泛型的声明:
interface List<T> 和 class GenTest<K,V>
其中,T、K、V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。
泛型的实例化:
一定要在类名后面指定类型参数的值(类型)。如:
List<String> strList = new ArrayList<String>();
Iterator<Customer> iterator = customers.iterator();
T只能是类,不能用基本数据类型填充。但可以使用包装类填充。
把一个集合中的内容限制为一个特定的数据类型,这就是泛型背后的核心思想。
注意点:
1、泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>
2、泛型类的构造器如下:public GenericClass(){}。而下面是错误的:public GenericClass<E>(){}
3、实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
4、泛型不同的引用不能相互赋值。
5、泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。经验:泛型要使用一路都用。要不用,一路都不要用。
6、如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
7、jdk1.7,泛型的简化操作:ArrayList<Fruit> flist = new ArrayList<>();
8、泛型的指定中不能使用基本数据类型,可以使用包装类替换。
9、在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型。因为静态结构早于实例化对象之前产生。
10、异常类不能是泛型的。
11、不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]; 参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。
12、父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
子类不保留父类的泛型:按需实现
没有类型 擦除
具体类型
子类保留父类的泛型:泛型子类
全部保留
部分保留
结论:子类必须是 "富二代",子类除了指定或保留父类的泛型,还可以增加自己的泛型。
T、E、K、V:
K、V:一般就是结合使用,键值对;
自定义的时候,使用T或E就行;
自定义泛型类:
自定义泛型接口:
自定义泛型方法:
方法,也可以被泛型化;不管此时定义在其中的类是不是泛型类,方法是否可以泛型和方法所处的类是否使用泛型没关系。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
泛型方法的格式:[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常;
泛型方法声明泛型时也可以指定上限;
// 当一个类中的某些内部结构(属性的类型、方法的入参类型、方法的返回值类型等)不能确定时,此时不确定的内部结构就可以使用泛型
public class Order<T> {
// 下面这两个属性类型确定
String orderName;
int orderId;
// 下面这个属性的类型不确定,此时就可以使用泛型
T orderT;
public Order(String orderName,int orderId,T orderT){
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
public T getOrderT(){
return orderT;
}
public void setOrderT(T orderT){
this.orderT = orderT;
}
@Override
public String toString() {
return "Order{" +
"orderName=‘" + orderName + ‘\‘‘ +
", orderId=" + orderId +
", orderT=" + orderT +
‘}‘;
}
}
==========================================================================
public class GenericTest {
@Test
public void test1() {
// 如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为 Object 类型
// 要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型
Order order = new Order();
order.setOrderT(123);
order.setOrderT("ABC");
// 建议:实例化时指明类的泛型
Order<String> order1 = new Order<String>("orderAA",1001,"order:AA");
order1.setOrderT("AA:hello");
// 下面就编译报错了
// order1.setOrderT(123);
}
}
// SubOrder 不是泛型类
public class SubOrder extends Order<Integer> {
}
=================================================================================
public class GenericTest {
@Test
public void test2() {
SubOrder sub1 = new SubOrder();
// 由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
sub1.setOrderT(1122);
// 下面编译报错
// sub1.setOrderT("1122");
}
}
// SubOrder1<T> 仍然是泛型类
// Order 后面如果加了 <T>,SubOrder1 后面也必须加,这是语法规定
public class SubOrder1<T> extends Order<T> {
}
===================================================================================
public class GenericTest {
@Test
public void test2() {
SubOrder1<String> sub1 = new SubOrder1<>();
sub1.setOrderT("order1...");
SubOrder1<Integer> sub2 = new SubOrder1<>();
sub2.setOrderT(1122);
}
}
public class GenericTest {
@Test
public void test3(){
ArrayList<String> list1 = null;
ArrayList<Integer> list2 = null;
// 泛型不同的引用不能相互赋值。
// 尽管在编译时 ArrayList<String> 和 ArrayList<Integer> 是两种类型,但是,在运行时只有一个 ArrayList 被加载到JVM中。
// list1 = list2;
}
}
// 当一个类中的某些内部结构(属性的类型、方法的入参类型、方法的返回值类型等)不能确定时,此时不确定的内部结构就可以使用泛型
public class Order<T> {
// 下面这两个属性类型确定
String orderName;
int orderId;
// 下面这个属性的类型不确定,此时就可以使用泛型
T orderT;
// 静态方法中不能使用类的泛型。
// 下面代码编译报错
public static void show(T orderT) {
System.out.println(orderT);
}
}
// 这样写可以
public class MyException<T> {
}
============================================================
// 异常类不能声明为泛型类
public class MyException<T> extends Exception {
}
=============================================================
public class Order<T> {
// 下面这两个属性类型确定
String orderName;
int orderId;
// 下面这个属性的类型不确定,此时就可以使用泛型
T orderT;
public void show() {
// 编译不通过
try{
}catch(T t){
}
}
}
public class Order<T> {
// 下面这两个属性类型确定
String orderName;
int orderId;
// 下面这个属性的类型不确定,此时就可以使用泛型
T orderT;
public Order(){
// 编译不通过
// T 只是一个变量,一个参数;只有当存在一个类且类的名字叫T的时候,下面的写法才正确
// T[] arr = new T[10];
// 编译通过
T[] arr = (T[]) new Object[10];
}
}
class Father<T1, T2> {
}
// 子类不保留父类的泛型
// 1、没有类型 擦除
class Son1 extends Father { // 等价于class Son extends Father<Object,Object>
}
// 2、具体类型
class Son2 extends Father<Integer, String> {
}
// 子类保留父类的泛型
// 1、全部保留
class Son3<T1, T2> extends Father<T1, T2> {
}
// 2、部分保留
class Son4<T2> extends Father<Integer, T2> {
}
=========================================================================
class Father<T1, T2> {
}
// 子类不保留父类的泛型
// 1、没有类型 擦除
class Son<A, B> extends Father { // 等价于 class Son extends Father<Object,Object>
}
// 2、具体类型
class Son2<A, B> extends Father<Integer, String> {
}
// 子类保留父类的泛型
// 1、全部保留
class Son3<T1, T2, A, B> extends Father<T1, T2> {
}
// 2、部分保留
class Son4<T2, A, B> extends Father<Integer, T2> {
}
public class Order<T> {
// 下面这两个属性类型确定
String orderName;
int orderId;
// 下面这个属性的类型不确定,此时就可以使用泛型
T orderT;
// 下面的这两个方法都不是泛型方法
public T getOrderT() {
return orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
// 泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
// 换句话说,泛型方法所属的类是不是泛型类都没有关系。
// 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
public static <E> List<E> copyFromArrayToList(E[] arr){
ArrayList<E> list = new ArrayList<>();
for(E e : arr){
list.add(e);
}
return list;
}
}
public class GenericTest {
// 测试泛型方法
@Test
public void test4() {
Order<String> order = new Order<>();
Integer[] arr = new Integer[]{1,2,3,4};
// 泛型方法在调用时,指明泛型参数的类型。
List<Integer> list = order.copyFromArrayToList(arr);
System.out.println(list);
}
}
原文:https://www.cnblogs.com/kehuaihan/p/13592431.html