简体   繁体   中英

java inheritance

Given these classes:

class Father {
  public Father getMe() {
    return this;
  }
}

class Child extends Father { .. }

I'm calling the public method of the Father class from the Child class:

Child c = new Child();
Child c1 = c.getMe();

So, this is not working, i have to use a cast to make it work :

Child c1 = (Child) c.getMe();

The question is: is there a better way to make it work without the cast? can be like this ?? :

public <T extends Father> T getMe() {
  return this;
}

Thanks in advance.

You should override getMe method with return type Child at Child class. This feauture is called as covariant return, it comes with jdk1.5 ..

class Child extends Father{  
       public Child getMe() {    
             return this;  
        }
   }

What about this solution?. It did not look elegant, you should cast to T at getThis method.. But there is no need to override getThis method at subclasses.. But unfortunately type safety is not enforced, one can define such a base object , Base<Child> baseChild = new Base<Child>(); Therefore I do not recommend this method..

class Base<T extends Base<T>> {
    public  T getThis() {

        return  (T) this;
    }
}

class Child extends Base<Child>{

}

Child child = new Child();
child.getThis(); // return type is Child
Base base = new Base();
base.getThis(); // return type is base

This works :)))

Child c = new Child();
Child c2 = c; //same as c.getMe()

No, there really isn't because Child is a subclass of Father , not the other way around. If you had

public Child getMe();

You could do

Father father = c.getMe();

with no problem because you can convert implicitly to a supertype, you can't do that the other way around. Basically, think of it this way. Every child is a father, in your case, but not every father is a child. Your second solution would work, although you would have to declare the generic type to be of type Child and that makes it not so much a question about inheritance and more about generics.

Ultimately, at the end of the day, as one of the commenters said, if you really need to know exactly which type the instance is, you may be doing something wrong. The real benefit of inheritance is the ability to decouple the pieces of your code. The client code doesn't care what the actual implementation is, it just knows what methods it needs to call to get something done. Granted, there are some instances where you do need to cast an object because you do need to know exactly what type it is, but that should be a rare occurrence. In this instance the value would be to define a method that takes a Father object as a parameter and understands how to work with the Father interface. All of the methods it would need would be defined as part of the Father class. Other code could create custom subclasses of Father that would allow them to extend the functionality of the class while still allowing them to work with the code designed around the Father interface.

The canonical way to do this is by using the curiously recurring template pattern :

class Father<T extends Father> {
  T getMe() { return (T)this; }
}

class Child extends Father<Child> {}

Child child = new Child().getMe(); // OK now.

This accomplishes what you want. There are a couple of uncommon but valid use cases where a base class needs access to its derived type. One example is something like this:

class Cached<T extends Cached> {
  public static T create(String name) {
    T cached = sCache.get(name);
    if (cached != null) return cached;

    cached = // create new T...
    sCache.put(name, cached);
    return cached;
  }

  private static Map<String, T> sCache = new HashMap<String, T>();
}

This is a neat trick, but it comes with a cost: you've broken the subtype relation. Your Father class is no longer a superclass of Child because there is no simple Father class, just Father<T> . You may be able to do some clever wildcard hackery to get subtyping back when you need it, but you'll find it cumbersome. Depending on your problem, this may be a worthwhile trade-off.

Java does not support covariance well.

This is the closest I get to something like this is: (but it's not practical)

public abstract class AFather<P extends AFather<P>> {
    public P getMe() { return (P)this; }
}
public class Father extends AFather<Father> {}
public abstract class AChild<P extends AChild<P>> extends AFather<P> {}
public class Child extends AChild<Child> {}

The most practical way I found of doing this is to overwride the method is the subclass:

public class Father {
    public Father getMe() { return this; }
}
public class Child extends Father {
    public Child getMe() { return (Child)super.getMe(); }
}

By the way, I don't know Scala well, but that language handles nice covariant and contravariant types.

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