【问题标题】:Implement an interface with a method signature whose generic parameters extend an interface使用泛型参数扩展接口的方法签名实现接口
【发布时间】:2022-01-19 07:53:08
【问题描述】:

以下是我正在尝试完成的示例。我正在尝试创建实现GenericRunnerLibraryRunner。但是,我收到一个 IDE 警告,指出 LibraryRunner 没有实现 GenericRunner 接口中的方法。这是有道理的,方法签名不匹配,但是如何在仍然使用扩展GenericCalculatorLibraryCalculator 的同时使方法签名匹配?

public class LibraryRunner implements GenericRunner {
    @Override
    public <T> T run(LibraryCalculator<T> calculator) {
        return T;
    }
}

public interface GenericRunner {
    <T, A> T run(GenericCalculator<T, A> calculator);
}


public interface LibraryCalculator<T> extends GenericCalculator<T, LibraryAlgorithm> {
    T calc(LibraryAlgorithm algorithm) throws LibraryException;
}

public interface GenericCalculator<T, A> {
    T calc(A algorithm) throws Exception;
}


public class LibraryException extends Exception {
    
}

【问题讨论】:

    标签: java generics


    【解决方案1】:

    接口的定义方式,即使LibraryCalculatorGenericCalculator 的子类型,您也不能覆盖该方法并更改其签名。另一个答案解释了原因。

    解决这个问题的一种方法是使用计算器类型参数化GenericRunner 接口:

    public interface GenericRunner<T, A, C extends GenericCalculator<T, A>> {
        T run(C calculator);
    }
    
    public class LibraryRunner<T> implements GenericRunner<T, LibraryAlgorithm, LibraryCalculator<T>> {
    
        @Override
        public T run(LibraryCalculator<T> calculator) {
            ...
        }
    
    }
    

    但请注意,您不能在 LibraryRunner 方法中返回 Object,因为它与 T 不匹配。如果你想返回一个特定的类型,比如Object(这违背了泛型LibraryCalculator的目的),你必须明确指定它:

    public class LibraryRunner implements GenericRunner<Object, LibraryAlgorithm, LibraryCalculator<Object>> {
    
        @Override
        public Object run(LibraryCalculator<Object> calculator) {
            return new Object();
        }
    
    }
    

    如果这不是您想要的,那么由LibraryRunner 的用户来决定T 应该绑定到哪个类型。

    【讨论】:

    • 这正是我想要的,tyvm!是的,您对Object 的看法是正确的。我只是在写问题时把它扔在那里,但我确实在我的代码中返回了一个通用的 T 对象。
    【解决方案2】:

    当你重写或实现一个方法时,你总是需要满足被重写方法的条件,例如你应该仍然可以调用带有参数 GenericCalculator 的 LibraryRunner.run。否则写起来就没意义了:

    LibraryRunner libRunner = new LibraryRunner();
    GenericRunner genRunner = libRunner;
    genRunner.run(new GenericCalculator<>());
    

    覆盖异常确实有效,因为当您调用 GenericCalculator.calc 时,您会期待任何异常并且调用 LibraryCalculator.calc 会将其缩小到仅 LibraryException

    您可以将覆盖方法视为更多信息。

    【讨论】:

    • 正在寻找一种方法来实现原始问题中的目标,但我很欣赏关于我做错了什么以及为什么 LibraryException 起作用的解释。
    猜你喜欢
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    相关资源
    最近更新 更多