Java CRTP和通配符:代码在Eclipse中编译而不是“javac” [英] Java CRTP and Wildcards: Code compiles in Eclipse but not `javac`

查看:103
本文介绍了Java CRTP和通配符:代码在Eclipse中编译而不是“javac”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对不起,这个模糊的标题。我有这段代码编译在Eclipse Juno(4.2)而不是javac(1.7.0_09):

 包测试; 

public final class Test {
public static class N< T extends N< T> {}

public static class R< T extends N< T> {
public T o;
}

public< T extends N< T> void p(final T n){}

public void v(final R?r){
p(r.o); //< - javac在此行上失败
}
}

错误是:

 
Test.java:13:错误:类Test中的方法p不能应用于给定类型;
p(r.o);
^
需要:T
找到:N< CAP#1>
原因:推断类型不符合声明的绑定
推断:N
bound(s):N >
其中T是一个类型变量:
T扩展在方法< T>中声明的N < p(T)
其中CAP#1是新鲜的类型变量:
CAP#1从N的捕获中扩展N
1错误

所以问题是:


  1. 这是一个 javac 错误或Eclipse错误?


  2. 是否在 v 方法的签名(即保留通配符)的情况下,以任何方式在 javac 中进行编译?



    我知道将其更改为< T扩展N< T> void v(final R T r)确实使其编译,但是我想知道是否有办法避免这种情况。此外,方法 p 不能更改为< T extends N<?>> void p(final T n)因为内容具有需要确切约束的类型 T扩展N 通配符有限,因为它们打破递归表达式,如 T扩展X< ; T> 类型参数允许。我们知道您要做的是基于以下方面的安全:


    1. ro T (由 R 声明),它是或扩展 N <

    2. 方法 p 采用类型为 T (由 p 声明),它也是或扩展 N li>
    3. 所以即使 r 键入为 R<?> 理论上来说, p(ro)

    这可能是推理的eclipse编译器(已知对于某些特定细微差别, javac不)进行正确的配额。



    假设您要使用javac进行编译,并且无法像您所提到的那样更改 v 的签名,所以您最好的做法是诉诸使用原始类型,选择退出通用类型检查:

      publ ic void v(最终R' r){
    //必须安装javac - 这是可以的,因为[insert above reasoning]
    @SuppressWarnings(rawtypes)
    N nRaw = r.o;
    p(nRaw);
    }


    Sorry for the vague title. I have this piece of code which compiles on Eclipse Juno (4.2) but not javac (1.7.0_09):

    package test;
    
    public final class Test {
        public static class N<T extends N<T>> {}
    
        public static class R<T extends N<T>> {
            public T o;
        }
    
        public <T extends N<T>> void p(final T n) {}
    
        public void v(final R<?> r) {
            p(r.o);       // <-- javac fails on this line
        }
    }
    

    The error is:

    Test.java:13: error: method p in class Test cannot be applied to given types;
            p(r.o);
            ^
      required: T
      found: N<CAP#1>
      reason: inferred type does not conform to declared bound(s)
        inferred: N<CAP#1>
        bound(s): N<N<CAP#1>>
      where T is a type-variable:
        T extends N<T> declared in method <T>p(T)
      where CAP#1 is a fresh type-variable:
        CAP#1 extends N<CAP#1> from capture of ?
    1 error
    

    So the questions are:

    1. Is this a javac bug or Eclipse bug?

    2. Is there any way to make this compile on javac, without changing the signature of the v method (i.e. keep the wildcard)?

      I know changing it to <T extends N<T>> void v(final R<T> r) does make it compile, but I would like to know if there's way to avoid this first. Also, the method p cannot be changed to <T extends N<?>> void p(final T n) because the content have types which requires the exact constraint T extends N<T>.

    解决方案

    Wildcards are limited in that they break recursive expressions like T extends X<T> that type parameters allow. We know what you're trying to do is safe based on the following:

    1. r.o is of type T (declared by R), which is or extends N<T>.
    2. The method p takes an argument of type T (declared by p), which also is or extends N<T>.
    3. So even though r is typed as R<?>, a call p(r.o) should theoretically be legal.

    This is possibly the reasoning of the eclipse compiler (known to make correct allowances for certain nuances of generics where javac doesn't).

    Assuming you want to compile with javac and can't change the signature of v like you mentioned, the best you can do is resort to using a raw type, which "opts out" of generic type checking:

    public void v(final R<?> r) {
        //necessary to placate javac - this is okay because [insert above reasoning]
        @SuppressWarnings("rawtypes")
        N nRaw = r.o;
        p(nRaw);
    }
    

    这篇关于Java CRTP和通配符:代码在Eclipse中编译而不是“javac”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆