簡體   English   中英

Java CRTP和通配符:代碼在Eclipse中編譯,但不是`javac`

[英]Java CRTP and Wildcards: Code compiles in Eclipse but not `javac`

對不起,標題含糊不清。 我有這段代碼編譯Eclipse Juno(4.2)但不是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
    }
}

錯誤是:

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

所以問題是:

  1. 這是一個javac bug還是Eclipse bug?

  2. 有沒有辦法在javac上進行javac ,而不更改v方法的簽名(即保留通配符)?

    我知道將它更改為<T extends N<T>> void v(final R<T> r)確實使它編譯,但我想知道是否有辦法首先避免這種情況。 此外,方法p不能改變為<T extends N<?>> void p(final T n)因為內容具有需要精確約束T extends N<T>

通配符的局限性在於它們會破壞類型參數允許的T extends X<T>類的遞歸表達式。 根據以下內容,我們知道您要做的是安全的:

  1. roT型(由R聲明),它是或延伸N<T>
  2. 方法p采用類型為T的參數(由p聲明),它也是或者擴展N<T>
  3. 因此,即使r被輸入為R<?> ,理論上呼叫p(ro)應該是合法的。

這可能是eclipse編譯器的推理(已知對javac沒有的泛型的某些細微差別做出正確的限制)。

假設您想使用javac進行編譯並且不能像您提到的那樣更改v的簽名,那么您可以做的最好的事情就是使用原始類型,它“選擇”泛型類型檢查:

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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM