Reputation: 11851
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 {
}
When I construct an instance of Child1, I want a "peer" to automatically be constructed which is also of type Child1, and be stored in the peer property. Likewise for Child2, with a peer of type Child2.
The problem is, on the assignment of the peer property in the parent class. I can't construct a new Child class by calling new Child1()
because then it wouldn't work for Child2. How can I do this? Is there a keyword that I can use that would refer to the child class? Something like new self()
?
Upvotes: 6
Views: 11310
Reputation: 331
Replying for answer of Leonid Kuskov
Your example 2 will always throw a StackOverflowException. I fiddled around with the code a bit an below is the correct implementation for that. Though thanks to you to give me pointers in that direction.
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) {
}
}
Upvotes: 0
Reputation: 619
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 { }
Upvotes: -1
Reputation: 46
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 { }
It seems that the code may be more simple.
Upvotes: 2
Reputation: 26856
I would suggest replacing this whole thing with a Factory pattern, where you have complete control over what gets a peer added and you don't have to do it in the constructor.
Upvotes: 0
Reputation: 147164
I'll start by saying that I think it's probably a really bad design. And the class names are also bad, but I'll stick with them.
However, one way of dealing with it:
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);
}
}
Upvotes: 1
Reputation: 526
Note that without an accessor in the parent class you cannot get the peer object (you cannot instantiate Parent), so this design only makes sense as concept proof.
Upvotes: 0
Reputation: 6331
Something like this:
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());
}
}
This one works with default constructor, there's a bit more trickery involved if you want to construct a new peer with a non-default constructor. See The javadoc for Class.
Edit: fixed the infinite recursion :)
Upvotes: 0
Reputation: 7297
I'm not sure if it is possible to do this without running into cycles. I am convinced that it would be a lot clearer to write this using factory methods instead of constructors.
Upvotes: 8
Reputation: 25677
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())
}
}
Here's the simplest way I can think of. You could probably do it in the parent class using some of the java reflection API though (so ask the 'this' reference what class it is and construct a new class of that type. It may not work depending on how java constructors work though. In C++, the 'this' pointer in a constructor is of the same type as the constructors class)
Upvotes: -3