The situation is I want to inherit an object to have a cleaner constructor interface:
class BaseClass {
public BaseClass(SomeObject object){
...
}
}
class SubClass extends BaseClass{
private SubObject subObject = new SubObject();
public SubClass(){
super(new SomeObject(subObject)); // doesn't compile
}
}
But to do that I need to do stuff before the constructor like in the example above but can't because Java doesn't allow that. Is there any way around this? I'm starting to feel that if your class is designed to be subclassed it should always implement default constructor and provide setters for the values it needs... Sometimes you can get away with this if you create a new object straight into the super constructor as an argument but if you need a reference to the object you created then you are hosed.
You need to change it so that you're not referring to an instance member in the superconstructor call. Unfortunately if you need to then "save" the SubObject, it becomes tricky. I think you'd have to do it with constructor chaining:
class SubClass extends BaseClass{
private SubObject subObject;
public SubClass() {
this(new SubObject());
}
private SubClass(SubObject subObject) {
super(new SomeObject(subObject));
this.subObject = subObject;
}
}
public SubClass(){
super(new SomeObject(new SubObject())); // this should compile
}
Now in your super class, do something like this:
private final SomeObject foo;
public BaseClass(SomeObject foo){
this.foo = foo;
}
public /* or protected */ SomeObject getFoo(){return this.foo;}
Not exactly an answer since you would have no SubClass, but you could use a factory.
public BaseClassFactory {
public static BaseClass newBaseClass() {
// init some object
// ...
return new BaseClass(someObject);
}
}
Related
I have an abstract class with several subclasses. In the abstract classe I have implemented a copy constructor. Now, I want to clone one of the subclasses using the copy constructor, how can I do this? Obviously I do not know in advance what subclass I have to clone.
Here is an example of what I want to do :
abstract class AbstractClass {
public AbstractClass(AbstractClass ac) {
this();
setX(ac.getX());
setY(ac.getY());
}
// Some setter and getter for X and Y variables
}
class SubclassA extends AbstractClass {
public SubclassA(SubclassA a) {
super(a);
}
}
class SubclassB extends AbstractClass {
public SubclassB(SubclassB b) {
super(b);
}
}
public class Main {
public static void main(String[] args) {
AbstractClass a = new SubclassA();
AbstractClass b = new SubclassB();
// Get a copy of "a" or "b" using the copy constructor of abstract class
AbstractClass newA = AbstractClass(a);
AbstractClass newB = AbstractClass(b);
}
}
There are only two ways I can see to create a copy of a given object without knowing at compile time which class to instantiate (as requested in the question):
Use Reflection to call the copy constructor of the desired class, assuming you know at runtime what the class is, and that said class has a suitable copy constructor.
Call some copy method of the base class which is overridden by subclasses.
The first solution is not good as it requires the use of Reflection. The second can be implemented with the clone()/Cloneable standard mechanism (despite its issues), or with some custom-defined "copy()" method. Your choice.
abstract class AbstractClass {
public AbstractClass(AbstractClass ac) {
this();
setX(ac.getX());
setY(ac.getY());
}
public abstract AbstractClass clone();
// Some setter and getter for X and Y variables
}
class SubclassA extends AbstractClass {
public SubclassA(SubclassA a) {
super(a);
}
#Override
public SubclassA clone() {
return new SubclassA(this);
}
}
class SubclassB extends AbstractClass {
public SubclassB(SubclassB b) {
super(b);
}
#Override
public SubclassB clone() {
return new SubclassB(this);
}
}
public class Main {
public static void main(String[] args) {
AbstractClass a = new SubclassA();
AbstractClass b = new SubclassB();
// Get a copy of "a" or "b" using the copy constructor of abstract class
AbstractClass newA = a.clone(); // is instance of SubclassA
AbstractClass newB = b.clone(); // is instance of SubclassB
}
}
The trick here is to use your own clone method (which has nothing to do with Cloneable what so ever). This method in turns calls the proper copy constructor.
This means you get all the advantages of a copy constructor, and you can be sure that no matter hwta subclass of AbstractClass you get, you always get a copy of the proper subclass without needing to call the constructor yourself.
I wanted to implement a method in a abstract class that is called by the inherited classes and uses their values.
For instance:
abstract class MyClass{
String value = "myClass";
void foo(){System.out.println(this.value);}
}
public class childClass{
String value="childClass";
void foo(){super.foo();}
}
public static void main(String[] args){
new childClass.foo();
}
This will output "myClass" but what I really want is to output "childClass". This is so I can implement a "general" method in a class that when extended by other classes it will use the values from those classes.
I could pass the values as function arguments but I wanted to know if it would be possible to implement the "architecture" I've described.
A super method called by the inherited class which uses the values from the caller not itself, this without passing the values by arguments.
You could do something like this:
abstract class MyClass {
protected String myValue() {
return "MyClass";
}
final void foo() {
System.out.println(myValue());
}
}
public class ChildClass extends MyClass {
#Override
protected String myValue() {
return "ChildClass";
}
}
and so on
This is a place where composition is better than inheritance
public class Doer{
private Doee doee;
public Doer(Doee doee){
this.doee = doee;
}
public void foo(){
System.out.println(doee.value);
}
}
public abstract class Doee{
public String value="myClass"
}
public ChildDoee extends Doee{
public String= "childClass"
}
...
//Excerpt from factory
new Doer(new ChildDoee);
I believe you are asking whether this is possible:
public class MyClass {
void foo() {
if (this instanceof childClass) // do stuff for childClass
else if (this intanceof anotherChildClass) // do stuff for that one
}
}
So the answer is "yes, it's doable", but very much advised against as it a) tries to reimplement polymorphism instead of using it and b) violates the separation between abstract and concrete classes.
You simply want value in MyClass to be different for an instance of childClass.
To do this, change the value in the childClass constructor:
public class childClass {
public childClass() {
value = "childClass";
}
}
Edited:
If you can't override/replace the constructor(s), add an instance block (which gets executed after the constructor, even an undeclared "default" constructor):
public class childClass {
{
value = "childClass";
}
}
Considering that simple java code which would not work:
public class Bar extends AbstractBar{
private final Foo foo = new Foo(bar);
public Bar(){
super(foo);
}
}
I need to create an object before the super() call because I need to push it in the base class.
I don't want to use an initialization block and I don't want to do something like:
super(new Foo(bar)) in my constructor..
How can I send data to a base class before the super call ?
If Foo has to be stored in a field, you can do this:
public class Bar extends AbstractBar{
private final Foo foo;
private Bar(Foo foo) {
super(foo);
this.foo = foo;
}
public Bar(){
this(new Foo(bar));
}
}
Otherwise super(new Foo(bar)) looks pretty legal for me, you can wrap new Foo(bar) into a static method if you want.
Also note that field initializers (as in your example) and initializer blocks won't help either, because they run after the superclass constructor. If field is declared as final your example won't compile, otherwise you'll get null in superclass constructor.
thats not possible in java. the only possible solution is the new call in the super constructor.
if the foo object can be shared between instances you may declar it as static
public class Bar extends AbstractBar{
private static final Foo foo = new Foo(bar);
public Bar(){
super(foo);
}
}
if the super class is under your control, you can refactor it and use the template method pattern to pull the object into the constructor instead of pusing it from the subclass. this applys the hollywod principle: don't call us, we will call you ;)
public abstract class AbstractBar{
private Object thing;
public AbstractBar(){
this.thing = this.createThatThing();
}
protected abstract Object createThatThing();
}
public class Bar extends AbstractBar {
// no constructor needed
protected Object createThatThing(){
return new Thing();
}
}
class AbstractBar{
public AbstractBar() {
}
public AbstractBar(Foo t) {
}
}
class Bar extends AbstractBar{
static Foo t=null;
public Bar() {
super(t=new Foo());
}
}
class Foo{...}
I have the following situation:
public abstract class A {
private Object superMember;
public A() {
superMember = initializeSuperMember();
// some additional checks and stuff based on the initialization of superMember (***)
}
protected abstract Object initializeSuperMember();
}
class B extends A {
private Object subMember;
public B(Object subMember) {
super();
subMember = subMember;
}
protected Object initializeSuperMember() {
// doesn't matter what method is called on subMember, just that there is an access on it
return subMember.get(); // => NPE
}
}
The problem is that I get a NPE on a new object B creation.
I know I can avoid this by calling an initializeSuperMember() after I assign the subMember content in the subclass constructor but it would mean I have to do this for each of the subclasses(marked * in the code).
And since I have to call super() as the first thing in the subclass constructor I can't initialize subMember before the call to super().
Anyone care to tell me if there's a better way to do this or if I am trying to do something alltogether wrong?
Two problems:
First, you should never call an overrideable member function from a constructor, for just the reason you discovered. See this thread for a nice discussion of the issue, including alternative approaches.
Second, in the constructor for B, you need:
this.subMember = subMember;
The constructor parameter name masks the field name, so you need this. to refer to the field.
Follow the chain of invocation:
You invoke the B() constructor.
It invokes the A() constructor.
The A() constructor invokes the overridden abstract methot
The method B#initializeSuperMember() references subMember, which has not yet been initialized. NPE.
It is never valid to do what you have done.
Also, it is not clear what you are trying to accomplish. You should ask a separate question explaining what your goal is.
Hum, this code does not look good and in all likelyhood this is a sign of a bad situation. But there are some tricks that can help you do what you want, using a factory method like this:
public static abstract class A {
public abstract Object createObject();
}
public static abstract class B extends A {
private Object member;
public B(Object member) {
super();
this.member = member;
}
}
public static B createB(final Object member) {
return new B(member) {
#Override
public Object createObject() {
return member.getClass();
}
};
}
The problem is when you call super(), the subMember is not initialized yet. You need to pass subMemeber as a parameter.
public abstract class A {
public A (Object subMember) {
// initialize here
}
}
class B extends A {
public B (Object subMember) {
super(subMember);
// do your other things
}
}
Since you don't want to have subMember in the abstract class, another approach is to override the getter.
public abstract class A {
public abstract Object getSuperMember();
protected void checkSuperMember() {
// check if the supberMember is fine
}
}
public class B extends A {
private Object subMember;
public B(Object subMember) {
super();
this.subMember = subMember;
checkSuperMemeber();
}
#Override
public Object getSuperMember() {
return subMember.get();
}
}
I hope this can remove your duplicate code as well.
I was wondering if the below code makes any sense, since the compiler warns that "the blank final field objects may not have been initialized". Is there a better way of doing this?
public abstract Test {
protected final ArrayList<Object> objects;
}
public TestSubA extends Test {
public TestSubA() {
objects = new ArrayList<Objects>(20);
// Other stuff
}
}
public TestSubB extends Test {
public TestSubB() {
objects = new ArrayList<Objects>(100);
// Other stuff
}
}
I would make the field final and force the constructors to pass the value up:
public abstract class Test {
private final ArrayList<Object> objects;
protected ArrayList<Object> getObjects() {
return objects;
}
protected Test(ArrayList<Object> objects) {
this.objects = objects;
}
}
public class TestSubA extends Test {
public TestSubA() {
super(new ArrayList<Object>(20));
// Other stuff
}
}
public class TestSubB extends Test {
public TestSubB() {
super(new ArrayList<Object>(100));
// Other stuff
}
}
The problem with initializing the final parameters directly in the constructor of the sub-classes is that you need to do it all in one line since super() must be the first statement of the constructor. So instead, I prefer to make the constructor non-public and make a static build method like this:
public abstract class Test {
protected final ArrayList<Object> objects;
protected Test(ArrayList<Object> objects) {
this.objects = objects;
}
}
public class TestSubA extends Test {
public static TestSubA build() {
ArrayList<Object> objects = new ArrayList<Object>(20);
objects.put(...);
// Other stuff
return new TestSubA(objects);
}
private TestSubA(ArrayList<Object> objects) {
super(objects);
}
}
Instantiate the objects in the abstract class constructor and just pass the difference to the that constructor.
Generally speaking, it might be better to have a constructor in the base class that always sets the field, and not have a default constructor that doesn't set it. The subclasses can then explicitly pass the parameter in the first line of their constructor using super(value)