Java 将整数列表赋给字符串列表
我当时正在学习Java中的泛型,我接近一段非常有趣的代码。我知道在Java中,将一种类型的列表添加到另一种类型是非法的Java 将整数列表赋给字符串列表,java,generics,generic-method,Java,Generics,Generic Method,我当时正在学习Java中的泛型,我接近一段非常有趣的代码。我知道在Java中,将一种类型的列表添加到另一种类型是非法的 List<Integer> integerList = new ArrayList<Integer>(); List<String> stringList=integerList; List integerList=new ArrayList(); List stringList=整数列表; 所以在第二行我得到了一个编译时错误。 但是如果
List<Integer> integerList = new ArrayList<Integer>();
List<String> stringList=integerList;
List integerList=new ArrayList();
List stringList=整数列表;
所以在第二行我得到了一个编译时错误。
但是如果我在这样的类中创建一个泛型方法
class GenericClass <E>{
void genericFunction(List<String> stringList) {
stringList.add("foo");
}
// some other code
}
class泛型类{
void genericFunction(列表stringList){
字符串列表。添加(“foo”);
}
//其他代码
}
在main类中,调用带有整数列表的方法,我没有得到任何错误
public class Main {
public static void main(String args[]) {
GenericClass genericClass=new GenericClass();
List<Integer> integerList= new ArrayList<Integer>();
integerList.add(100);
genericClass.genericFunction(integerList);
System.out.println(integerList.get(0));
System.out.println(integerList.get(1));
}
}
公共类主{
公共静态void main(字符串参数[]){
GenericClass GenericClass=新的GenericClass();
List integerList=new ArrayList();
整数列表。添加(100);
genericClass.genericFunction(整数列表);
System.out.println(integerList.get(0));
System.out.println(integerList.get(1));
}
}
输出100
福
为什么我没有收到任何错误?您没有收到任何编译时错误,因为以原始方式使用
GenericClass
:
GenericClass GenericClass=新的GenericClass()代码>,
实际上,您是在告诉编译器禁用泛型类型检查,因为您不在乎
因此:
void-genericsfunction(List-stringList)
变成
void genericFunction(List stringList)
用于编译器
您可以尝试以下操作:GenericClass GenericClass
,您会立即注意到编译器意识到泛型的错误使用,并显示错误:
类型GenericClass中的方法genericFunction(List)不适用于参数(List)
此外,如果尝试在运行时获取第二位置对象的类:
System.out.println(integerList.get(1).getClass());
,您将得到一个错误:
java.lang.ClassCastException:java.lang.String不能强制转换为java.lang.Integer
您已经混合了泛型。它可以很好地编译,但在运行时可能会失败,因为通用信息在运行时丢失
应使用Generic在编译时跟踪此类错误
最好详细解释一下
警告:类型安全:方法泛型函数(列表)
属于原始类型泛型类
。对泛型类型泛型类的引用应为
参数化
如果有两个方法具有相同的名称和不同的泛型列表类型,则会导致编译时错误。如果方法参数可用下面的示例代码证明,编译器无法解析泛型类型
示例代码:(编译器错误-不是有效的重载方法)
void genericFunction(List stringList){…}
void genericFunction(List stringList){…}
进行一些更改并重试:
class GenericClass <E>{
void genericFunction(List<E> stringList) {
...
}
// some other code
}
...
GenericClass<String> genericClass=new GenericClass<String>(); // Genreric object
List<Integer> integerList= new ArrayList<Integer>();
integerList.add(100);
genericClass.genericFunction(integerList); // compile time error
class泛型类{
void genericFunction(列表stringList){
...
}
//其他代码
}
...
GenericClass GenericClass=新的GenericClass();//遗传客体
List integerList=new ArrayList();
整数列表。添加(100);
genericClass.genericFunction(整数列表);//编译时错误
以这种方式创建方法
class GenericClass<E> {
private List<E> list = new ArrayList<E>();
public void addAll(List<E> newList) {
list.addAll(newList);
}
public void add(E e) {
list.add(e);
}
public E get(int index) {
return list.get(index);
}
// some other code
}
class泛型类{
私有列表=新的ArrayList();
公共void addAll(列表newList){
list.addAll(newList);
}
公共空间添加(E){
列表.添加(e);
}
公共E-get(int索引){
返回列表。获取(索引);
}
//其他代码
}
添加到其他答案中
事实上,您将原始(未参数化)类型与参数化类型混合在一起,这会导致类型丢失,并且在类型安全检查不允许时,会将一个显然正确的参数传递给genericFunction
问题仍然是为什么列表
类型在未经参数化的泛型类
对象中丢失。编译器在您的情况下“禁用”类型检查的原因是类型擦除机制,即(简单地说)您的原始对象属于具有以下内容的类:
class GenericClass {
void genericFunction(List stringList) {
stringList.add("foo");
}
// some other code
}
正如您所看到的,它不会对正在传递的列表的内容进行任何类型检查(它会到处擦除类型参数)。更重要的是,类型擦除还从integerList
变量中擦除参数化类型,这使它完全适合作为genericFunction
方法的参数
因此,正如其他人所指出的,最好帮助Java保持其安全类型检查机制的完整性:
GenericClass<?> genericClass=new GenericClass<Integer>();
List<Integer> integerList= new ArrayList<Integer>();
integerList.add(100);
// no-no here
genericClass.genericFunction(integerList);
System.out.println(integerList.get(0));
System.out.println(integerList.get(1));
GenericClass GenericClass=新的GenericClass();
List integerList=new ArrayList();
整数列表。添加(100);
//这里没有
genericClass.genericFunction(整数列表);
System.out.println(integerList.get(0));
System.out.println(integerList.get(1));
但是,如果你这样做了,编译器会完成它的工作,并向你发射火箭筒
阅读有关类型擦除的更多信息。这是一个很好的特性,它允许进行泛型类型检查,同时仍然保持与前泛型Java版本的向后兼容性。这种情况发生了,因为(对我来说相当令人惊讶)您已经关闭了整个泛型类的泛型类型检查
您需要知道,首先,您正在构造一个没有类型参数的泛型类:
GenericClass genericClass = new GenericClass();
显然,正因为如此,您的以下代码:
class GenericClass<E> {
void genericFunction(List<String> stringList) {
stringList.add("foo");
}
// some other code
}
请注意,List
也变成了原始类型,这让我相当惊讶
您可以在这里找到完整答案,参考Jon Skeet解释的JLS:
我认为发生这种情况是公平的(尽管不是您所期望的),因为如果您决定使用原始类型,则假定您使用的是Java4或更低版本,并且无论哪种方式都无法访问泛型,因此它可能是w
class GenericClass<E> {
void genericFunction(List<String> stringList) {
stringList.add("foo");
}
// some other code
}
class GenericClass {
void genericFunction(List stringList) {
stringList.add("foo");
}
// some other code
}
class GenericClass <E>{
void genericFunction(List<String> stringList) {
stringList.add("foo");
}
// some other code
}