简体   繁体   中英

Avoid casting in inherited java-classes

I have a class:

class MyClass {

  public MyClass getParent() { ... }

  public MyClass[] getChildren() { ... }

  ....

}

and a subclass

MySubClass extends MyClass {

  public String getId() { }

  ...
}

Everytime I used getChildren() or getParent() on an instance of MySubClass , I have to cast the result of theese methods, eg:

MySubClass sub = new MySubClass();
((MySubClass)sub.getParent()).getId();

Is there any way (by language or design) to avoid that casting?

Thanks for any ideas!

Update What I would like is that getParent() and getChildren() always return the type of the instance they are called from, eg sub.getChildren() should return MySubClass[]

You can use the self-type pattern:

class MyClass<T extends MyClass<T>> { 
  public T getParent() { ... }
  public List<T> getChildren() { ... }  // you can use an array here too, but don't :)
}

class MySubclass extends MyClass<MySubclass> {
  public String getId() { ... }
}

You can implement your getParent and getChildren methods as desired, declare fields in MyClass that hold T references and know that they behave at least as MyClass references, et cetera. And if you call getParent or getChildren on a MySubClass , you can use the return values as MySubClass instances with no casts anywhere.

The primary disadvantage of this approach is that people who haven't seen it before tend to get pretty confused.

Is there any way (by language or design) to avoid that casting?

The answer is No . If you want to access super class field or method than you must explicitly cast.

Beginning with Java 5.0, you can override methods with covariant return types , ie you can override a method to return a subclass parent class. (see Covariant return type in Java ):

public class MySubClass extends MyClass {

  @Override
  public MySubClass getParent() {
    return (MySubClass) super.getParent();
  }

  @Override
  public MySubClass[] getChildren() {
    return (MySubClass[]) super.getChildren();
  }

  public String getId() {
    ...
  }
}

You can then call new MySubClass().getChildren()[0].getId() .

Of course this will only work if MySubClass always has MySubClass instances as parent and/or children

Yes, assuming that you know that the parent and children of a MySubClass will always be of type MySubClass .

In that case you could just narrow the return types in MySubClass and do the casting there:

MySubClass extends MyClass() {
    @Overrides
    public MySubClass getParent() { return (MySubclass) super.getParent(); }

    @Overrides
    public MySubClass[] getChildren() { return (MySubclass[]) super.getChildren(); }

    public String getId() { }

    ...
}

Maybe using generics ( http://docs.oracle.com/javase/tutorial/extra/generics/index.html )

You should have something like this:

public class MyClass<T extends MyClass> {

    public T getParent() { return null; }

    public MyClass[] getChildren() {
        return null;
    }

    public static void main(String[] args) {
        MyClass<MySubClass> o = new MySubClass();
        o.getParent().getId();
    }
}

class MySubClass extends MyClass<MySubClass> {

    public String getId() {
        return "";
    }
}

Depending on what you are actually trying to do, either make your base class abstract and add getId():

abstract class MyClass() {
    public MyClass getParent() { ... }
    public MyClass[] getChildren() { ... }
    public String getId();
    ....
}

MySubClass extends MyClass() {
    @Overrides
    public String getId() { }
    ...
}

Alternatively, depending on your requirements, implement getId() in your base class:

class MyClass() {
    public MyClass getParent() { ... }
    public MyClass[] getChildren() { ... }
    public String getId() { }
    ....
}

MySubClass extends MyClass() {
    ...
}

Add the method getId to the super class as well ie. MyClass.

Any subclasses can still override and have their own implementation. If you are scared of subclasses not overriding getId,then throw an exception from the super class from getId.

Th erotically, getID is some thing that is applicable for All Class and hence can be added to super.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM