java在泛型方法中使用它(继承)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java在泛型方法中使用它(继承)相关的知识,希望对你有一定的参考价值。

在创建在父类中使用的lambda时,我正在尝试访问子类方法和字段。代码更容易解​​释:

class Parent {
    List<Processor<? extends Parent>> processors;

    private void doSmth() {
        for (Processor<? extends Parent> processor : processors) {
            processor.doJob(this);  //this lines gives compile error
        }
    }

    public void registerListeners(Processor<? extends Parent> ... subscribers) {
        this.subscriberList = Arrays.asList(subscribers);
    }
}

ProcessorFunctionalInterface的地方。

public interface Processor<T extends Parent> extends BiFunction<T, Message,  Boolean> {
    AtomicReference<Boolean> ok = new AtomicReference<>(false);

    default void doJob(T client, Message message) {
        if (apply(client, message))
            ok.set(true);
    }

    default boolean isDone() {
        return ok.get();
    }
}

想要使用这些类的示例:

Child childInstance= new Child(); //where Child class extends Parent
childInstance.registerListeners((child, message) -> child.callSomeChildMethod());
childInstance.doSmth(message);

在没有冗余指定参数类型的情况下创建lambda会非常酷,如下所示:

childInstance.registerListeners((Processor<Child>) (child, message) -> child.callSomeChildMethod());

(因为它总是应该是我注册监听器的类型) 问题是代码没有编译错误 incompatible types: Parent cannot be converted to capture#1 of ? extends Parent 这是合乎逻辑的(我理解其中的原因)。在java中是否有某些方法我可以使用此代码? 提前致谢!

答案

你在List<Processor<? extends Parent>> processors;课上有Parent的想法是不可取的。如您所见,因为您没有提到列表所具有的进程类型;无论你在哪里调用processor.doJob(anyObjectHere),都会以某种方式抛出错误(除非你进行显式转换)

尝试做这样的事情;

  1. 声明一个Client而不是你的Parent,其中包含List<Processor<? extends Parent>> processors中的处理器类型; abstract class Client<T extends Client<T>> { List<Processor<T>> processors; public void doSmth(Message message) { for (Processor<T> processor : processors) { processor.doJob(getThis(), message); } } abstract T getThis(); public void registerListeners(Processor<T> subscribers) { this.processors = Arrays.asList(subscribers); } }
  2. 将你的Processor定义改为纳入Client而不是Parent interface Processor<T extends Client<T>> extends BiFunction<T, Message, Boolean> { AtomicReference<Boolean> ok = new AtomicReference<>(false); default void doJob(T client, Message message) { if (apply(client, message)) ok.set(true); } default boolean isDone() { return ok.get(); } }
  3. 现在你可以像这样创建你的Child; class Child extends Client<Child> { boolean callSomeChildMethod() { return true; } @Override Child getThis() { return this; } }
  4. 并像以前一样打电话给他们; Child childInstance= new Child(); //where Child class extends Parent childInstance.registerListeners((child, message) -> child.callSomeChildMethod()); childInstance.doSmth(message);

这样既没有编译错误也没有警告

另一答案

你可以简单地转换processor对象来声明你想要传递一个派生自Parent的类的对象(可能是Child),并将this转换为相同的类型。它甚至可以是通用的:

private <T extends Parent> void doSmth() {
    for (Processor<? extends Parent> p : processors) {
        Processor<T> processor = (Processor<T>) p; // explicit cast
        processor.doJob((T) this);  //no compile error
    }
}

以上是关于java在泛型方法中使用它(继承)的主要内容,如果未能解决你的问题,请参考以下文章

在泛型方法中返回特定类型,具体取决于运行时没有反射或动态的枚举值

在泛型方法中返回原始集合类型

Java泛型擦除——以super关键字指定类型下限的在泛型擦除时会被擦成啥样的呢?

如何在泛型集合上创建扩展方法

操作 Java 泛型:泛型在继承方面体现与通配符使用

泛型方法与桥方法