泛型和未经检查的转换
Generics and unchecked cast
我知道这个问题被问了很多次,但无论如何我找不到可以应用于我的代码的东西。也许是因为我没有完全理解一切。我只想避免 @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 方法可以 return Book 或 SearchableBook 避免使用两个非常相似的方法。
我尝试将类型作为参数发送给执行类似操作的方法,但我仍然收到相同的警告。我仍然需要 return 通用类型,所以我肯定有同样的问题 :
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
的资源发生了什么?我说的是特定于可搜索书籍(MyBook 包装器)的搜索功能 => findSentence()
的实现所使用的资源。它们是否仅在我的 OpenBook
方法中使用并且 GC 之后清除它们? .其实它看起来很简单,我不明白为什么我没有早点考虑...
但是,界面的目标是什么?因为显然我真的不需要它,因为 MyBook class 中会有几种方法并且没有一个是强制性的,所以不需要放入接口。希望我清楚。
使其成为受检异常:void f() throws IllegalArgumentExceprion;
如果你这样定义会怎么样:
public static <T extends Book> T openBook(String ebookFilePath, boolean searchable)
更新:
创建一个包含 Book
作为字段的包装器 MyBook
。然后创建一个接口Searchable
并在MyBook
中实现它。然后你可以删除通用的:
public static MyBook openBook(String ebookFilePath, boolean searchable)
为字段 Book
创建 getter 和 setter。
您是否考虑过创建接口而不是使用泛型?这样,您的 Book 或 SearchableBook 都可以实现它,并且您的转换不会有问题。
编辑:
实际上根本没有使用泛型的逻辑,您可以将泛型更改为这样的接口:public interface BookBehaviour { Object readEpub(FileInputStream fileInputStream); }
然后您的 class SearchableBook 应该实现 BookBehaviour 以及您的方法 readEpub(fileInputStream ) 应该 return BookBehaviour 类型。
我终于改变了我的架构。
我想使用 Epublib 中的 Ebook
class 并为其添加在书中搜索以查找包含特定单词的句子的功能,这就是我的目的我的 SearchableBook class.
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 class,但后来意识到我无法将 Book 转换为 SearchableBook,这对我的计划来说是个问题。所以我尝试了我在本主题中解释的另一种方法。创建一个不扩展 Book 但将 Book 作为 属性 和 BookHelper class 的 SearchableBook class 以避免复制:
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();
}
}
为了能够将此代码用于 Book
和 SearchableBook
class 我尝试(如我的问题中所述)在我的 BookHelper class 中执行此操作:
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
class 中实现这个读取方法,需要为我不可搜索的书添加另一个 class 才能在它...所以我回到了我的第一个问题,复制。
最后我又回到了一个更简单的方法。不再有继承、接口、泛型或反射...只是创建了一个 BookHelper
class 接收 Book
作为参数并实现搜索功能。然后我可以实例化两本书,一本将使用我的 BookHelper
class 而另一本不用。这个 BookHelper class 也将包含一个方法来打开这本书并避免复制 InputStream
代码。
我只是想使用这些更复杂的东西,因为我看到每个人都在他们的项目中使用...但我意识到我应该继续不用,因为即使我开始理解这些概念并阅读大量相关内容,我也从来没有在我的项目中确实需要这些东西,就像在这个特别的项目中一样。
无论如何,如果您有更好的建议,那么欢迎您对这个问题有更好的回答。
我知道这个问题被问了很多次,但无论如何我找不到可以应用于我的代码的东西。也许是因为我没有完全理解一切。我只想避免 @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 方法可以 return Book 或 SearchableBook 避免使用两个非常相似的方法。
我尝试将类型作为参数发送给执行类似操作的方法,但我仍然收到相同的警告。我仍然需要 return 通用类型,所以我肯定有同样的问题 :
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
的资源发生了什么?我说的是特定于可搜索书籍(MyBook 包装器)的搜索功能 => findSentence()
的实现所使用的资源。它们是否仅在我的 OpenBook
方法中使用并且 GC 之后清除它们? .其实它看起来很简单,我不明白为什么我没有早点考虑...
但是,界面的目标是什么?因为显然我真的不需要它,因为 MyBook class 中会有几种方法并且没有一个是强制性的,所以不需要放入接口。希望我清楚。
使其成为受检异常:void f() throws IllegalArgumentExceprion;
如果你这样定义会怎么样:
public static <T extends Book> T openBook(String ebookFilePath, boolean searchable)
更新:
创建一个包含 Book
作为字段的包装器 MyBook
。然后创建一个接口Searchable
并在MyBook
中实现它。然后你可以删除通用的:
public static MyBook openBook(String ebookFilePath, boolean searchable)
为字段 Book
创建 getter 和 setter。
您是否考虑过创建接口而不是使用泛型?这样,您的 Book 或 SearchableBook 都可以实现它,并且您的转换不会有问题。
编辑:
实际上根本没有使用泛型的逻辑,您可以将泛型更改为这样的接口:public interface BookBehaviour { Object readEpub(FileInputStream fileInputStream); }
然后您的 class SearchableBook 应该实现 BookBehaviour 以及您的方法 readEpub(fileInputStream ) 应该 return BookBehaviour 类型。
我终于改变了我的架构。
我想使用 Epublib 中的 Ebook
class 并为其添加在书中搜索以查找包含特定单词的句子的功能,这就是我的目的我的 SearchableBook class.
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 class,但后来意识到我无法将 Book 转换为 SearchableBook,这对我的计划来说是个问题。所以我尝试了我在本主题中解释的另一种方法。创建一个不扩展 Book 但将 Book 作为 属性 和 BookHelper class 的 SearchableBook class 以避免复制:
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();
}
}
为了能够将此代码用于 Book
和 SearchableBook
class 我尝试(如我的问题中所述)在我的 BookHelper class 中执行此操作:
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
class 中实现这个读取方法,需要为我不可搜索的书添加另一个 class 才能在它...所以我回到了我的第一个问题,复制。
最后我又回到了一个更简单的方法。不再有继承、接口、泛型或反射...只是创建了一个 BookHelper
class 接收 Book
作为参数并实现搜索功能。然后我可以实例化两本书,一本将使用我的 BookHelper
class 而另一本不用。这个 BookHelper class 也将包含一个方法来打开这本书并避免复制 InputStream
代码。
我只是想使用这些更复杂的东西,因为我看到每个人都在他们的项目中使用...但我意识到我应该继续不用,因为即使我开始理解这些概念并阅读大量相关内容,我也从来没有在我的项目中确实需要这些东西,就像在这个特别的项目中一样。
无论如何,如果您有更好的建议,那么欢迎您对这个问题有更好的回答。