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; public GenericFactory(Class theClass) { this.theClass = theClass; } public T createInstance() throws Exception { return (T) this.theClass.newInstance(); } }

其中 Class.newInstance() 方法是反射知识的内容,这里只要知道此方法用于 theClass 类对象的创建就行。
是一个类型标记,表示这个泛型类在实例化时可以拥有的类型集。下面是一个例子:

GenericFactory<MyClass> factory = new GenericFactory<MyClass>(MyClass.class); MyClass myClassInstance = factory.createInstance(); GenericFactory<SomeObject> factory1 = new GenericFactory<SomeObject>(SomeObject.class); SomeObject someObjectInstance = factory1.createInstance();

使用泛型,我们就不必转换从 factory.createInstance() 方法返回的对象,会自动返回 new GenericFactory 的 <> 尖括号中的类型对象。

泛型方法

一个泛型方法定义如下:

public static <T> T addAndReturn(T element, Collection<T> collection){ collection.add(element); return element; }

其中 T 是方法返回值, 放在方法返回值之前,是所有泛型方法必须有的类型参数声明,表示这是一个泛型方法,如果没有 只有 T ,那就不是泛型方法,而是泛型类的一个成员方法,就像上面泛型类定义的方法:

public T createInstance() throws Exception { ... }

这不是一个泛型方法,而是 GenericFactory泛型类的一个成员方法而已,泛型方法必须在方法返回值之前有似于 的标记。

注意在泛型方法中,参数有 2 个,第一个是 T 类型的参数,第二个是元素类型为 T 的 Collection 集合,编译器会根据实际参数来推断 T 为何种类型 ,如下这样是完全可行的:

String stringElement = "stringElement"; List<Object> objectList = new ArrayList<Object>(); Object theElement = addAndReturn(stringElement, objectList);

如上,第一个参数为 String 类型,第二个是 List

继承关系的泛型参数

定义如下类:

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>();

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspysj.html