我搞不懂为什么这段代码不能编译.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Generic {


public static void main(String[] args) {

    //List of imputs
    List<Test> tests = new ArrayList<>();
    tests.add(new TestSub1());
    tests.add(new TestSub2());

    // Processors are in a Map
    Map<String, Processor<? extends Test>> testMaps = new HashMap<>();
    testMaps.put("Processor1", new Processor1());
    testMaps.put("Processor2", new Processor2());


    // Doesn't compile
    // java: incompatible types: Generic.Test cannot be converted to capture#1 of ? extends Generic.Test
    tests.stream().filter(t -> t instanceof TestSub1)
            .forEach(test ->
                testMaps.get("Processor1").doWork(tests.get(0))
            );
}


static class Test {
}

static class TestSub1 extends Test {

}

static class TestSub2 extends Test {

}

static abstract class Processor<T extends Test> {

    abstract void doWork(T t);
}

// Processors can handle subclasses of Test
static  class Processor1 extends Processor<TestSub1> {

    @Override
    void doWork(TestSub1 testSub1) {
        System.out.println("processing testSub1");
    }
}

static  class Processor2 extends  Processor<TestSub2> {

    @Override
    void doWork(TestSub2 testSub2) {
        System.out.println("processing testSub2");
    }
}
}

我想有每个测试的子类处理器.我试图将Tests.get(0)转换为TestSub1,但也不起作用.有没有可能这样做,或者我怎样才能使我的处理器类型安全和通用.

谢谢!

推荐答案

您理所当然地得到了一个编译时错误.您有一个值为? extends Test的映射,但是编译器不知道处理器类的泛型类型将具有的确切类型.然后,try 将一个超类传递给doWork方法.

下面的例子可以更好地理解这一点:

testMaps.get("Processor1").doWork(tests.get(1))

如果将一个TestSub2类型的对象传递给doWork()方法会怎么样?Processor1只能处理类型TestSub1的类.在前面的代码中,您以这样一种方式过滤结果并不重要,即只有适当类型的参数才能到达方法.编译器不知道这一点--它不分析代码的语义.Java是一种强类型语言,因此编译器不会允许您这样做.

在这种情况下,您可以使用像Joshua Bloch提出的"类型安全的异类容器"这样的设计模式:

class ProcessorTypeSafeContainer {
    private final Map<Class<? extends Test>, Processor<? extends Test>> processorRegistry = new HashMap<>();

    <T extends Test> void registerProcessor(Class<T> type, Processor<T> processor) {
        processorRegistry.put(type, processor);
    }

    void processTest(Test test) {
        Processor<? extends Test> processor = processorRegistry.get(test.getClass());
        if (processor == null)
            throw new IllegalArgumentException("No processor registered for type " + test.getClass());
        doWorkWithProcessor(processor, test);
    }

    private <T extends Test> void doWorkWithProcessor(Processor<T> processor, Test test) {
        processor.doWork((T) test);
    }
}

然后你可以像这样简单地使用它:

public static void main(String[] args) {
    List<Test> tests = new ArrayList<>();
    tests.add(new TestSub1());
    tests.add(new TestSub2());

    ProcessorTypeSafeContainer container = new ProcessorTypeSafeContainer();
    container.registerProcessor(TestSub1.class, new Processor1());
    container.registerProcessor(TestSub2.class, new Processor2());

    tests.forEach(container::processTest);
}

Java相关问答推荐

当切换javaFX场景时,stage的大小正在Minimize

我的scala文件失败了Scala.g4 ANTLR语法

Java自定义ThreadPool—暂停任务提交并取消当前排队任务

在spring—data中自动发现native—sql查询期间遇到重复的SQL别名[id]

JDK22执行repackage of goal org. springframework. boot:spring—boot—maven—plugin:3.2.3:repackage failed:unsupported class file major version 66—>

Java List with all combinations of 8 booleans

为什么BasicComboBoxRenderer在文本不存在或文本为空的情况下设置两次文本?

DTO到实体,反之亦然,控制器和服务之间的哪一层应该处理转换?

在bash中将数组作为Java程序的参数传递

由于 list 中的权限错误,Android未生成

Spring @Value default无法计算表达式

与不同顺序的组进行匹配,不重复组但分开

无法在Java中处理PayPal支付响应

Spring-Boot Kafka应用程序到GraalVM本机映像-找不到org.apache.kafka.streams.processor.internals.DefaultKafkaClientSupplier

解析方法";javax/imageio/metadata/IIOMetadata.getAsTree(Ljava/lang/String;)Lorg/w3c/dom/Node时加载约束冲突

在Java泛型中使用通配符时,如何推断类型

如何使用jOOQ在PostgreSQL中从枚举类型生成Java枚举

窗口启动后不久,从java.awt.Graphics disapear创建的矩形

从 Java 17 切换回 Java 8 后出现的问题

移动二维数组的行