2012-02-14 36 views
1

我試圖清理一些遺留代碼,並有一些unchecked cast警告我正在努力擺脫。困難的未經檢查的投射警告

我已經將提供警告的代碼解壓縮到下面的可編譯程序中。請注意,我刪除了大部分代碼以使其更小,因此所有這些代碼都可能不完整。它編譯,但運行它不會做任何事情。

import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipException; 
import java.util.zip.ZipInputStream; 

public class GenericsTest { 

    public static void main(String[] args) throws IOException { 
     Reader reader = new Reader(); 
     List<String> stringEntries = reader.readAll(StringEntry.class); 
    } 

    public static class Reader { 

     public <T> ZipInputStream getInputStream(String fileName) throws ZipException, FileNotFoundException { 
      return new ZipInputStream(new FileInputStream(fileName));//_file.getInputStream(_paths.get(fileName)); 
     } 

     public <T, TEntry extends Entry<T>> List<T> readAll(Class<TEntry> type) throws IOException { 
      List<T> list = new ArrayList<T>(); 
      List<TEntry> entries = createEntries(type); 
      for (TEntry entry : entries) { 
       list.add(read(entry)); 
      } 
      return list; 
     } 

     public <T> T read(Entry<T> entry) throws IOException { 
      ZipInputStream is = null; 
      try { 
       //is = _archive.getInputStream(entry.getName()); 
       return entry.read(is); 
      } finally { 
       if (is != null) { 
        is.close(); 
       } 
      } 
     } 

     public <TEntry extends Entry> List<TEntry> createEntries(Class<TEntry> type) throws ZipException { 
      List<TEntry> entries = new ArrayList<TEntry>(); 
      List<String> paths = new ArrayList<String>();//getPaths(type); 
      for (String path : paths) { 
       entries.add(createEntry(type, path)); 
      } 
      return entries; 
     } 

     public <TEntry extends Entry> TEntry createEntry(Class<TEntry> type, String folder) { 
      if (StringEntry.class.equals(type)) { 
       return (TEntry) new StringEntry(folder); 
      } else if (IntegerEntry.class.equals(type)) { 
       return (TEntry) new IntegerEntry(folder); 
      } 
      throw new IllegalArgumentException("Unknown type: " + type); 
     } 
    } 

    public static abstract class Entry<T> extends ZipEntry { 

     private T _data; 

     public Entry(T data, String folder, String name) { 
      super(folder + "/" + name); 
      _data = data; 
     } 

     protected abstract T read(InputStream is) throws IOException; 
    }; 

    public static class StringEntry extends Entry<String> { 

     public StringEntry(String folder) { 
      super("Hallo world!", folder, "StringEntry"); 
     } 

     @Override 
     protected String read(InputStream is) throws IOException { 
      throw new UnsupportedOperationException("Not supported yet."); 
     } 
    }; 

    public static class IntegerEntry extends Entry<Integer> { 

     public IntegerEntry(String folder) { 
      super(42, folder, "IntegerEntry"); 
     } 

     @Override 
     protected Integer read(InputStream is) throws IOException { 
      throw new UnsupportedOperationException("Not supported yet."); 
     } 
    }; 
} 

編譯上述代碼給出以下警告

GenericsTest.java:57: warning: [unchecked] unchecked cast 
found: GenericsTest.StringEntry 
required: TEntry 
       return (TEntry) new StringEntry(folder); 
GenericsTest.java:59: warning: [unchecked] unchecked cast 
found: GenericsTest.IntegerEntry 
required: TEntry 
       return (TEntry) new IntegerEntry(folder); 
2 warnings 

更改

public <TEntry extends Entry> TEntry createEntry... 

public <TEntry extends Entry<T>> TEntry createEntry... 

給出一個編譯器錯誤(cannot find symbol: class T)。

我不想更改代碼太多,因爲它工作正常,所以我如何修復(而不是隱藏)代碼更改最少的警告?

回答

2

您已經傳遞了Class對象爲該方法只需使用Class.cast()

public <TEntry extends Entry<?>> TEntry createEntry(Class<TEntry> type, String folder) { 
    if (StringEntry.class.equals(type)) { 
     return type.cast(new StringEntry(folder)); 
    } else if (IntegerEntry.class.equals(type)) { 
     return type.cast(new IntegerEntry(folder)); 
    } 
    throw new IllegalArgumentException("Unknown type: " + type); 
} 

上述更改使您的代碼無需警告即可編譯。

此外,在getInputStream()的簽名中的<T>可能不是必需的。

+0

我沒有了解Class.cast()!每天學習新東西:)謝謝! – ughzan 2012-02-15 07:09:53

+0

@ughzan Class.cast()或多或少是如何擺脫未經檢查的強制轉換警告的主要方式。它的主要限制是你不能有'Entry '的類對象(相對於擴展它的'StringEntry'類),所以你不能投射它。 – millimoose 2012-02-15 18:24:09

2

如果您想要使用多個通用參數,您需要在參數列表中指定它。你可以試試這個嗎?

public <T, TEntry extends Entry<T>> TEntry createEntry(... 

UPDATE

我有一些時間玩這個,把那些漂亮的類對象使用:

public <T, TEntry extends Entry<T>> List<TEntry> createEntries(Class<TEntry> type) throws ZipException { 
     List<TEntry> entries = new ArrayList<TEntry>(); 
     List<String> paths = new ArrayList<String>();//getPaths(type); 
     for (String path : paths) { 
      entries.add(createEntry(type, path)); 
     } 
     return entries; 
    } 

    public <T, TEntry extends Entry<T>> TEntry createEntry(Class<TEntry> type, String folder) { 
     if (StringEntry.class.equals(type)) { 
      return type.cast(new StringEntry(folder)); 
     } else if (IntegerEntry.class.equals(type)) { 
      return type.cast(new IntegerEntry(folder)); 
     } 
     throw new IllegalArgumentException("Unknown type: " + type); 
    } 
} 
+0

你真的試過這個看看它是否會讓編譯器警告消失嗎? – millimoose 2012-02-14 15:09:06

+0

原始回答:不;更新的答案爲我編譯(JDK 1.6) – gpeche 2012-02-14 15:10:51

+0

更新中的'T'是多餘的,但這只是一個小問題。 – millimoose 2012-02-14 15:24:50

0

恕我直言,對遺留代碼,以使它通用友好的可相當的經驗,特別是如果你有大量代碼的基礎...因爲可能這個代碼已經部署,你會不會考慮迭代方法?

通過迭代方法我的意思是...獲取所有警告並使用@SuppressWarning消除它們,然後使用TODO註釋,隨着時間的推移,每次需要對代碼進行更改時,如果您偶然發現了一個TODO,只是改變它,然後...

我萬一說你只是遷移到Java 5的和有成千上萬的警告..

+0

'@ SuppressWarnings'應該是封裝良好的黑客的最後選擇,您知道這些黑客是正確的,最好有測試以確保它們保持正確,並且當您知道無法清除乾淨的警告時方式,或至少不是沒有更多的麻煩,而不是它的價值。它不是**你應該在你的代碼庫中大量散佈以免編譯器停止讓你感到內疚。 – millimoose 2012-02-14 15:08:23

+0

我完全同意你的看法......我只是在談論如果你正在通過一個遺留項目遷移到Java 5,有時候只是不能通過正確的泛型來支付......這對我來說是唯一的例外, @SuppressWarning可以接受 – 2012-02-14 15:13:59

+0

在這種情況下,我只是留下警告。 – millimoose 2012-02-14 15:20:04