1

I have a MyClass which has an attribute of type MyAttribute. This class is inherited by MySubClass which has an attribute of type MySubAttribute. MySubAttribute is a subclass of MyAttribute :

class MyClass {
    MyAttribute myAttribute;
    MyClass(MyAttribute myAttribute) {
        this.myAttribute = myAttribute;
    }

    MyAttribute getMyAttribute() {
        return myAttribute;
    }
}

class MySubClass extends MyClass {
    MySubClass(MySubAttribute mySubAttribute) {
        super(mySubAttribute);
    }
}


class MyAttribute {
    void doSomething() {
    }
}

class MySubAttribute extends MyAttribute {
    @Override
    void doSomething() {
        super.doSomething();
    }
    void doSomethingElse() {
    }
}

Now imagine that I have the following code:

mySubClass.getMyAttribute();

How to make the returned value of type MySubAttribute?

4 Answers 4

2

You should take a look at Java Generics.

Also, you no longer need to define MySubClass unless you wanna add extra methods or properties to it.

class MyClass<T extends MyAttribute> {
  T myAttribute;
  MyClass(T myAttribute) {
    this.myAttribute = myAttribute;
  }

  T getMyAttribute() {
    return myAttribute;
  }
}


class MyAttribute {
  void doSomething() {
    System.out.println("Doing something...");
  }
}

class MySubAttribute extends MyAttribute {
  void doSomethingElse() {
    System.out.println("Doing something else...");
  }
}

// You would instantiate `mySubClass` as follows
MyClass<MySubAttribute> mySubClass = new MyClass<>(new MySubAttribute());
mySubClass.getMyAttribute().doSomethingElse();
Sign up to request clarification or add additional context in comments.

Comments

1

You could add something like this to MySubClass:

@Override
MySubAttribute getMyAttribute() {
    return new MySubAttribute();
}

7 Comments

I assume you are asking about the static return type. The way the code is written in your question, mySubClass.getMyAttribute() is already going to return a MySubAttribute instance, assuming mySubClass points to an instance of MySubClass.
I don't think so because when i do : mySubCass.getMyAttribute(); the method who is used is that whic is in MyClass. So the retuned value type is MyAttribute.
"the method who is used is that whic is in MyClass. So the retuned value type is MyAttribute" - That static return type is MyAttribute but the type of the object returned is MySubAttribute.
So how to do this: MySubAttribute msa = mySubClass.getAttribute(); msa.doSomethingElse(); because it doesn't compile and I would like to avoid using casting @JeffScottBrown
MySubAttribute msa = (MySubAttribute)mySubClass.getAttribute(); msa.doSomethingElse();
|
0

The usual solution is generics:

class MyClass<A extends MyAttribute> {
    A myAttribute;
    MyClass(A myAttribute) {
        this.myAttribute = myAttribute;
    }

    A getMyAttribute() {
        return myAttribute;
    }
}

class MySubClass extends MyClass<MySubAttribute> {

Alternatively, you could have MySubClass override the getter with a narrower return type:

    @Override
    MySubAttribute getMyAttribute() {
        // we know the cast succeeds because we have set a MySubAttribute in the constructor
        return (MySubAttribute) myAttribute; 
    }

The generic solution offers better compile time checking of the implementing class, and allows a caller to refer to the type of the attribute even if they don't know the subtype of MyClass by writing MyClass<MySubAttribute>. On the other hand, the generic solution does require callers to write a type parameter (even if just MyClass<?>), so calling code gets slightly more verbose.

Comments

-1

If I understand correctly, then you're asking for:

public interface HasMyAttribute {
    MyAttribute getMyAttribute();
}

public class MyClass implements HasMyAttribute {
    private MyAttribute myAttribute;

    public MyClass(MyAttribute myAttribute) {
        this.myAttribute = myAttribute;
    }

    @Override
    public MyAttribute getMyAttribute() {
        return this.myAttribute;
    }
}

public class MySubClass extends MyClass implements HasMyAttribute {

    private MySubAttribute mySubAttribute;

    public MySubClass(MySubAttribute mySubAttribute) {
        super(mySubAttribute);
        this.mySubAttribute = mySubAttribute;
    }

    @Override
    public MySubAttribute getMyAttribute() {
        return mySubAttribute;
    }
}

(though, if you don't need two distinct concrete classes, @xxMrPHDxx's answer is much better)

5 Comments

If you do this there will be 2 attribute references in every instance of MySubClass, those will be mySubAttribute and myAttribute, and both references will point to the same instance. This is almost certainly not desireable.
Ok, I'll bite. Why?
"Ok, I'll bite. Why?" - myAttribute is defined in MyClass so there will be a private myAttribute field and because of the getter there will be a public myAttribute property (as distinct from the field). MySubClass extends MyClass so it inherits those things, and then in addition to that is a mySubAttribute field and property defined in MySubClass.
I wasn't asking why there would be 2 references in every instance of MySubClass, I was asking why it was not desirable. Is there some sort of reference limit to a single instance we're supposed to maintain, or some other obscure design principle I'm not aware of?
"Is there some sort of reference limit to a single instance we're supposed to maintain, or some other obscure design principle I'm not aware of?" - No. There isn't any sort of reference limit in the JVM (not one that you have any practical reason to care about), and I wouldn't consider the design principles in question to be obscure at all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.