Java泛型学习总结
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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<String> strings = new ArrayList<String>();
strings.add("a String");
String aString = strings.get(0);
以上这个 List 集合只能放⼊ String 对象,如果视图放⼊别的对象那么编译器会报错,让代码编写者必须进⾏处理,这就是额外的类型检查。
另外注意List 的 <> 尖括号⾥⾯只能是对象引⽤类型,不包括基本类型(可以使⽤对应包装类代替)。
Java 泛型从 Java 7 开始,编译器可以⾃动类型判断,可以省略构造器中的泛型,下⾯是⼀个Java 7 泛型例⼦:
List<String> strings = new ArrayList<>();
这也叫做菱形语法(<>),在上⾯的⽰例中,实例化 ArrayList 的时候,编译器根据前⾯ List 知道 new 的 ArrayList 泛型信息是 String。
foreach 循环可以很好地与泛型集合整合,如下:
List<String> strings = new ArrayList<>();
// 这⾥省略将 String 元素添加进集合的代码...
for(String aString : strings){
System.out.println(aString);
}
也可以使⽤泛型迭代器遍历集合,如下:
List<String> list = new ArrayList<String>;
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String aString = iterator.next();
}
注意,泛型类型检查仅在编译时存在。
在运⾏时,可以使⽤反射或者其他⽅式使字符串集合插⼊其他对象,但⼀般不会这样做。
当然泛型的⽤处不仅仅限于集合。
泛型类
从上⾯的内容中,我们已了解泛型的⼤概理念。
可以在⾃定义 Java 类上使⽤泛型,并不局限于 Java API 中的预定义类。
定义泛型类只需要在类名后紧跟尖括号,其中 T 是类型标识符,也可以是别的,⽐如 E 、V 等,如下例:
public class GenericFactory<T> {
Class theClass = null;
其中 Class.newInstance() ⽅法是反射知识的内容,这⾥只要知道此⽅法⽤于 theClass 类对象的创建就⾏。
是⼀个类型标记,表⽰这个泛型类在实例化时可以拥有的类型集。
下⾯是⼀个例⼦:
使⽤泛型,我们就不必转换从 factory.createInstance() ⽅法返回的对象,会⾃动返回 new GenericFactory 的 <> 尖括号中的类型对象。
泛型⽅法
⼀个泛型⽅法定义如下:
其中 T 是⽅法返回值, 放在⽅法返回值之前,是所有泛型⽅法必须有的类型参数声明,表⽰这是⼀个泛型⽅法,如果没有 只有 T ,那就不是泛型⽅法,⽽是泛型类的⼀个成员⽅法,就像上⾯泛型类定义的⽅法:
这不是⼀个泛型⽅法,⽽是 GenericFactory 泛型类的⼀个成员⽅法⽽已,泛型⽅法必须在⽅法返回值之前有似于 的标记。
注意在泛型⽅法中,参数有 2 个,第⼀个是 T 类型的参数,第⼆个是元素类型为 T 的 Collection 集合,编译器会根据实际参数来推断 T 为何种类型,如下这样是完全可⾏的:
如上,第⼀个参数为 String 类型,第⼆个是 List 类型,貌似两个 T 是不匹配的,但是这⾥编译器会⾃动将 String 转换为 Object 类型,并将 T 标识为Object 。
继承关系的泛型参数
定义如下类:
新建并初始化如下类对象:
因为 A 是 B 和 C 类的共同⽗类,那么 List public GenericFactory(Class theClass) {
this.theClass = theClass;
}
public T createInstance() throws Exception {
return (T) this.theClass.newInstance();
}
}
GenericFactory<MyClass> factory = new GenericFactory<MyClass>(MyClass.class);
MyClass myClassInstance = factory.createInstance();
GenericFactory<SomeObject> factory1 = new GenericFactory<SomeObject>(SomeObject.class);
SomeObject someObjectInstance = factory1.createInstance();
public static <T> T addAndReturn(T element, Collection<T> collection){
collection.add(element);
return element;
}
public T createInstance() throws Exception { ... }
String stringElement = "stringElement";
List<Object> objectList = new ArrayList<Object>();
Object theElement = addAndReturn(stringElement, objectList); public class A { }public class B extends A { }public class C extends A { }
List<A> listA = new ArrayList<A>();List<B> listB = new ArrayList<B>();。