将整数列表分配到string列表中
我正在学Java的generics,我接近了一个非常有趣的代码。 我知道在Java中将一种types的列表添加到另一种types是非法的。
List<Integer> integerList = new ArrayList<Integer>(); List<String> stringList=integerList;
所以在第二行我得到一个编译时错误。
但是如果我在这样的类中创build一个generics方法,
class GenericClass <E>{ void genericFunction(List<String> stringList) { stringList.add("foo"); } // some other code }
而在主类调用与Integer列表的方法我没有得到任何错误。
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)); } }
产量
100
FOO
为什么我没有得到任何错误?
你有混合通用与原始types 。 它可以很好地编译,但是在运行时可能会失败,因为通用信息在运行时会丢失。
在编译时应该使用generics来追踪这些错误。
什么是原始types,为什么我们不应该使用它? 详细。
警告:types安全:方法genericFunction(List)
属于原始typesGenericClass
。 对genericsGenericClass<E>
引用应该被参数化。
如果你有两个具有不同GenerictypesList的相同名字的方法,那么它会导致编译时错误。 在下面的示例代码可以certificate的方法参数的情况下,编译器无法parsinggenericstypes。
示例代码:(编译器错误 – 不是有效的重载方法)
void genericFunction(List<String> stringList){...} void genericFunction(List<Integer> 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
以这种方式创build方法
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 }
您没有得到任何编译时错误,因为通过以原始方式使用GenericClass<E>
:
GenericClass genericClass = new GenericClass();
,
你实际上告诉编译器禁用genericstypes检查,因为你不在乎。
所以 :
void genericFunction(List<String> stringList)
变
编译器的void genericFunction(List stringList)
。
你可以尝试下面的代码: GenericClass<?> genericClass
,你会立刻注意到编译器意识到这个generics不好用,它会告诉你错误:
The method genericFunction(List<String>) in the type GenericClass<capture#1-of ?> is not applicable for the arguments (List<Integer>)
此外,如果您尝试在运行时获取第二个位置对象的类:
System.out.println(integerList.get(1).getClass());
,你会得到一个错误: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
。
发生这种情况,因为(相当令人惊讶的是我)你已经closures了整个 GenericClass
类的genericstypes检查。
你需要知道,你首先在这里构造一个没有types参数的generics类:
GenericClass genericClass = new GenericClass();
而且,由于这个原因,你的下面的代码是:
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 }
请注意, List
也成为一个原始types,这是我相当惊讶。
你可以在这里find完整的答案,参考Jon Skeet解释的JLS: https ://stackoverflow.com/a/662257/2057294。
我认为这是公平的(尽pipe不是你所期望的),因为如果你决定使用原始types,那么假定你正在使用Java 4或更低版本,并且根本不可能访问generics,所以它也可以不提供他们的方法,而不涉及被删除的类的genericstypes。
添加到其他答案。
事实上,你正在混合使用参数化types的原始(未参数化)types,这会导致types丢失,并且在types安全检查不应该允许的情况下将明显正确的parameter passing给genericFunction
。
问题仍然是为什么 List<String>
types在未参数化的GenericClass
对象中丢失。 在你的情况下,编译器“禁用”types检查的原因是types擦除机制,它说(简单来说)你的原始对象属于一个具有以下内容的类:
class GenericClass { void genericFunction(List stringList) { stringList.add("foo"); } // some other code }
正如你所看到的,不会对所传递的列表内容进行任何types的检查(它会擦除所有types的参数)。 更重要的是,types擦除也会从integerList
variables中擦除您的参数化types,这使得它完全适合您的genericFunction
方法的参数。
因此,正如其他人指出的那样,最好能帮助Java保持安全的types检查机制:
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));
但是如果你这样做了,那么编译器就会完成它的工作,然后把火箭筒放在你身上。
在这里阅读types擦除更多。 这是一个很好的function,允许进行genericstypes检查,同时仍然保持与预genericsJava版本的向后兼容性。
class GenericClass <E>{ void genericFunction(List<String> stringList) { stringList.add("foo"); } // some other code }
当你在类名后面写。它指定了types参数。它是一个通用的function。它引入了typesvariablesE,它可以在类中的任何地方使用。 typesvariables可以是您指定的任何非基本types:任何类types,任何接口types,任何数组types或甚至另一个typesvariables。