Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何解决Java泛型通配符/抽象歧义问题?_Java_Generics_Abstract Class - Fatal编程技术网

如何解决Java泛型通配符/抽象歧义问题?

如何解决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

下面的代码是我的项目正在使用的模式的简化版本。我们使用的标准模式是每个对象类型都有一个Writer。对于一个抽象类型的子类型(在本例中为Animal),我希望使用枚举作为查找正确编写器的方法

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)