什么情况下存在默认构造函数
说明
如果一个Java类没有显式包含构造函数的声明,那么隐含着有一个默认构造函数。
示例
定义一个类B,没有显式声明构造函数,所以存在一个默认构造函数:
package com.thb;
public class B {
public void method() {}
}
定义一个类C,显式声明了一个带参数的构造函数,所以就不存在默认构造函数:
package com.thb;
public class C {
private String msg;
public C(String msg) {
this.msg = msg;
}
public void method() {}
}
定义一个类Test1 ,调用类B和类C:
package com.thb;
public class Test1 {
public static void main(String[] args) {
// 类B没有声明构造函数,所以会隐含着有一个默认构造函数
B b = new B();
b.method();
// 如果去掉下面代码前面的注释就会编译出错,因为类C中已经明确声明了一个带参数的构造
// 函数,就不会有默认构造函数了
// C c = new C();
C c = new C("hello"); // 调用类C声明的构造函数
c.method();
}
默认构造函数的形式
一个顶层类、成员类、局部类的默认构造函数形式如下:
默认构造函数的访问修饰符
说明
默认构造函数的访问修饰符和类的访问修饰符相同;如果类没有显式声明访问修饰符,那么默认构造函数是包的访问修饰符。
示例—类用public修饰
定一个类B,用public修饰,没有声明构造函数,所以存在一个默认构造函数:
package com.thb;
public class B {
public void method() {}
}
打开类B编译后的class文件,可以发现,因为类B的访问控制修饰符是public,所以默认构造函数的访问控制修饰符也是public:
// Compiled from B.java (version 18 : 62.0, super bit)
public class com.thb.B {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
public B();
0 aload_0 [this]
1 invokespecial java.lang.Object() [8]
4 return
Line numbers:
[pc: 0, line: 3]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: com.thb.B
// Method descriptor #6 ()V
// Stack: 0, Locals: 1
public void method();
0 return
Line numbers:
[pc: 0, line: 5]
Local variable table:
[pc: 0, pc: 1] local: this index: 0 type: com.thb.B
}
示例—类没有显式声明访问控制修饰符
定义类D,没有显式声明访问控制修饰符,即表示是包访问控制:
package com.thb;
class D {
}
打开类D编译后的class文件,可以发现,默认构造函数也没有注明访问控制修饰符,即是包访问控制:
// Compiled from D.java (version 18 : 62.0, super bit)
class com.thb.D {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
D();
0 aload_0 [this]
1 invokespecial java.lang.Object() [8]
4 return
Line numbers:
[pc: 0, line: 3]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: com.thb.D
}
默认构造函数没有形式参数(非private的内部成员类除外)
说明
默认构造函数没有形式参数,非private的内部成员类除外。
非private的内部成员类的默认构造函数有一个形式参数,这个形式参数类型是包裹内部成员类的外部类。
示例:非private的内部成员类的默认构造函数
定义一个类E,在其内部定义一个非private的成员类AnotherInE :
package com.thb;
public class E {
class AnotherInE {
}
}
打开类E 编译后的class文件,可以发现它有一个没有形式参数的默认构造函数:
// Compiled from E.java (version 18 : 62.0, super bit)
public class com.thb.E {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
public E();
0 aload_0 [this]
1 invokespecial java.lang.Object() [8]
4 return
Line numbers:
[pc: 0, line: 3]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: com.thb.E
Inner classes:
[inner class info: #17 com/thb/E$AnotherInE, outer class info: #1 com/thb/E
inner name: #19 AnotherInE, accessflags: 0 default]
Nest Members:
#17 com/thb/E$AnotherInE
}
打开内部类AnotherInE 编译后的class文件,可以发现内部成员类的默认构造函数有一个形式参数,类型是包裹它的类E:
// Compiled from E.java (version 18 : 62.0, super bit)
class com.thb.E$AnotherInE {
// Field descriptor #6 Lcom/thb/E;
final synthetic com.thb.E this$0;
// Method descriptor #8 (Lcom/thb/E;)V
// Stack: 2, Locals: 2
E$AnotherInE(com.thb.E arg0);
0 aload_0 [this]
1 aload_1 [arg0]
2 putfield com.thb.E$AnotherInE.this$0 : com.thb.E [10]
5 aload_0 [this]
6 invokespecial java.lang.Object() [12]
9 return
Line numbers:
[pc: 0, line: 5]
Local variable table:
[pc: 0, pc: 10] local: this index: 0 type: com.thb.E.AnotherInE
Inner classes:
[inner class info: #1 com/thb/E$AnotherInE, outer class info: #22 com/thb/E
inner name: #24 AnotherInE, accessflags: 0 default]
Nest Host: #22 com/thb/E
}
默认构造函数没有throws 子句
默认构造函数体的内容
说明
如果声明的是基本类Object,那么默认构造函数体是空的。如果声明的是其它的类,在默认构造函数体内调用父类的没有形式参数的构造函数。
示例----在子类的默认构造函数体内调用父类的没有形式参数的构造函数
定义类B:
package com.thb;
public class B {
public void method() {}
}
定义B的子类BB:
package com.thb;
public class BB extends B {
}
打开类BB编译后的class文件,可以发现它的默认构造函数体内调用父类B的没有形式参数的构造函数:
// Compiled from BB.java (version 18 : 62.0, super bit)
public class com.thb.BB extends com.thb.B {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
public BB();
0 aload_0 [this]
1 invokespecial com.thb.B() [8]
4 return
Line numbers:
[pc: 0, line: 3]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: com.thb.BB
}
编译出错示例—子类没有显式定义造函数,但父类没有这样一个构造函数:无形式参数并且无throws 子句
定义一个类B,显式定义了一个带形式参数的构造函数,但没有定义无形式参数且没有throws 子句的构造函数:
package com.thb;
public class B {
private String name;
public B(String name) {
this.name = name;
}
public void method() {}
}
定义类B的子类BB,BB中没有显式定义构造函数,编译出错: