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=整数列表; 所以在第二行我得到了一个编译时错误。 但是如果

我当时正在学习Java中的泛型,我接近一段非常有趣的代码。我知道在Java中,将一种类型的列表添加到另一种类型是非法的

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
}