【问题标题】:How can I refer to the type of the current class?如何引用当前类的类型?
【发布时间】:2013-08-04 22:40:25
【问题描述】:

这有点难以解释,但我到处寻找,找不到任何好的答案。

我也看过 Stack Overflow 问题 How can I refer to the class type a interface is implementing in Java?How do I return an instance of an object of the same type as the class passed in using Java 6?,但他们无法回答我的问题。应用继承时出现异常。

有一个例子,方便理解:

假设我有一个名为 SelfMaker 的界面:

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

A 有一条狗,它可以和其他狗一起生育。所以狗是一个“自我创造者”,像这样:

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();
    }
}

但是,我有一只家养狗,它是一只狗,但它有一个可爱的家庭给他取名。像这样:

public class DomesticDog extends Dog {
    private String name;

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

现在,我有一些类可以处理一些“SelfMaker”的事情,我们称这个类为“Couple”。像这样:

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

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

例外:

当我想创建几个DomesticDogs 时出现异常。像这样:

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

这将在 &lt;DomesticDog&gt; 抱怨时引发异常:Bound mismatch: The type DomesticDog is not a valid substitute for the bounded parameter &lt;T extends SelfMaker&lt;T&gt;&gt; of the type Couple&lt;T&gt;

我已经尝试将类 Couple 的广义变量更改为:Couple&lt;T extends SelfMaker&lt;?&gt;&gt;,但“儿子”不会是 DomesticDog(我希望“儿子”成为 DomesticDog)。如果我添加一些演员表,那么它会编译,但它会不太清晰。

所以...这里的问题是:有没有一种方法可以在没有强制转换和概括的情况下实现这一目标?

【问题讨论】:

标签: java oop generics


【解决方案1】:

您必须使Dog 泛型和抽象,并带有一个指示getSelf() 结果的类型参数。然后,每种类型的Dog 都需要将其作为参数来实现:

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();
    }
}

【讨论】:

  • 但是如果你也想制作 Dog 对象呢?或者,如果您想扩展 DomesticDog 以创建 DomesticDogs 的子类别怎么办?
【解决方案2】:

如果不进行强制转换,我想不出办法来做到这一点。如果你覆盖了 DomesticDog 的 procreate 和 getSelf 方法,并且改变了 Couple 类的声明,你的问题就解决了:

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();
    }
}

如果您不想在 Dog 的每个子类中重写 getSelf(),您可以在 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");
}

这保证了 getSelf() 返回的每个值都是this.getClass() 的一个实例。但是您仍然必须为子类转换 procreate() 的返回值。无法将返回类型显式指定为 this.getClass()

【讨论】:

  • 这很聪明。但是......没有办法引用类的类型吗?这将使我的代码更适合
  • 不,除非您使用通配符或强制转换,否则您不能使用泛型显式引用“this”的运行时类。请参阅上面的编辑。
  • 所有这些想法都绕过了类型系统,并依赖程序员在编译器无法检查的情况下做正确的事情。
  • @newacct,没有办法避免这种情况。鉴于您在下面的解决方案,是什么阻止程序员继承 DomesticDog 而不是覆盖 getSelf()?或者创建一个名为 WildDog 的 Dog 子类,然后创建一个 WildDog 的子类,其中 getSelf() 不会被覆盖?避免这种情况的唯一方法是确保 Dog 的所有子类都是最终的,但是没有办法在 Dog 类中以编程方式指定这一点。无论如何,你都必须依靠程序员来做正确的事情。
  • @HansBrende:有人可以继承 DomesticDog 并且不覆盖 getSelf(),但是这样代码仍然是完全类型安全的——procreate 方法将返回 DomesticDog,它与 type 参数所说的匹配。因此,如果有人想制作一种奇怪的狗亚型,以安全的方式向家养狗繁殖,那对他们来说很好;它同样适用于代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-13
  • 1970-01-01
  • 2022-01-26
  • 2021-07-02
  • 2015-10-21
  • 1970-01-01
相关资源
最近更新 更多