出现的缘由:想让一个类能够用于全部类型,可是咱们在之前定义的时候,只能定义一种类型,因而就出现了泛型。java
咱们能够看看 Java 定义的 List 接口的使用。dom
import java.util.ArrayList; import java.util.List; public class GenericTest { public static void main(String[] args) { // 指定类型 ,list 只能存储 String 元素,告诉 Java 这个 List 只能有 String 元素 List<String> strList = new ArrayList<>(); strList.add("str1"); strList.add("str2"); strList.add("str3"); strList.forEach(System.out::println); } }
上面的 List 的引用指向的是 ArrayList 对象,咱们看一下 ArrayList 中的 add 方法定义。code
看一下 ArrayList 的 add 方法对象
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
能够看到要添加的元素类型是 E,那么这个 E 来自哪里呢?咱们看一下 ArrayList 的定义:接口
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
咱们建立对象时是这样的:ci
List<String> strList = new ArrayList<>();
也就是说,这个 E 就是咱们在建立 ArrayList 对象时放入的类型,经过看 add 方法咱们发现,要添加的元素也必须是这个类型。element
固然别的类不必定是这样,要根据泛型的定义来判断使用的方式,具体状况,具体分析。rem
将类型定义在类后面的尖括号 ,能够定义多个。编译器
public class MyGenericType1<MyType1, MyType2> { private MyType1 type1; private MyType2 type2; }
其实泛型就是类型擦除,而后在调用的时候,帮咱们作强制类型转换。若是出现错误,报错信息会显示在调用的那一行。it
协变和逆变都是针对引用类型的,不能用于建立对象类型,在建立对象时必须指定一个明确类型。
List<? extends Person> persons = null;
这种形式就是协变,使用协变时,类必须是 ? extends
后面的类自己或其子类。
List<? super Student> person2s = null;
这种形式就是逆变,使用逆变时,类必须是? super
后面的类自己或其父类。
import java.util.ArrayList; import java.util.List; public class GenericTest { public static void main(String[] args) { // 指定类型 ,list 只能存储 String 元素,告诉 Java 这个 List 只能有 String 元素 // 协变:类必须是 ? extends 后面的类自己或其子类 List<? extends Person> persons = null; // 不能够加入(List并无记住是什么类型,须要指定明确的类型) // persons.add(new Person()); // persons.add(new Student()); persons = new ArrayList<Person>(); persons = new ArrayList<Student>(); // 逆变:类必须是 ? super 后面的类自己或者其父类类 List<? super Student> person2s = null; person2s = new ArrayList<Person>(); person2s = new ArrayList<Student>(); } }
写入使用逆变,读取使用协变。能够参考 Java 类库中的方法。
泛型最重要的就是这两点。