Java泛型有界类型参数接口如何使用?赋值Dog实例报错原因是什么?
错误原因
- 你定义的泛型参数
<T extends AnimalProperty>的含义是:T是任意一个实现了AnimalProperty接口的具体类型,而非固定为Dog类。比如后续使用者可以合法声明Test<Cat>(只要Cat也实现了AnimalProperty),此时T的实际类型是Cat,你在构造方法中强制赋值Dog实例,自然会出现类型不匹配的错误。 - 你直接写
AnimalProperty prop = new Dog()能正常运行,是因为这里明确使用父接口类型引用指向子类实例,属于向上转型的合法用法;但泛型场景下T是动态绑定的具体子类型,和固定写AnimalProperty类型的语义完全不同。
正确使用方案
根据你的使用场景可以选择以下任意一种方案:
方案1:保留泛型,实例从外部传入
如果你的Test类需要支持任意AnimalProperty实现的通用能力,不要在内部硬编码实例化Dog,改为通过构造方法参数传入实例:
class Test<T extends AnimalProperty> { T animalWithProp; // 构造方法接收外部传入的T类型实例 public Test(T animal) { this.animalWithProp = animal; System.out.println(animalWithProp.sound()); } } // 使用示例 public class Main { public static void main(String[] args) { // 传入Dog实例,T自动推断为Dog Test<Dog> dogTest = new Test<>(new Dog()); // 如果后续有Cat实现,也可以直接传入 // Test<Cat> catTest = new Test<>(new Cat()); } }
方案2:不需要泛型则直接声明接口类型
如果你的Test类不需要区分不同的AnimalProperty实现类型,完全不需要使用泛型,直接把成员变量声明为AnimalProperty即可:
class Test { AnimalProperty animalWithProp; public Test() { this.animalWithProp = new Dog(); System.out.println(animalWithProp.sound()); } }
方案3:保留泛型的同时提供默认Dog实现
如果你希望保留泛型能力的同时,提供默认用Dog的无参构造方案,可以新增静态工厂方法实现:
class Test<T extends AnimalProperty> { T animalWithProp; public Test(T animal) { this.animalWithProp = animal; System.out.println(animalWithProp.sound()); } // 静态工厂方法返回固定Test<Dog>类型 public static Test<Dog> createWithDefaultDog() { return new Test<>(new Dog()); } } // 使用默认Dog实例的示例 public class Main { public static void main(String[] args) { Test<Dog> defaultTest = Test.createWithDefaultDog(); } }
内容的提问来源于stack exchange,提问作者Pablo
相关产品推荐
相关产品推荐

