簡體   English   中英

Java泛型和varargs

[英]Java generics and varargs

我想用泛型和varargs實現一個函數。

public class Question {
    public static <A> void doNastyThingsToClasses(Class<A> parent, Class<? extends A>... classes) {
        /*** something here ***/
    }
    public static class NotQuestion {
    }
    public static class SomeQuestion extends Question {
    }
    public static void main(String[] args) {
        doNastyThingsToClasses(Object.class, Question.class, SomeQuestion.class); // OK
        doNastyThingsToClasses(Question.class, SomeQuestion.class); // OK
        doNastyThingsToClasses(Question.class, Object.class, SomeQuestion.class); // compilation failure
    }
}

這里的目的是斷言傳遞給該函數的所有參數都是Class對象,擴展了作為第一個參數給出的Class。 因此,main方法的兩個第一行將編譯,第三行將生成錯誤。

Why I get "Type safety : A generic array of Class is created for a varargs parameter" message for the first two lines? 為什么我得到“類型安全:為varargs參數創建類的通用數組”消息前兩行?

我在這里錯過了什么嗎?

how to redesign it to prevent this warning from being shown on every line calling "doNastyThingsToClasses" function? 如何重新設計它以防止在每行調用“doNastyThingsToClasses”函數時顯示此警告? 我可以將其更改為“doNastyThingsToClasses(Class <A> parent,Class <?> ... classes)”並刪除警告,但這也會刪除編譯時類型檢查 - 如果我想要的話,那就太好了確保正確使用此功能。 更好的解決方案?

幾乎總是如此,Angelika Langer的Java泛型常見問題解答非常詳細地解釋了它 (滾動到“當我調用”varargs“方法時,為什么編譯器有時會發出未經檢查的警告?” - ID不能正常工作。)

基本上,你最終會以比正常情況更糟的方式丟失信息。 Java泛型中的另一個小痛點:(

Jon Skeet的答案(當然)是正確的; 我將通過指出你可以擺脫這個警告,用一個很大的'if'來擴展它。 如果您願意承諾使用Java 7構建項目,則可以避免此警告。

作為Project Coin的一部分,Bob Lee寫了一個提議 ,要求在方法聲明網站而不是使用網站上抑制此警告。

這個提議被JDK7接受了(雖然語法略有改變,但@SuppressWarnings("varargs") ); 如果您有好奇心,可以查看為JDK添加此支持的提交

對你來說不一定有用,但我想我會把它作為一個單獨的答案,以便它繼續為未來的讀者而生,他們可能很幸運地生活在后Java-7世界。

另外,現在可以使用Java 7的新@SafeVarargs注釋來抑制警告。

@SafeVarargs
public static <A> void func( Class<A> parent, Class<? extends A>... classes ) {
    // Do func...
}

我對這個問題的解決辦法是

  1. 創建一個Nastier類
  2. 從doNastyThingsToClasses中刪除....
  3. make doNastyThingsToClasses非靜態方法
  4. 簡而言之,就像這樣做
  5. 歸還這個
  6. 將重復args移動到類屬性

     class Nastier { private final Class<A> parent; public Nastier(Class<A> parent) { this.parent = parent; } public <A, C extends A> Nastier do(Class<? extends A> clazz) { System.out.println(clazz); return this; } } public static void main(String[] args) { Nastier nastier = new Nastier(Object.class); nastier.do(Question.class).do(SomeQuestion.class).do(NotQuestion.class); } 

我相信代碼看起來干凈,我很高興.... :)

好的,所以最后我最終扔掉了varargs:

public class Question {

    public static <A, C extends A> void doNastyThingsToClasses(Class<A> parent, List<Class<? extends A>> classes) {
        /******/
        for(Class<? extends A> clazz : classes) {
            System.out.println(clazz);
        }
    }

    public static class NotQuestion {
    }
    public static class SomeQuestion extends Question {
    }

    public static void main(String[] args) {

        ArrayList<Class<? extends Object>> classes = new ArrayList<Class<? extends Object>>();
        classes.add(Question.class);
        classes.add(SomeQuestion.class);
        classes.add(NotQuestion.class);
        doNastyThingsToClasses(Object.class, classes);

        ArrayList<Class<? extends Question>> clazzes = new ArrayList<Class<? extends Question>>();
        clazzes.add(Question.class);
        clazzes.add(SomeQuestion.class);
        clazzes.add(NotQuestion.class); // yes, this will _not_ compile
        doNastyThingsToClasses(Question.class, clazzes);

    }

}

唯一的缺陷是用於填充用於攜帶函數參數的集合的長代碼。

第二個參數Class<? extends A> Class<? extends A> ...必須擴展第一個參數所在的類(例如,參數1是一個Question所以第二個參數是擴展Question東西。

細分:
NastyThingsToClasses(Object.class, Question.class, SomeQuestion.class); // OK
一切都擴展了Object所以第二個參數是正確的。

NastyThingsToClasses(Question.class, SomeQuestion.class); // OK
SomeQuestion延伸Question ,這是公平的游戲。

NastyThingsToClasses(Question.class, Object.class, SomeQuestion.class);
Object不擴展Question因此錯誤。


希望這能把事情搞清楚。

-Brett

暫無
暫無

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

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