简体   繁体   中英

How can I refer to the type of the current class?

This is kind of difficult to explain, but I've looked everywhere, and I couldn't find any good answer.

I've also seen Stack Overflow questions How can I refer to the class type a interface is implementing in Java? and How do I return an instance of an object of the same type as the class passed in using Java 6? , but they couldn't answer my question. There is an exception when I apply inheritance.

There is an example, to make it easier to understand:

Let's say I have some interface called SelfMaker:

public interface SelfMaker <SELF>{
    public SELF getSelf();
}

And A have a Dog, which can procreate with another dogs. So the dog is a "SelfMaker", like this:

public class Dog implements SelfMaker<Dog> {
    String color;

    public String toString() {
        return "some " + color + " dog";
    }

    public Dog procreate(Dog anotherDog) {
        Dog son = getSelf();
        son.color = color;
        return son;
    }

    @Override
    public Dog getSelf() {
        return new Dog();
    }
}

But then, I have a DomesticDog, who is a Dog, but it has a lovely family who named him. Like this:

public class DomesticDog extends Dog {
    private String name;

    public String toString() {
        return super.toString() + " named " + name;
    }
}

Now, I have some class that handles couples of things that are "SelfMaker"s, let's call this class "Couple". Like this:

public class Couple<T extends SelfMaker<T>> {
    private T first;
    private T second;

    public String toString() {
        return first.toString() + " and " + second.toString();
    }
}

THE EXCEPTION:

The exception comes when I want to create a couple of DomesticDog s. Like this:

public class CoupleOfDomesticDogs extends Couple<DomesticDog>{
    public DomesticDog procreate(){
        DomesticDog son = first.procreate(second);
        return son;
    }
}

This will throw an exception on <DomesticDog> complaining: Bound mismatch: The type DomesticDog is not a valid substitute for the bounded parameter <T extends SelfMaker<T>> of the type Couple<T>

I have already tried to change the generalised variable from class Couple to this: Couple<T extends SelfMaker<?>> but the "son" won't be a DomesticDog (and I want the "son" to be a DomesticDog). If I add some cast, then it will compile, but it will be less legible.

So... here is the question: Is there a way to achieve this without castings and generalizations?

There is no way that I can think of to do this without casting. Your problem will be solved if you override the procreate and getSelf methods of DomesticDog and change the declaration of class Couple as such:

public class DomesticDog extends Dog {
    private String name;

    public DomesticDog procreate(Dog anotherDog) {
        return (DomesticDog)super.procreate(anotherDog);
    }

    public Dog getSelf() {
        return new DomesticDog();
    }

    public String toString() {
        return super.toString() + " named " + name;
    }
}

public class Couple<T extends SelfMaker<? super T>> {
    protected T first;
    protected T second;

    public String toString() {
        return first.toString() + " and " + second.toString();
    }
}

If you don't want to override getSelf() in every subclass of Dog, you could make the following change in class Dog:

public Dog getSelf() {
    Class<? extends Dog> thisClass = this.getClass();
    try {
        return thisClass.newInstance();
    } catch (InstantiationException e) {
    } catch (IllegalAccessException e) {
    }
    throw new UnsupportedOperationException(thisClass 
                         + " does not supply a public no-arg constructor");
}

This guarantees that every value returned by getSelf() is an instance of this.getClass() . But you would still have to cast the return value of procreate() for subclasses. There is no way to explicitly specify a return type as this.getClass() .

You will have to make Dog generic and abstract, with a type parameter that indicates the result of getSelf() . Each type of Dog will then need to implement this with themselves as the parameter:

public abstract class Dog<T> implements SelfMaker<T> {
    String color;

    public String toString() {
        return "some " + color + " dog";
    }

    public T procreate(T anotherDog) {
        T son = getSelf();
        son.color = color;
        return son;
    }

}

public class DomesticDog extends Dog<DomesticDog> {
    private String name;

    public String toString() {
        return super.toString() + " named " + name;
    }

    @Override
    public DomesticDog getSelf() {
        return new DomesticDog();
    }
}

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