如何解决Java泛型通配符/抽象歧义问题?
下面的代码是我的项目正在使用的模式的简化版本。我们使用的标准模式是每个对象类型都有一个Writer。对于一个抽象类型的子类型(在本例中为Animal),我希望使用枚举作为查找正确编写器的方法如何解决Java泛型通配符/抽象歧义问题?,java,generics,abstract-class,Java,Generics,Abstract Class,下面的代码是我的项目正在使用的模式的简化版本。我们使用的标准模式是每个对象类型都有一个Writer。对于一个抽象类型的子类型(在本例中为Animal),我希望使用枚举作为查找正确编写器的方法 abstract class Writer<T> { abstract void write(T value); } abstract class Animal { abstract AnimalType getType(); } class Cat extends Anim
abstract class Writer<T> {
abstract void write(T value);
}
abstract class Animal {
abstract AnimalType getType();
}
class Cat extends Animal {
AnimalType getType() { return AnimalType.CAT; }
}
class CatWriter extends Writer<Cat> {
void write(Cat value) { }
}
// The AnimalType stores a reference to the correct writer for the Animal subclass
enum AnimalType {
CAT(new CatWriter());
Writer<? extends Animal> writer;
Writer writerThatWorksWithWarning;
Writer<Animal> writerThatWorksButCantBeAssigned;
AnimalType(Writer<? extends Animal> writer) {
this.writerThatWorksWithWarning = writer;
this.writer = writer;
// ERROR: Incompatible Types
this.writerThatWorksButCantBeAssigned = writer;
}
}
抽象类编写器{
抽象空写(T值);
}
抽象类动物{
抽象AnimalType getType();
}
猫科动物{
AnimalType getType(){return AnimalType.CAT;}
}
类CatWriter扩展了Writer{
无效写入(Cat值){}
}
//AnimalType存储对动物子类的正确编写器的引用
枚举动物型{
CAT(新CatWriter());
Writer我认为这里的问题是不能用enum表示类型层次结构,因此无法告诉类型系统对于enum{CAT,DOG;}
CAT
应键入CAT extensed Animal
,而DOG
应键入DOG extensed Animal
。既然您已经有了类层次结构,为什么不使用它呢?例如:
public interface Writer<T> {
public void write(T t);
}
public abstract class Animal<T extends Animal<T>> {
public abstract Writer<T> getWriter()...
}
public class Cat extends Animal<Cat> {
@Override
public Writer<Cat> getWriter()...
}
公共接口编写器{
公共无效写入(T);
}
公共抽象类动物{
公共摘要编写器getWriter()。。。
}
公营猫科动物{
@凌驾
公共编写器getWriter()。。。
}
在我看来,您真正使用enum的目的更像是
的hashmap,有点像内置的单例。您可以这样做,但只能通过隐藏类型来实现。试试这个
enum AnimalType {
CAT(new CatWriter());
private Writer<? extends Animal> writer;
AnimalType(Writer<? extends Animal> writer) {
this.writer = writer;
}
public Writer<Animal> getWriter() {
return (Writer<Animal>)writer;
}
}
我会让动物不知道作家,毕竟它们是动物 您可以有一个
映射
,对于其中的每个条目,您都可以保持键类
和值编写器
大约是相同的类型X
。我们无法用类型来表示这种关系,因此必须在某些位置执行强制转换。如果查找类型失败(例如Cat),请尝试使用其超级类型(动物)再次查找
类型安全的公共API可以设计为
static public <T> void registerWriter(Class<T> type, Writer<T> writer)
static public <T> Writer<? super T> getWriter(Class<T> type)
根据对象的类型,可以找到合适的编写器,编写器将接受该对象。事实上,它基于您提供的相同示例。其思想是,您正在控制setter,因此您可以在getter中键入cast而无需担心。啊,我明白了,所以,即使我有未选中的cast,我也不必担心,因为我知道如何正确?@Renesis:是的,准确地说。请参见您提供的示例。解决方案是保留属性
私有
,并提供您选择的公共setter
和公共getter
。为了保证安全。这里您不需要任何setter,因为您使用的是枚举
并初始化ev因此,你不可能在那里得到一些愚蠢的东西。然后CAT.getwriter().write(dog)
将在没有任何警告的情况下编译。@Ricky Clarkson:我只是试图解决手头的问题。此外,我在帖子中已经提出了一个建议,关于如何实现所有这些。是的,我正在像HashMap一样使用它,事实上,在我需要枚举之前,我一直打算使用它,因为我们为该类型存储一个整数代码。因此,首先,它是放置writer的一个方便的地方,其次,将writer存储在Cat中本身将打破其他主要对象(没有导致此问题的超类)的约定。我想提出这个建议。这位作者很困惑。@Adeel Ansari你能告诉我你为什么删除了你的答案吗?我会接受的。我喜欢你的答案,尽管演员Adeel Ansari(在删除的答案中)提出了这个建议修复我的代码,我稍后会看一看并实施你的建议,看看它是否与代码的其余部分一致。@Renesis:我在那里得到了反对票,可能是因为人们不理解我实际上没有提出新的解决方案,只是试图快速修复手中的问题。但是,已经取消了你的b的帖子利斯。
Animal cat = new Cat();
Animal dog = new Dog();
cat.getType().getWriter().write(cat);
// java.lang.ClassCastException in the write() method's argument
cat.getType().getWriter().write(dog);
static public <T> void registerWriter(Class<T> type, Writer<T> writer)
static public <T> Writer<? super T> getWriter(Class<T> type)
static public static void write(Object obj)