目录
介绍
优点
泛型类
语法定义
代码示例
泛型类注意事项
抽奖示例
泛型类派生子类
定义
代码示例
子类是泛型
子类不是泛型
泛型接口
定义
泛型方法
定义
代码示例
泛型方法与可变参数
泛型方法总结
编辑类型通配符
定义
代码示例
通配符的上限
定义
代码示例
通配符的下限
定义
代码示例
jdk中下限通配符的使用
类型擦除
泛型与数组
泛型与反射
定义
代码示例
介绍
JAVA推出泛型以前,程序员可以构建一个元素类型为Object的集合,该集合能够存储任意的数据类型对象,而在使用该集合的过程中,需要程序员明确知道存储每个元素的数据类型,否则很容易引发ClassCastException异常。
Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构。
泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数。
优点
类型安全
消除了强制类型的转换
泛型类
语法定义
代码示例
// <T> 泛型标识--类型形参 T创建对象的时候指定具体的数据类型
public class Generic<T> {//T 外部创建使用类的时候来指定 可以理解为 谁用谁定义private T key;public Generic() {}public Generic(T key) {this.key = key;}public T getKey() {return key;}public void setKey(T key) {this.key = key;}@Overridepublic String toString() {return "Generic{" +"key=" + key +'}';}
}
测试:
注意泛型类不支持基本数据类型 这点在编译时就会有报警提示
泛型类注意事项
抽奖示例
public class ProdocGetter<T> {Random random = new Random();//奖品private T product;//奖品池List<T> list = new ArrayList<>();//添加奖品public void addPro(T t){list.add(t);}//随机抽奖public T getProduct(){return list.get(random.nextInt(list.size()));}public static void main(String[] args) {//创建抽奖器对象 指定奖品类型(数据类型)ProdocGetter<String> stringProdocGetter = new ProdocGetter<>();String[] strings = {"苹果电脑","小米手机","奔驰汽车","迪迦奥特曼玩具"};//奖品池塞入奖品for (String pro : strings) {stringProdocGetter.addPro(pro);}//抽奖System.out.println("恭喜您,抽中了:"+stringProdocGetter.getProduct());System.out.println("分割线====================================");ProdocGetter<Integer> intProdocGetter = new ProdocGetter<>();Integer[] integers = {100,500,9000,16645,30458};//奖品池塞入奖品for (Integer pro : integers) {intProdocGetter.addPro(pro);}//抽奖System.out.println("恭喜您,抽中了:"+intProdocGetter.getProduct()+"元");}
}
测试:
泛型类派生子类
定义
代码示例
子类是泛型
父类泛型
public class Parent<E> {private E value;public E getValue() {return value;}public void setValue(E value) {this.value = value;}
}
子类泛型
//泛型类派生子类,子类也是泛型类,那么子类的泛型标识要和父类一致。
public class Child<T> extends Parent<T>{@Overridepublic T getValue() {return super.getValue();}public static void main(String[] args) {Child<String> child = new Child<>();child.setValue("我是一个字符串");System.out.println(child.getValue());}
}
测试:
注意此时的子类泛型是T,继承的父类也是T,而最原先定义的父类泛型是E
子类如果是泛型,那么必须指定父类泛型和子类是一致的
如果不一致:
子类不是泛型
//泛型类派生子类 如果子类不是泛型,那么父类需要明确指定数据类型 如果不指定那么数据类型则为Object
public class ChildSecond extends Parent<Integer>{@Overridepublic Integer getValue() {return super.getValue();}@Overridepublic void setValue(Integer value) {super.setValue(value);}public static void main(String[] args) {ChildSecond childSecond = new ChildSecond();childSecond.setValue(1000);System.out.println(childSecond.getValue());}
}
测试:
如果不明确指定父类的数据类型
泛型接口
定义
泛型接口的代码示例和泛型类派生子类如出一辙,不再代码示例
泛型方法
定义
代码示例
还是以之前的例子,但是这里需要多定义一个泛型方法
public class ProdocGetter<T> {Random random = new Random();//奖品private T product;//奖品池List<T> list = new ArrayList<>();//添加奖品public void addPro(T t){list.add(t);}//随机抽奖public T getProduct(){return list.get(random.nextInt(list.size()));}//定义泛型方法public <E> E getProduct(List<E> list){return list.get(random.nextInt(list.size()));}public static void main(String[] args) {ProdocGetter<Integer> prodocGetter = new ProdocGetter<>();List<String> strList = new ArrayList<>();strList.add("华为手机");strList.add("苹果手表");strList.add("空调");//泛型方法的调用 类型是通过调用方法的时候来指定String procut = prodocGetter.getProduct(strList);System.out.println(procut+"\t"+procut.getClass().getSimpleName());System.out.println("分割线=============================================>");ArrayList<Integer> integers = new ArrayList<>();integers.add(100);integers.add(30004);integers.add(6471);Integer integer = prodocGetter.getProduct(integers);System.out.println(integer+"\t"+integer.getClass().getSimpleName());}
}
测试:
定义多个泛型类型的静态泛型方法
泛型方法与可变参数
泛型方法总结
类型通配符
定义
代码示例
我们先看下数据类型Integer和Number的关系
点进Integer可以看到Integer是继承了Number
根据原先多态的想法,我们可以这样定义:
但是这里却报错了
也就是说泛型这里不可以使用多态来进一步转换类型数据,这个时候类型通配符的作用就显现出来了
通配符的上限
定义
代码示例
书写三个继承关系类,Animal->BIgDog->Dog
Animal:
public class Animal {
}
BIgDog:
public class BIgDog extends Animal{
}
Dog:
public class Dog extends BIgDog{
}
测试:
本次没有测试演示,可以看到此时定义的通配符上限类为BigDog,所以showAnimal中传递的集合数据类型只能由BigDog或者BigDog的子类,BigDog的父类Animal已经报警不可用
需要注意的是通配符上限的集合是不允许填充实例数据的,比如:
因为此时定义了通配符的上限类,而集合根本不确定集合中存的数据是什么数据类型
通配符的下限
定义
代码示例
可以看到此时定义的通配符下限类为BigDog,所以showAnimals中传递的集合数据类型只能由BigDog或者BigDog的父类,BigDog的子类Dog已经报警不可用
通配符下限这里集合是可以直接添加实例的
jdk中下限通配符的使用
改造三个类
Animal
public class Animal {public String name;public Animal(String name) {this.name = name;}@Overridepublic String toString() {return "Animal{" +"name='" + name + '\'' +'}';}
}
BigDog
public class BIgDog extends Animal{public Integer age;public BIgDog(String name, Integer age) {super(name);this.age = age;}@Overridepublic String toString() {return "BIgDog{" +"age=" + age +", name='" + name + '\'' +'}';}
}
Dog
public class Dog extends BIgDog{public Integer level;public Dog(String name, Integer age, Integer level) {super(name, age);this.level = level;}@Overridepublic String toString() {return "Dog{" +"level=" + level +", age=" + age +", name='" + name + '\'' +'}';}
}
TreeSet中的有一个构造函数就是典型的通配符下限使用
测试:
类型擦除