Вызов конструктора подкласса из абстрактного класса в Java - PullRequest
5 голосов
/ 21 мая 2009
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, и сохранялся в свойстве peer. Аналогично для Child2, с одноранговым узлом типа Child2.

Проблема заключается в присвоении свойства peer в родительском классе. Я не могу создать новый класс Child, вызвав new Child1(), потому что тогда он не будет работать для Child2. Как я могу это сделать? Могу ли я использовать ключевое слово, которое будет относиться к дочернему классу? Что-то вроде new self()?

Ответы [ 9 ]

8 голосов
/ 21 мая 2009

Я не уверен, возможно ли это сделать без циклов. Я убежден, что было бы намного понятнее написать это, используя фабричные методы вместо конструкторов.

2 голосов
/ 21 мая 2009
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 { }

Кажется, что код может быть более простым.

1 голос
/ 21 мая 2009

Начну с того, что считаю, что это, вероятно, действительно плохой дизайн. И имена классов тоже плохие, но я буду придерживаться их.

Однако, один из способов справиться с этим:

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);
    }   
}
0 голосов
/ 01 июля 2016

Ответив за ответ Леонид Кусков

Ваш пример 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) {
    }
}
0 голосов
/ 27 мая 2012
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 { }
0 голосов
/ 21 мая 2009

Я бы предложил заменить все это на шаблон фабрики, где у вас есть полный контроль над тем, что добавляется к пиру, и вам не нужно делать это в конструкторе.

0 голосов
/ 21 мая 2009

Обратите внимание, что без метода доступа в родительском классе вы не можете получить равноправный объект (вы не можете создать экземпляр Parent), поэтому этот дизайн имеет смысл только в качестве доказательства концепции.

0 голосов
/ 21 мая 2009

Примерно так:

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());
    }
}

Этот работает с конструктором по умолчанию, есть немного хитрости, если вы хотите создать новый узел с конструктором не по умолчанию. См. Javadoc для класса.

Редактировать: исправлена ​​бесконечная рекурсия:)

0 голосов
/ 21 мая 2009
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())
    }
}

Вот самый простой способ, который я могу придумать. Вы, вероятно, могли бы сделать это в родительском классе, используя некоторый API-интерфейс отражения java (поэтому спросите ссылку «this», что это за класс, и создайте новый класс этого типа. Однако он может не работать в зависимости от того, как работают конструкторы java. В C ++ указатель 'this' в конструкторе того же типа, что и класс конструкторов)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...