有没有办法在Java中调用超类构造函数?
如果我有课:有没有办法在Java中调用超类构造函数?,java,oop,constructor,super,Java,Oop,Constructor,Super,如果我有课: class A { public A() { } } 还有一个 class B extends A { public B() { } } 有没有办法让B.B()不调用A.A()?这将违反is-a原则。因此,如果你真的需要它,那么多态性就不是你所追求的。每个超类都需要构造,除了调用构造函数之外没有其他方法。我认为唯一的方法就是搞乱字节码。 我不确定类加载器或JVM是否检查是否正在调用super(),但是,正如Bozho所写的,这样做时,您可能会以不一致的对象结束。在J
class A {
public A() { }
}
还有一个
class B extends A {
public B() { }
}
有没有办法让
B.B()
不调用A.A()?这将违反is-a原则。因此,如果你真的需要它,那么多态性就不是你所追求的。每个超类都需要构造,除了调用构造函数之外没有其他方法。我认为唯一的方法就是搞乱字节码。
我不确定类加载器或JVM是否检查是否正在调用super()
,但是,正如Bozho所写的,这样做时,您可能会以不一致的对象结束。在Java中绝对没有办法做到这一点;这将打破语言规范
在返回对新创建对象的引用作为结果之前,将使用以下过程处理指示的构造函数以初始化新对象:
为构造函数[…]指定参数
如果此构造函数以同一类中另一个构造函数的显式构造函数调用开始(使用this
),则[…]
此构造函数不会以同一类中另一个构造函数的显式构造函数调用开始(使用This
)。如果此构造函数用于非对象
的类,则此构造函数将以超类构造函数的显式或隐式调用开始(使用super
)
为此类[…]执行实例初始值设定项和实例变量初始值设定项
执行此构造函数体的其余部分[…]
如果不想调用超类构造函数,对象模型还有其他问题。最接近所需行为的方法是将构造函数中通常执行的初始化委托给模板方法,然后在子类实现中重写该方法。例如:
public class A {
protected Writer writer;
public A() {
init();
}
protected void init() {
writer = new FileWriter(new File("foo.txt"));
}
}
public class B extends A {
protected void init() {
writer = new PaperbackWriter();
}
}
然而,正如其他人所指出的,这通常表明您的设计存在问题,在这种情况下,我通常更喜欢合成方法;例如,在上面的代码中,您可以定义构造函数以接受编写器实现作为参数。否-您不能这样做,为什么还要这样做?这会弄乱你的对象模型
无论如何,我相信如果你仍然想这样做,那么你将不得不操纵生成的字节码。。。。有两个可用的库,可以轻松地插入字节码
强烈建议不要这样做…java中的每个对象都是object的一个子类(带有大写字母“O”的对象)。创建子类的对象时,会调用超类构造函数。即使您的类没有继承任何其他类,也会隐式地继承对象,因此必须调用对象构造函数。因此,super()被调用用于此目的 假设你的意思是
class B extends A {
public B() { }
}
那你当然可以
class B extends A {
public B() {
this(abort());
}
private B(Void dummy) {
/* super(); */
}
private static Void abort() {
throw null;
}
}
不是很有用。类A
的接口[not Java keyword]表示您需要运行其构造函数来构造它,这是合理的。例外情况是,可序列化类是在不调用可序列化类的构造函数的情况下构造的
正如另一张海报所指出的,B并没有扩展A,所以它无论如何也不会调用A的构造函数
在Java中无法做到这一点
您可能可以按如下方式等效地完成您想要做的事情:
a) 在层次结构的每个类中,包括一个具有唯一签名的构造函数,该构造函数使用其参数调用超类的构造函数。例如,声明一个类“Noop”和一个将其作为参数的构造函数:
public class NoOp {
}
public class class1 {
class1() {
System.out.println("class1() called");
}
class1(String x, String y) {
System.out.println("class1(String, String) called");
}
class1(NoOp x) {
System.out.println("class1(NoOp) called");
}
}
public class class2 extends class1 {
class2() {
System.out.println("class2() called");
}
class2(String x, String y) {
System.out.println("class2(String, String) called");
}
class2(NoOp x) {
super(x);
System.out.println("class2(NoOp) called");
}
}
public class class3 extends class2 {
class3() {
System.out.println("class3() called");
}
class3(String x, String y) {
super(new NoOp());
System.out.println("class3(String, String) called");
}
class3(NoOp x) {
super(x);
System.out.println("class3(NoOp) called");
}
public static void main(String args[]) {
class3 x = new class3("hello", "world");
}
}
如果运行此命令,您将获得输出
class1(NoOp) called
class2(NoOp) called
class3(String, String) called
因此,实际上您已经创建了一个class3构造函数,它只调用不做任何事情的构造函数。我有一个类似的要求,我需要我的子类不经过超类的构造函数,我想要超类的其余好处。既然超级班也是我的,下面是我做的
class SuperClass {
protected SuperClass() {
init();
}
// Added for classes (like ChildClassNew) who do not want the init to be invoked.
protected SuperClass(boolean doInit) {
if (doInit)
init();
}
//
}
class ChildClass1 extends SuperClass {
ChildClass1() {
// This calls default constructor of super class even without calling super() explicitly.
// ...
}
// ....
}
class ChildClass2 extends SuperClass {
ChildClass2() {
// This calls default constructor of super class even without calling super() explicitly.
// ...
}
// ....
}
class ChildClassNew extends SuperClass {
ChildClassNew() {
/*
* This is where I didn't want the super class' constructor to
* be invoked, because I didn't want the SuperClass' init() to be invoked.
* So I added overloaded the SuperClass' constructor where it diesn;t call init().
* And call the overloaded SuperClass' constructor from this new ChildClassNew.
*/
super(false);
//
// ...
}
// ....
}
Java反序列化不调用构造函数,但它似乎基于一些内部JVM技巧
但是,有一个框架允许您以可移植的方式进行此操作:objeness()
我最近在Spring中看到了这一点,当使用CGLIB代理时,Spring创建了两个类实例,但构造函数只被调用一次:
此行为在Spring 4中添加:
基于CGLIB的代理类不再需要默认构造函数。
通过重新打包的Objensis库提供支持
作为Spring框架的一部分进行内联和分发。用这个
策略中,根本没有为代理实例调用构造函数
再也没有了
您可以调用自己选择的超类构造函数。这可以通过显式调用超级类构造函数来实现:
super(para_1, para_2,........);
你的意思是B类扩展了A{
?顺便说一句:这些不是好的类名-它们看起来像泛型参数。无论如何,你不是从B调用A的构造函数,B不是从A继承的。我只是试图从不同的包扩展其他人的类。我只是重写了其中的一部分。请看:谢谢!如果你发现自己需要要做到这一点,那么你不需要继承,你需要组合。”有效Java第二版,第17项:继承的设计和文档,否则禁止:构造函数不能直接或间接调用可重写的方法我不是说这是一件好事——我只是说这就是你要做的。毫无疑问,但在我有时间解决之前,我需要解决它。在班级只为学生服务的情况下
class BaseA {
BaseA(){
System.out.println("This is BaseA");
}
BaseA(int a){
System.out.println("This is BaseA a");
}
}
class A extends BaseA {
A(){
super(5);
System.out.println("This is A");
}
public static void main(String[] args) {
A obj=new A();
}
}
Output will be:
This is BaseA a
This is A