泛型和未经检查的演员

时间:2017-01-17 11:34:47

标签: android generics casting warnings

我知道这个问题被问了很多时间,但无论如何我找不到可以应用于我的代码的东西。也许是因为我没有完全理解一切。我只想避免@SuppressWarnings("unchecked")解决方案。所以为我的代码找到一个新的架构。

当我尝试转换为通用类型时,我在此行有警告Unchecked cast:com.example.reader.models.SearchableBook to T(T)epubReader.readEpub(fileInputStream)

public class BookHelper {
   public static <T> T openBook(String ebookFilePath, boolean searchable) {
        T book = null;
        EpubReader epubReader = new EpubReader();
        FileInputStream fileInputStream = null;

        try {
            fileInputStream = new FileInputStream(ebookFilePath);
            book = searchable ? (T)new SearchableBook(epubReader.readEpub(fileInputStream)) : (T)epubReader.readEpub(fileInputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return book;
    }
}

我使用泛型,因为我希望这个BookHelper方法可以返回Book或SearchableBook,避免使用两种非常相似的方法。

我尝试将类型作为参数发送到执行此类操作的方法,但我仍然有相同的警告。我仍然需要返回一个泛型类型,所以我确实遇到了同样的问题:

public static <T> T openBook(String ebookFilePath, boolean searchable, Type t) {
    T book = null;
    EpubReader epubReader = new EpubReader();
    FileInputStream fileInputStream = null;

    try {
        fileInputStream = new FileInputStream(ebookFilePath);
        if(t instanceof Book) {
            book = (T)epubReader.readEpub(fileInputStream);
        } else ...

在最后一种情况下,它并不是不安全所以我可以使用SuppressWarnings,但我想以正确的方式做到这一点......我想知道在这种情况下人们通常如何做。我想最好的方法是不要复制我的代码以避免这个警告......

更新1

现在我有了可搜索的界面:

public interface Searchable {

    String findSentence(String words);
}

实现此接口的包装器MyBook:

public class MyBook implements Searchable  {
    private Book mBook;

    public MyBook(Book book) {
        this.setBook(book);
    }

    public Book getBook() {
        return mBook;
    }

    public void setBook(Book book) {
        mBook = book;
    }

    @Override
    public String findSentence(String words) {
        return null;
    }
}

我的openBook(String ebookFilePath, boolean searchable)方法:

public static MyBook openBook(String ebookFilePath, boolean searchable) {
    MyBook book = null;
    EpubReader epubReader = new EpubReader();
    FileInputStream fileInputStream = null;

    try {
        fileInputStream = new FileInputStream(ebookFilePath);
        book = new MyBook(epubReader.readEpub(fileInputStream));

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return book;
}

在MainActivity中:

protected void onCreate(Bundle savedInstanceState) {  
...  
        MyBook searchBook = BookHelper.openBook(BOOK0_PATH, true);
        Book book = BookHelper.openBook(BOOK1_PATH,false).getBook();
...    
}

它可以工作,没有代码复制但是。如果我想实例化一本书,我只需实例化包装并调用getter getBook()。但是,那些用于实现MyBook Book的资源发生了什么?findSentence()我不需要这些资源?我在谈论搜索功能实现所使用的资源=&gt; OpenBook特定于可搜索的书(MyBook包装器)。它们是仅在我的{{1}}方法中使用,GC之后是否清除它们? 。事实上,它看起来很简单,我不明白为什么我之前没有想到它......

然后,界面的目标是什么?因为很明显我并不需要它,因为MyBook类中会有多个方法,没有一个是强制性的,所以不需要放入接口。希望我很清楚。

4 个答案:

答案 0 :(得分:1)

如果你定义这样的东西怎么样:

public static <T extends Book> T openBook(String ebookFilePath, boolean searchable)

<强>更新

创建一个包含MyBook的包装器Book作为字段。然后创建一个接口Searchable并在MyBook中实现它。然后你可以删除通用:

public static MyBook openBook(String ebookFilePath, boolean searchable)

为字段Book创建getter和setter。

答案 1 :(得分:0)

使其成为检查异常:void f()抛出IllegalArgumentExceprion;

答案 2 :(得分:0)

我终于改变了我的架构。

我想使用Epublib中的这个Ebook类,并添加了在书中搜索以查找包含特定单词的句子的功能,这是我的SearchableBook类的目的。

import nl.siegmann.epublib.domain.Book;

public class SearchableBook {
    private Book mBook;

    // Find a sentence containing the words in parameters
    public Sentence findSentence(String[] wordsToFind) { ... }

    ...
}

首先,我尝试扩展Epublib Book课程但后来意识到我无法将书籍投入到SearchableBook中,这对我的计划来说是一个问题。所以我尝试了我在本主题中解释的其他方法。创建一个不扩展Book的SearchableBook类,但将Book作为属性和BookHelper类来避免复制:

EpubReader epubReader = new EpubReader();
FileInputStream fileInputStream = null;

try {
    fileInputStream = new FileInputStream(ebookFilePath);
    book = epubReader.readEpub(fileInputStream);
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        fileInputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

为了能够将此代码用于BookSearchableBook类,我尝试(如我的问题所述)在我的BookHelper类中执行此操作:

 public static <T> T openBook(String ebookFilePath, boolean searchable) throws IllegalArgumentException {
        T book = null;
        EpubReader epubReader = new EpubReader();
        FileInputStream fileInputStream = null;

        try {
            fileInputStream = new FileInputStream(ebookFilePath);
            book = searchable ? (T)new SearchableBook(epubReader.readEpub(fileInputStream)) : (T)epubReader.readEpub(fileInputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return book;
    }

但得到了未经检查的演员问题。

然后我尝试使用Interface

public interface BookBehaviour { Object read(String ebookFilePath); }

但是后来我必须在我的SearchableBook类中实现这个read方法,需要为我不可搜索的Book添加另一个类,以便能够在其中实现read方法...所以我回到了我的第一个问题,复制。

最后我回到了一个更简单的方法。不再有继承,接口,泛型或反射......只是创建了一个BookHelper类,它接收Book作为参数并实现搜索功能。然后我可以实现两本书,一个将使用我的BookHelper类而另一个不会。此BookHelper类将包含一个打开书籍的方法,并避免复制InputStream代码。

我只是想使用这些更复杂的东西,因为我看到每个人都在他们的项目中使用......但只是意识到我应该继续这样做,因为即使我开始理解这些概念并阅读大量内容我也从未真正需要这些东西在我的项目中,就像在这个特定的那个。

无论如何,如果你有更好的主张,那么对这个问题有更好的答案,欢迎你。

答案 3 :(得分:-1)

您是否考虑过创建接口而不是使用泛型?通过这种方式,您的Book或SearchableBook都可以实现它,并且您的演员阵容也不会成为问题。

编辑:

实际上根本没有使用泛型的逻辑,你可以将你的泛型更改为这样的界面:public interface BookBehaviour { Object readEpub(FileInputStream fileInputStream); }那么你的类SearchableBook应该实现BookBehaviour,你的方法readEpub(fileInputStream)应该返回BookBehaviour类型