Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/316.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_Reification - Fatal编程技术网

Java 如何将泛型接口传递给具体化的方法?

Java 如何将泛型接口传递给具体化的方法?,java,generics,reification,Java,Generics,Reification,我有一个通用接口 public interface MyInterface<T> { T method(T input); } 公共接口MyInterface{ T法(T输入法); } 以及它的两个实现,通过普通类,如 public class MyClass<T> implements MyInterface<T> { @Override public T method(T input) { T output =

我有一个通用接口

public interface MyInterface<T> {
    T method(T input);
}
公共接口MyInterface{
T法(T输入法);
}
以及它的两个实现,通过普通类,如

public class MyClass<T> implements MyInterface<T> {
    @Override
    public T method(T input) {
        T output = input; // whatever
        return output;
    }
}
公共类MyClass实现MyInterface{
@凌驾
公共T方法(T输入){
T输出=输入;//无论什么
返回输出;
}
}
和匿名类(见下文)。现在我想测试这些实现:

class TestClass1 {
    // ...
}

class TestClass2 {
    final int n;
    final String s;

    TestClass2(int n, String s) {
        this.n = n;
        this.s = s;
    }
    // ...
}

public class TestGenericImplementation {
    private static <T> void makeTest(T testObject, MyInterface<T> impl) {
        T output = impl.method(testObject);
        if (output == null)
            throw new NullPointerException();
        // verify output further
    }

    // Question 1. How to specify the parameter here properly?
    public static void testImplementation(MyInterface impl) {
        // Question 2. How to avoid compiler warning about unchecked cast below?

        // Doesn't work if impl is of type MyInterface<?> above
        makeTest(new TestClass1(), impl);
        makeTest(new TestClass2(1, "ABC"), impl); 

        // Ugly typecasts. Compiler complains.
        makeTest(new TestClass1(), (MyInterface<TestClass1>) impl);  
        makeTest(new TestClass2(1, "ABC"), (MyInterface<TestClass2>) impl); 
    }

    public static void main(String[] args) {
        // Question 3. How to pass the interface argument here?

        // Works but issues compiler warning about raw type
        testImplementation(new MyClass());
        testImplementation(new MyInterface() {
            @Override
            public Object method(Object input) {
                return null; // whatever
            }
        });

        // Looks ugly
        testImplementation(new MyClass<Object>()); 
        testImplementation(new MyInterface<Object>() {
            @Override
            public Object method(Object input) {
                return null;
            }
        });

        /* Diamond operator appeared only in Java 7,
         * while generics were introduced in Java 5.
         * What was the recommended way to solve this problem between 2004 and 2011?
         * Besides that, this doesn't work for anonymous classes.
         */
        testImplementation(new MyClass<>()); 
        testImplementation(new MyInterface<>() { // Doesn't work
            @Override
            public Object method(Object input) {
                return null;
            }
        });

        testImplementation(x -> x); // Lambda exprssions are for simple cases only
    }
}
类TestClass1{
// ...
}
类TestClass2{
最终整数n;
最终字符串s;
TestClass2(整数n,字符串s){
这个,n=n;
这个.s=s;
}
// ...
}
公共类TestGenericImplementation{
私有静态void makeTest(T testObject,MyInterface impl){
T输出=impl.method(testObject);
if(输出==null)
抛出新的NullPointerException();
//进一步验证输出
}
//问题1.如何在此处正确指定参数?
公共静态无效测试实现(MyInterface impl){
//问题2.如何避免编译器对下面的未检查强制转换发出警告?
//如果impl属于上述MyInterface类型,则不起作用
makeTest(新TestClass1(),impl);
makeTest(新测试类别2(1,“ABC”),impl;
//难看的类型转换。编译器抱怨。
makeTest(新TestClass1(),(MyInterface)impl);
makeTest(新的TestClass2(1,“ABC”),(MyInterface)impl);
}
公共静态void main(字符串[]args){
//问题3.如何在此处传递接口参数?
//可以工作,但会发出有关原始类型的编译器警告
测试实现(新MyClass());
测试实现(新的MyInterface(){
@凌驾
公共对象方法(对象输入){
返回null;//无论什么
}
});
//看起来很丑
测试实现(新MyClass());
测试实现(新的MyInterface(){
@凌驾
公共对象方法(对象输入){
返回null;
}
});
/*菱形运算符仅出现在Java 7中,
*而泛型是在Java5中引入的。
*在2004年到2011年间,解决这个问题的推荐方法是什么?
*除此之外,这不适用于匿名类。
*/
测试实现(新MyClass());
testImplementation(新的MyInterface(){//不起作用
@凌驾
公共对象方法(对象输入){
返回null;
}
});
testImplementation(x->x);//Lambda表达式仅适用于简单情况
}
}
问题是,由于从泛型接口转换到其具体版本(我需要使用具体类
TestClass1
TestClass2
来代替泛型类型变量
T
),编译器会发出一系列错误和警告。是否有可能完全避免这些警告?如果没有(即,如果它们只能被抑制),是否存在由此产生的陷阱

<T> void makeTest(T testObject, Test.MyInterface<T> impl)
这是一个矛盾。在第一种情况下,T将是
TestClass1
,在第二种情况下,T将是
TestClass2
。如果要使用
Test.MyInterface
的通用版本,则没有任何类型可能满足此要求。你只是因为使用了原始类型才得以逃脱。它不能同时是
Test.MyInterface
Test.MyInterface

您需要摆脱
testImplementation
方法并停止使用原始类型。主方法的第一部分可能如下所示:

public static void main(String[] args) {

    makeTest(new Test.TestClass1(), new Test.MyClass<>());
    makeTest(new Test.TestClass2(1, "ABC"), new Test.MyClass<>());
publicstaticvoidmain(字符串[]args){
makeTest(new Test.TestClass1(),new Test.MyClass());
makeTest(new Test.TestClass2(1,“ABC”),new Test.MyClass();

我就是这样解决的

/* This utility method bears the brunt.
 * It shows that the cast is safe for this particular interface.
 * It is recommended to explain why. Example is given below. */
@SuppressWarnings("unchecked")
public static <T> MyInterface<T> reify(MyInterface<?> impl) {
    /* Safe because instances of MyInterface<T> doesn't suppose to hold
     * objects of type T (directly or indirectly) between invocations
     * of its methods. */
    return (MyInterface<T>) impl;
}

// Use a wildcard type in the signature
public static void testImplementation(MyInterface<?> impl) {
    // No warnings now
    makeTest(new TestClass1(), reify(impl));
    makeTest(new TestClass2(1, "ABC"), reify(impl));
}

public static void main(String[] args) {
    // Use the diamond operator for ordinary classes
    testImplementation(new MyClass<>());
    // Use lambda expressions when possible
    testImplementation(x -> x);
    /* Anonymous classes still require explicit type
    (Object in this case, Bound when the type variable is bounded
    at the interface definition: MyInterface<T extends Bound> */
    testImplementation(new MyInterface<Object>() {
        @Override
        public Object method(Object input) {
            return input;
        }
    });
}
/*这种实用方法首当其冲。
*它表明,对于这个特定的接口,强制转换是安全的。
*建议解释原因。下面给出了示例*/
@抑制警告(“未选中”)
公共静态MyInterface具体化(MyInterface impl){
/*安全,因为MyInterface的实例不应该保持
*调用之间T类型的对象(直接或间接)
*它的方法有很多*/
返回(MyInterface)impl;
}
//在签名中使用通配符类型
公共静态无效测试实现(MyInterface impl){
//现在没有警告
makeTest(newtestclass1(),具体化(impl));
makeTest(新的TestClass2(1,“ABC”),具体化(impl));
}
公共静态void main(字符串[]args){
//对普通类使用菱形运算符
测试实现(新MyClass());
//尽可能使用lambda表达式
测试实施(x->x);
/*匿名类仍然需要显式类型
(在本例中为对象,当类型变量有界时为有界。)
在接口定义处:MyInterface*/
测试实现(新的MyInterface(){
@凌驾
公共对象方法(对象输入){
返回输入;
}
});
}
仍然需要一个
@SuppressWarnings
,但将所有不安全操作集中在一个地方,以便解释为什么抑制是安全的


如果有人有更好的解决方案,请告诉我。

Java中的泛型永远不会具体化。你是什么意思?@Michael我的意思是从
T
转换到
TestClass1
TestClass2
中的
testImplementation()
。如果具体化在这里是一个错误的术语,请纠正我。方法
testImplementation()
是不可避免的,因为它为一个特定的
MyInterface
实现组合了一系列测试,并在最后输出最终结果。如果我需要为10个不同的实现执行10个测试,该怎么办?将100个
makeTest()
调用插入
main()
?我提到过使用
/* This utility method bears the brunt.
 * It shows that the cast is safe for this particular interface.
 * It is recommended to explain why. Example is given below. */
@SuppressWarnings("unchecked")
public static <T> MyInterface<T> reify(MyInterface<?> impl) {
    /* Safe because instances of MyInterface<T> doesn't suppose to hold
     * objects of type T (directly or indirectly) between invocations
     * of its methods. */
    return (MyInterface<T>) impl;
}

// Use a wildcard type in the signature
public static void testImplementation(MyInterface<?> impl) {
    // No warnings now
    makeTest(new TestClass1(), reify(impl));
    makeTest(new TestClass2(1, "ABC"), reify(impl));
}

public static void main(String[] args) {
    // Use the diamond operator for ordinary classes
    testImplementation(new MyClass<>());
    // Use lambda expressions when possible
    testImplementation(x -> x);
    /* Anonymous classes still require explicit type
    (Object in this case, Bound when the type variable is bounded
    at the interface definition: MyInterface<T extends Bound> */
    testImplementation(new MyInterface<Object>() {
        @Override
        public Object method(Object input) {
            return input;
        }
    });
}