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?
CodePudding user response:
You could add something like this to MySubClass
:
@Override
MySubAttribute getMyAttribute() {
return new MySubAttribute();
}
CodePudding user response:
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();
CodePudding user response:
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.
CodePudding user response:
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)