很多时候我都有一个异常说“缺少默认构造函数的实现”。很多时候,参数化构造函数的定义本身就可以完成所有工作。我想知道在什么条件下会发生这种情况。
8 回答
编译器永远不会强制存在默认构造函数。您可以根据需要使用任何类型的构造函数。
对于某些库或框架,类可能需要具有默认构造函数,但这不是由编译器强制执行的。
您可能会看到的问题是,如果您有一个带有自定义构造函数的类,并且您的构造函数主体中没有隐式super()
调用。在这种情况下,编译器将引入对超类默认构造函数的调用。如果超类没有默认构造函数,那么您的类将无法编译。
public class MyClass extends ClassWithNoDefaultConstructor
public MyClass() {
super(); //this call will be added by the compiler if you don't have any super call here
// if the super class has no default constructor the above line will not compile
// and removing it won't help either because the compiler will add that call
}
}
如果类中不存在构造函数,则在编译时添加一个默认构造函数。
如果类中存在任何一个参数化构造函数,则不会在编译时添加默认构造函数。
因此,如果您的程序有任何包含参数的构造函数并且没有指定默认构造函数,那么您将无法使用默认构造函数创建该类的对象。
例如:
class A{
A(int a){}
}
A a = new A() -----> Error.
-------------------------------------------------------
class A{
A(int a){}
A(){}
}
A a = new A() -----> It will work.
-----------------------------------------------------------
class A{
}
A a = new A() -----> It will work.
正如Joachim Sauer所说,当您使用 spring 之类的框架时,除了参数化构造函数之外,提供默认构造函数很重要/有时需要。因为如果你想通过依赖注入在另一个类中注入你的类对象,那么这个类应该有默认的构造函数。
否则你的依赖注入将失败。
这只是我遇到默认构造函数重要性的一种情况
目前尚不清楚您是在谈论运行时异常还是编译错误。
只有当您的代码(或您的代码调用的某些库代码)尝试使用反射来创建某个类的实例,并且不小心尝试使用不存在的构造函数时,才会发生运行时异常。(而且我怀疑异常消息会使用术语“默认构造函数”......)
发生编译错误是因为您显式或隐式尝试调用不存在的“无参数”构造函数。有三种情况'
// case #1
new Foo();
// case #2
public Bar extends Foo {
public Bar() {
super();
}
}
// case #3
public Bar extends Foo {
public Bar() {
// no explicit 'this' or 'super' call.
}
}
前两个示例非常明显地调用了无参数构造函数。
最后一个示例调用无参数构造函数,因为如果您在构造函数的开头没有显式super
或“调用”,JLS 表示将发生调用……除了构造函数 for 之外的所有情况。this
super()
Object
最后,你回答标题中的问题:
什么时候必须在 Java 中使用默认构造函数和参数化构造函数?
严格来说,拥有默认构造函数从来都不是强制性的。必须有一个无参数构造函数(显式声明或默认)......只有当它被显式或隐式调用时。
(可能有一些库/框架假设您的类具有无参数构造函数,但这超出了我们可以回答的范围。此外,这样的假设将使得可以反射地创建实例......我已经涵盖了。)
通常,当类的实例通过反射创建时(例如在反序列化时),可能会发生这种情况。如果你的类是可序列化的或者它的实例可以通过反射机制创建,你应该定义默认构造函数。
案例1:
如果您不编写构造函数,则将添加默认构造函数(由编译器),您可以使用它创建对象。但是如果你写了一个参数化的构造函数,并且想要创建像这样的对象ClassName ObjName = new ClassName();
那么您必须手动添加默认构造函数。
案例2(继承):如果您的子类构造函数没有
显式调用父类构造函数(在第一行本身),那么编译器将为您完成。class ChildClass extends ParentClass{ ChildClass(){ //super() added by compiler. } }
现在同样的事情,
如果父类中没有构造函数,则将调用精细的默认构造函数(由编译器添加)。
但是如果父类有一个参数化的构造函数,那么就没有默认构造函数,所以你会得到你的错误。
当你有一个参数化的构造函数和
想要创建像案例 1 一样的对象。
继承这个类并且不进行显式调用
super(parameter,...);
在 ChildClass 构造函数的第一行。
编译器将在编译代码时添加默认构造函数,但是当您在代码中声明参数化构造函数时,将省略默认构造函数。
当默认构造函数被参数化构造函数重载时,使用默认构造函数而不是参数化构造函数创建对象时,代码中需要有一个默认构造函数。
当您使用需要创建 Spring bean 实例且 bean 类只有参数化构造函数的框架(例如:Spring 框架)时,需要默认构造函数。
@Component
public class Bank {
private String bankName;
public Bank(String bankName){
this.bankName = bankName;
}
@Override
public String toString() {
return this.bankName;
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext context = new
AnnotationConfigApplicationContext(SpringConfig.class);
Bank bank = context.getBean(Bank.class);
System.out.println(bank);
}
}
将抛出一个错误,要求实现默认构造函数