【问题标题】:Call subclass constructor from abstract class in Java从Java中的抽象类调用子类构造函数
【发布时间】:2009-05-21 07:58:37
【问题描述】:
public abstract class Parent {

    private Parent peer;

    public Parent() {
        peer = new ??????("to call overloaded constructor");
    }

    public Parent(String someString) {
    }

}

public class Child1 extends parent {

}

public class Child2 extends parent {

}

当我构造 Child1 的实例时,我希望自动构造一个也是 Child1 类型的“对等体”,并将其存储在对等属性中。对于 Child2 也是如此,具有 Child2 类型的对等体。

问题在于,在父类中对等属性的赋值。我不能通过调用new Child1() 来构造一个新的 Child 类,因为这样它就不适用于 Child2。我怎样才能做到这一点?有没有我可以使用的关键字来引用子类? new self() 之类的东西?

【问题讨论】:

  • 对我来说似乎是一个奇怪的模式。使用“ParentFactory”实例化这些对象会更好吗?
  • 这是一个很奇怪的设计。我想对等点的对等点将是原始对象?
  • peer 会变成什么样子?我的意思是它有什么用处,或者对此有什么实际的启发。

标签: java


【解决方案1】:

我不确定是否可以在不陷入循环的情况下执行此操作。我相信使用工厂方法而不是构造函数来编写它会更清晰。

【讨论】:

  • 是的,绝对不应该直接使用构造函数。
  • ...但是工厂方法难道不是一种解决方法模式,在语言中是不可能的,真的吗?
【解决方案2】:
public abstract class Parent implements Clonable{

  private Object peer;

  // Example 1 
  public Parent() {
    try {
      peer = this.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
  }

  // Example 2
  public Parent(String name) {
    try {
      peer = this.getClass().getConstructor(String.class).newInstance(name);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  } 

  public <T extends Parent> T getPeer() {
    return (T)peer;
  }
}

public class Child01 extends Parent { }

public class Child02 extends Parent { }

看来代码可能更简单。

【讨论】:

  • 但他希望“peer”成为一个新对象,而不是“this”
  • ...一个新对象,其对等对象依次为“this”。
【解决方案3】:

我首先要说我认为这可能是一个非常糟糕的设计。而且类名也不好,但我会坚持下去。

但是,一种处理方式:

public abstract class Parent {
    interface PeerFactory {
        Parent create(Parent peer);
    }
    private final Parent peer;

    protected Parent(Parent peer) {
        super();
        this.peer = peer;
    }
    protected Parent(PeerFactory peerFactory) {
        super();
        this.peer = peerFactory.create(this);
    }
}

public class Child1 extends parent {
    private static final PeerFactory peerFactory = new PeerFactory {
        public Parent create(Parent peer) {
            return new Child1(peer);
         }
    };
    public Child1() {
        super(peerFactory);
    } 
    private Child1(Peer peer) {
        super(peer);
    }   
}

【讨论】:

    【解决方案4】:

    类似这样的:

    public class Peer {
        public static abstract class Parent {
                private Parent peer;
    
                protected Parent(boolean needPeer) {
                        if (needPeer) {
                                try {
                                        peer = getClass().newInstance();
                                }
                                catch (Throwable e) {
                                        System.err.println(e);
                                }
                        }
                }
    
                public String getPeerClass() {
                        return peer.getClass().toString();
                }
        }
    
        public static class Child1 extends Parent {
                public Child1() {
                        this(false);
                }
                public Child1(boolean needPeer) {
                        super(needPeer);
                }
        }
    
        public static class Child2 extends Parent {
                public Child2() {
                        this(false);
                }
                public Child2(boolean needPeer) {
                        super(needPeer);
                }
        }
    
        public static void main(String[] args) {
                Parent p1 = new Child1(true);
                Parent p2 = new Child2(true);
    
                System.out.println(p1.getPeerClass());
                System.out.println(p2.getPeerClass());
        }
    }
    

    这适用于默认构造函数,如果您想使用非默认构造函数构造一个新的对等点,则涉及更多技巧。请参阅 Class 的 javadoc。

    编辑:修复了无限递归:)

    【讨论】:

    • 酷。这似乎是一个不错的解决方案。我想知道 Thilo 提出的问题是否适用于此,或者这就是您使用内部类的原因?
    • 这不是也在构造函数中创建无限递归吗? Class.newInstance() 仍然调用构造函数。
    • 而不是“boolean needPeer = false”(没有peer),我想peer的peer应该是原始对象...... OP应该重新考虑他的设计。
    • 我只使用了内部类,这样我就可以只用一个 java 文件对其进行测试:) 请参阅我对他对另一个问题的回答的评论。 (Parent 的 ctor 中的 getClass() 调用并不真正“好”,但这就是 java 的工作原理耸耸肩。)
    【解决方案5】:

    请注意,如果没有父类中的访问器,您将无法获取对等对象(您无法实例化 Parent),因此这种设计仅作为概念证明才有意义。

    【讨论】:

      【解决方案6】:

      我建议用工厂模式替换整个事情,在这种模式下,您可以完全控制添加对等点的内容,而不必在构造函数中进行。

      【讨论】:

        【解决方案7】:

        回复Leonid Kuskov的回复

        您的示例 2 将始终抛出 StackOverflowException。我稍微摆弄了一下代码,下面是正确的实现。虽然感谢你在那个方向给我指点。

        public class AbstractClassDemo {
        
            public static void main(String[] args) {
                Child1 c1 = new Child1();
                System.out.println(c1.getPeer().getClass().getName());
            }
        
        }
        
        abstract class Parent {
            private Object peer;
        
            public Parent() {
        
            }
        
            public Parent(String s) {
                try {
                    setPeer(this.getClass().getConstructor(String.class)
                            .newInstance(""));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        
            public Object getPeer() {
                return peer;
            }
        
            public void setPeer(Object peer) {
                this.peer = peer;
            }
        }
        
        class Child1 extends Parent implements Cloneable {
            public Child1() {
                super("Child1");
            }
        
            public Child1(String child1) {
            }
        }
        
        class Child2 extends Parent implements Cloneable {
            public Child2() {
                super("Child2");
            }
        
            public Child2(String child2) {
            }
        }
        

        【讨论】:

          【解决方案8】:
          public abstract class Parent implements Clonable {
            private Object peer;
          
            // Example 1 
            public Parent() {
              try {
                peer = this.clone();
              } catch (CloneNotSupportedException e) {
                e.printStackTrace();
              }
            }
          
            // Example 2
            public Parent(String name) {
              try {
                peer = this.getClass().getConstructor(String.class).newInstance(name);
              } catch (Exception e) {
                e.printStackTrace();
              }
            }
          
          } 
          
          public <T extends Parent> T getPeer() {
           return (T)peer;
          }
          
          public class Child01 extends Parent { }
          
          public class Child02 extends Parent { }
          

          【讨论】:

            【解决方案9】:
            public abstract class Parent {
            
                private Parent peer;
            
                public Parent(Parent peer) {
                    this.peer = peer;
                }
            
                public Parent(String someString) {
                }
            
            }
            
            public class Child1 extends parent {
                public Child1() {
                    super(new Child1())
                }
            }
            
            public class Child2 extends parent {
                public Child2() {
                    super(new Child2())
                }
            }
            

            这是我能想到的最简单的方法。不过,您可能可以使用一些 java 反射 API 在父类中执行此操作(所以询问“this”引用它是什么类并构造该类型的新类。它可能无法工作,具体取决于 java 构造函数的工作方式。在 C++ 中,构造函数中的“this”指针与构造函数类的类型相同)

            【讨论】:

            • 是的。这是我希望避免的,但我可能不得不这样做。干杯
            • Child1() 和 Child2() 构造函数不是无限调用自己吗?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-03-20
            • 2014-08-09
            • 2013-10-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多