Java 泛型学习总结
前言
Java 5 添加了泛型,提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,可以为以前处理通用对象的类和方法,指定具体的对象类型。听起来有点抽象,所以我们将马上看一些泛型用在集合上的例子:
泛型集合
先看一个没有泛型的集合例子:
List list = new ArrayList();
list.add(new Integer(2));
list.add("a String");
因为 List 可以添加任何对象,所以从 List 中取出的对象时,因为不确定(List不记住元素类型)当时候保存进 List 的元素类型,这个对象的类型只能是 Object ,还必须由程序编写者记住添加元素类型,然后取出时再进行强制类型转换就,如下:
Integer integer = (Integer) list.get(0);
String string = (String) list.get(1);
通常,我们只使用带有单一类型元素的集合,并且不希望其他类型的对象被添加到集合中,例如,只有 Integer 的 List ,不希望将 String 对象放进集合,并且也不想自己记住元素类型,并且强制类型转换还可能会出现错误。
使用 Generics(泛型)就可以设置集合的类型,以限制可以将哪种对象插入集合中。 这可以确保集合中的元素,都是同一种已知类型的,因此取出数据的时候就不必进行强制类型转换了,下面是一个 String 类型的 List 的使用例子:
List strings = new ArrayList();
strings.add("a String");
String aString = strings.get(0);
以上这个 List
Java 泛型从 Java 7 开始,编译器可以自动类型判断,可以省略构造器中的泛型,下面是一个Java 7 泛型例子:
List strings = new ArrayList<>();
这也叫做菱形语法(<>), 在上面的示例中,实例化 ArrayList 的时候,编译器根据前面 List
foreach 循环可以很好地与泛型集合整合,如下:
List strings = new ArrayList<>();
// 这里省略将 String 元素添加进集合的代码...
for(String aString : strings){
System.out.println(aString);
}
也可以使用泛型迭代器遍历集合,如下:
List list = new ArrayList;
Iterator iterator = list.iterator();
while(iterator.hasNext()){
String aString = iterator.next();
}
注意,泛型类型检查仅在编译时存在。在运行时,可以使用反射或者其他方式使字符串集合插入其他对象,但一般不会这样做。
当然泛型的用处不仅仅限于集合。
泛型类
从上面的内容中,我们已了解泛型的大概理念。
可以在自定义 Java 类上使用泛型,并不局限于 Java API 中的预定义类。定义泛型类只需要在类名后紧跟
public class GenericFactory {
Class theClass = null;
public GenericFactory(Class theClass) {
this.theClass = theClass;
}
public T createInstance() throws Exception {
return (T) this.theClass.newInstance();
}
}
其中 Class.newInstance() 方法是反射知识的内容,这里只要知道此方法用于 theClass 类对象的创建就行。
GenericFactory factory = new GenericFactory(MyClass.class);
MyClass myClassInstance = factory.createInstance();
GenericFactory factory1 = new GenericFactory(SomeObject.class);
SomeObject someObjectInstance = factory1.createInstance();
使用泛型,我们就不必转换从 factory.createInstance() 方法返回的对象,会自动返回 new GenericFactory
泛型方法
一个泛型方法定义如下:
public static T addAndReturn(T element, Collection collection){
collection.add(element);
return element;
}
其中 T 是方法返回值,
public T createInstance() throws Exception { ... }
这不是一个泛型方法,而是 GenericFactory
注意在泛型方法中,参数有 2 个,第一个是 T 类型的参数,第二个是元素类型为 T 的 Collection 集合,编译器会根据实际参数来推断 T 为何种类型 ,如下这样是完全可行的:
String stringElement = "stringElement";
List
如上,第一个参数为 String 类型,第二个是 List 定义如下类: 新建并初始化如下类对象: 因为 A 是 B 和 C 类的共同父类,那么 ListJava不能实现真正泛型的原因? - RednaxelaFX的回答 - 知乎 JDK 文档中经常能看到 T、K、V、E、N 等类型参数,实际上这些符号随意选择使用也是没问题的,甚至可以使用如 A、B 等,但建议和 JDK 文档风格保持一致,至少得让人容易理解。 T:type 在 Java 中不能创建一个确切泛型类型的数组,如下代码是不允许的: 将会报错:Error:(11, 27) java: 创建泛型数组。 但是使用通配符创建泛型数组是可以的,比如下面代码是被允许的: 为什么? 首先对于Java数组,数组必须明确知道内部元素的类型,而且编译器会”记住“这个类型,每次往数组里插入新元素都会进行类型检查,不匹配会抛出java.lang.ArrayStoreException错误。更多信息可参考此文↓ 本文参考:继承关系的泛型参数
public class A { }
public class B extends A { }
public class C extends A { }
List listA = new ArrayList();
List listB = new ArrayList();
其他
常见各符号的含义:
K:key
V:value
E:element
N:Number泛型数组
ListList<?>[] strLists = new ArrayList<?>[8];
Java 为什么不支持泛型数组-简书
菜鸟教程
Java Generics Tutorial