Java - 将泛型类型映射到所述类型的使用者

标签 java generics

我最近玩的时候遇到了这个问题。基本上,我想创建一个中心类,某种类型的消费者可以在其中自行注册。然后,某些东西会为消费者发布对象,只有那些使用已发布类型的人才能收到它。

整个程序可以概括为:

public class Main
{
    public interface Fruit
    {
    }

    public class Apple implements Fruit
    {
    }

    public class Banana implements Fruit
    {
    }

    public interface FruitConsumer<T extends Fruit>
    {
        public void consume(T fruit);
    }

    public class Consumers<T extends Fruit>
    {
        Map<Class<T>, Collection<FruitConsumer<T>>> consumers = new HashMap<>();

        public void register(Class<T> clazz, FruitConsumer<T> consumer)
        {
            consumers.putIfAbsent(clazz, new HashSet<>());
            consumers.get(clazz).add(consumer);
        }

        public void consume(T fruit)
        {
            Collection<FruitConsumer<T>> cons = consumers.get(fruit.getClass());
            for (FruitConsumer<T> c : cons)
            {
                c.consume(fruit); // <-- Breaks if T is Apple
            }
        }
    }

    public class BananaConsumer implements FruitConsumer<Banana>
    {
        void register(Consumers c)
        {
            c.register(Banana.class, this);
            c.register(Apple.class, this); // <-- Why does this work?
        }

        @Override
        public void consume(Banana banana)
        {
            System.out.println("Mmm, banana");
        }
    }

    public static void main(String... args)
    {
        Main main = new Main();
        main.run();
    }

    private void run()
    {
        Consumers consumers = new Consumers<>();
        BananaConsumer bananaConsumer = new BananaConsumer();

        bananaConsumer.register(consumers);

        Banana banana = new Banana();
        consumers.consume(banana);

        Apple apple = new Apple();
        consumers.consume(apple);
    }
}

现在,我想我明白为什么会崩溃了。对于两个参数,编译器无法知道 Consumers.register 方法中的 T 是否是相同的 T。编译器只能强制两个参数都满足 T extends Fruit 的要求。我想记住能够在 C++ 中使用类似的代码结构,因此这两种语言必须有一些不同的地方。我的假设正确吗?

此外,正确的处理方法是什么?我希望水果子类型的不同消费者能够注册自己,并且只收到他们自己作为消费者的水果。另外,我希望您可以将自己注册为消费者,以确保安全(我注意到只要没有人“错误”地注册自己,此代码就可以工作)。

最后,这种现象的名称是什么?基本上,我可以通过谷歌搜索什么来了解更多相关信息。

最佳答案

您正在声明 void register(Consumers c)BananaConsumer并且它的参数是原始类型。你可以这样做:

    public interface FruitConsumer<T extends Fruit> {
    void register(final Consumers<T> c);
    void consume(T fruit);
}

当你实现FruitConsumer<Banana>时,这个参数将是一个香蕉消费者。

(我正在解释为什么该行可以在不阅读所有代码的情况下工作,并且其他答案提供的解决方案似乎对您的问题更符合逻辑。)

关于Java - 将泛型类型映射到所述类型的使用者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51482113/

相关文章:

Java 泛型 'Incompatible Type' 编译时错误

java - 如何获取参数化类型

java - 初学者构建 jsp 的指导

java - 在 if 语句中初始化变量,稍后在代码中使用但表示未定义

java - 使用单独的映射器、 reducer 和驱动程序类运行 MR 程序

Java 多态泛型调用

swift - 泛型 ExpressibleByStringLiteral 字符串转换

java - struts 2 jquery 插件不工作

java - 列出 Android 设备上的所有一种文件类型?

java - 如何避免java中自引用类型安全接口(interface)的参数类型警告?