知识点
什么是构造器
构造器通常也叫构造方法, 构造函数, 构造器在每个项目中几乎无处不在. 当你 new 一个对象时, 就会调用构造器. 构造器格式如下:
[修饰符, 比如 public] 类名 (参数列表, 可以没有参数){
- // 这里不能有 return
- }
默认构造器
如果没有定义构造器, 则会默认一个无参构造器, 这就是为什么你定义了一个对象, 比如 People, 没有定义任何构造器却可以 new 这个对象, 比如 new People() . 如果自定义了构造器, 则会覆盖默认构造器.
如何禁止对象被外部创建
一些特殊需求, 不希望定义的对象被外部创建 (典型的就是单例了), 那直接将构造器的修饰符改为 private 即可. 这样就不能在外部通过 new 来创建这个对象了.
构造器重载
与普通方法一样, 构造器也支持重载. 一个对象中是可以支持同时定义多个构造器, 通过不同的参数列表来实现重载. 经常看到代码中 new 一个对象时, 有时传入参数, 有时又可以不用传. 比如: new People() 跟 new People("张三"), 这里就是重载了.
构造器的继承
子类构造器会默认调用父类无参构造器, 如果父类没有无参构造器, 则必须在子类构造器的第一行通过 super 关键字指定调用父类的哪个构造器, 具体看下文例子. final 类是不允许被继承的, 编译器会报错. 很好理解, 由于 final 修饰符指的是不允许被修改, 而继承中, 子类是可以修改父类的, 这里就产生冲突了, 所以 final 类是不允许被继承的.
构造器, 静态代码块, 构造代码块的执行顺序, 详见下文实例
无继承的情况下的执行顺序
静态代码块: 只在程序启动后执行一次, 优先级最高
构造代码块: 任何一个构造器被调用的时候, 都会先执行构造代码块, 优先级低于静态代码块
构造器: 优先级低于构造代码块
总结一下优先级: 静态代码块 > 构造代码块 > 构造器
有继承的情况下的执行顺序:
父类静态代码块: 只在程序启动后执行一次, 优先级最高
子类静态代码块: 只在程序启动后执行一次, 优先级低于父类静态代码块
父类构造代码块: 父类任何一个构造器被调用的时候, 都会执行一次, 优先级低于子类静态代码块
父类构造器: 优先级低于父类构造代码
子类构造代码块: 子类任何一个构造器被调用的时候, 都会执行一次, 优先级低于父类构造器
子类构造器: 优先级低于子类构造代码块
总结一下优先级: 父类静态代码块 > 子类静态代码块 > 父类构造代码块 > 父类构造器 > 子类构造代码块 > 子类构造器
实例
1. 默认构造器
新建一个类, 不提供任何构造器, 编译器会默认提供一个无参构造器, 这就是为什么没定义任何构造器, 却可以 new 某个对象 ()
- public class People {
- }
以上这个 People 类, 可以直接通过 new People() 来实例化.
2. 禁止对象被外部创建
如果不希望 People 在外部通过 new People() 来实例化, 只需要将构造器定义为 private
- public class People {
- private People(){
- }
- }
3. 构造器重载
重载可以简单理解为: 同个方法名, 不同的参数列表. 如果希望 People 能在外部通过 new People() 或 new People("字符串") 来实例化, 则通过以下代码即可
- public class People {
- // 通过 new People() 调用
- public People(){
- }
- // 通过 new People("字符串") 调用
- public People(String str){
- }
- }
4. 构造器的继承
定义父类构造器, 由于该构造器自定义了一个带参构造器, 覆盖了默认的无参构造器, 所以不能直接 new SuperClass() 调用了, 除非再定义一个无参构造器
- /**
- * 父类构造器
- */
- public class SuperClass {
- /**
- * 自定义带参构造器
- */
- public SuperClass(String str){
- System.out.println("父类的带参构造方法, 参数为:" + str);
- }
- }
定义子类构造器, 继承 SuperClass, 由于 SuperClass 没有无参构造器, 所以必须在子类构造器中通过 super("字符串") 来调用, 否则编译器会报错
- /**
- * 子类构造器
- */
- public class SubClass extends SuperClass {
- /**
- * 无参构造器
- */
- public SubClass(){
- // 由于 SuperClass 没有无参构造器, 所以必须在子类构造器中通过 super("字符串") 来调用, 否则编译器会报错.
- // 如果没定义该句, 则编译器会默认调用 super()
- super("");
- }
- /**
- * 带参构造器
- */
- public SubClass(String subStr){
- // 由于 SuperClass 没有无参构造器, 所以必须在子类构造器中通过 super("字符串") 来调用, 否则编译器会报错.
- // 如果没定义该句, 则编译器会默认调用 super()
- super(subStr);
- }
- }
5. 构造器, 静态代码块, 构造代码块的执行顺序
5.1 无继承的情况
- public class People {
- static {
- System.out.println("静态代码块, 程序启动后执行, 只会执行一次");
- }
- /**
- * 默认的无参构造器
- */
- public People(){
- System.out.println("默认构造器");
- }
- /**
- * 构造器重载, 自定义一个带参构造器
- * @param str
- */
- public People(String str){
- System.out.println("带参构造器, 参数:" + str);
- }
- {
- System.out.println("构造代码块, 每次调用构造方法都会执行一次");
- }
- }
实例化 People
- public static void main(String[] args){
- System.out.println("--------------people----------------");
- People people = new People();
- System.out.println("--------------people1----------------");
- People people1 = new People("张三");
- }
执行以上代码, 输出:
--------------people----------------
静态代码块, 程序启动后执行, 只会执行一次
构造代码块, 每次调用构造方法都会执行一次
默认构造器
--------------people1----------------
构造代码块, 每次调用构造方法都会执行一次
带参构造器, 参数: 张三
5.2 有继承的情况
定义父类 SuperClass
- /**
- * 父类构造器
- */
- public class SuperClass {
- {
- System.out.println("父类构造代码块, 每次调用构造方法都会执行的");
- }
- /**
- * 父类无参构造方法
- */
- public SuperClass(){
- System.out.println("父类的默认构造方法");
- }
- /**
- * 重载, 自定义父类带参构造方法
- * @param str
- */
- public SuperClass(String str){
- System.out.println("父类的带参构造方法, 参数为:" + str);
- }
- static {
- System.out.println("父类的静态代码块, 程序启动后执行, 只会执行一次");
- }
- }
定义子类 SubClass, 继承 SuperClass
- /**
- * 子类构造器, 继承 SuperClass
- */
- public class SubClass extends SuperClass {
- static {
- System.out.println("子类的静态代码块, 程序启动后执行, 只会执行一次, 先执行父类的, 再执行子类的");
- }
- {
- System.out.println("子类构造代码块, 每次调用构造方法都会执行的");
- }
- /**
- * 无参构造器
- */
- public SubClass(){
- // 这里没有指定调用父类哪个构造器, 会默认调用 super(), 调用父类的无参构造器 public SuperClass()
- }
- /**
- * 重载构造器, 多传两个参数
- * @param str
- * @param str1
- */
- public SubClass(String str,String str1){
- // 必须写在构造器第一行, 调用父类构造器 public SuperClass(String str)
- super(str);
- System.out.println("子类带参构造器:" + str1);
- }
- }
实例化 SubClass
- public static void main(String[] args){
- System.out.println("--------------subClass1----------------");
- SubClass subClass1 = new SubClass();
- System.out.println("--------------subClass2----------------");
- SubClass subClass2 = new SubClass("子类第一个参数","子类第二个参数");
- }
执行以上代码, 输出:
--------------subClass1----------------
父类的静态代码块, 程序启动后执行, 只会执行一次
子类的静态代码块, 程序启动后执行, 只会执行一次, 先执行父类的, 再执行子类的
父类构造代码块, 每次调用构造方法都会执行的
父类的默认构造方法
子类构造代码块, 每次调用构造方法都会执行的
--------------subClass2----------------
父类构造代码块, 每次调用构造方法都会执行的
父类的带参构造方法, 参数为: 子类第一个参数
子类构造代码块, 每次调用构造方法都会执行的
子类带参构造器: 子类第二个参数
源码获取
以上示例都可以通过我的 GitHub https://github.com/simonxie/javase-demo 获取完整的代码, 点击获取
来源: https://www.cnblogs.com/mingsay/p/12441490.html