泛型
泛型类
- 简单泛型类
public class Parent<E> {
private E key;
public Parent(E key) {
this.key = key;
}
/**
* 此方法并不是泛型方法,只是使用了类的泛型
*/
public E getKey(){
return key;
}
/**
* 此方法并不是泛型方法,只是使用了类的泛型
* @param key
*/
public void setKey(E key) {
this.key = key;
}
}
子类继承泛型父类
- 不指定父类泛型,默认为Object
public class Child<T> extends Parent{
public Child(Object key) {
super(key);
}
@Override
public Object getKey() {
return super.getKey();
}
}
- 不指定子类泛型,则需要直接指定父类泛型类型
/*
* 子类不指定泛型,需直接指定父类泛型类型
*/
public class Child extends Parent<String>{
public Child(String key) {
super(key);
}
@Override
public String getKey() {
return super.getKey();
}
}
- 指定子类泛型需与父类泛型保持一致
/**
* 父类泛型需和子类泛型一致,
* 虽然Parent中泛型等于E,但这里子类定义泛型为T 也需把父类泛型写成T,
* 定义子类继承父类时,泛型需保持一致,相当于把T当成类型传递给父类使用
*/
public class Child<T> extends Parent<T>{
public Child(T key) {
super(key);
}
@Override
public T getKey() {
return super.getKey();
}
}
- 指定多个子类泛型,指定的父类泛型时需包含在子类泛型列表中
/**
* Parent<x>中的泛型需在 Child<...>泛型列表中
*/
public class Child<T,E> extends Parent<T>{
private E value;
public Child(T key,E value) {
super(key);
this.value = value;
}
@Override
public T getKey() {
return super.getKey();
}
public E getValue(){
return value;
}
}
泛型接口
- 泛型类接口
public interface Generator<E> {
E getKey();
}
- 实现类不是泛型类,接口要明确数据类型
public class Apple implements Generator<String>{
private String key;
@Override
public String getKey() {
return key;
}
}
- 实现类也是泛型类,实现类和接口的泛型类型要一致
public class Pear<T> implements Generator<T>{
private T key;
@Override
public T getKey() {
return key;
}
}
泛型方法
- public与返回值中间非常重要,可以理解为声明此方法为泛型方法,只有声明了的方法才是泛型方法
- 泛型类中的使用了泛型的成员方法并不是泛型方法。
- 表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T,与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
public static <T> List<T> toList(T... arr) {
List<T> lists = new ArrayList<T>();
for (T element : arr) {
lists.add(element);
}
return lists;
}
public static <T> T getOne(T... arr) {
return arr[new Random().nextInt(arr.length)];
}
public static <T> T getOneRandom(List<T> lists) {
return lists.get(new Random().nextInt(lists.size()));
}
- 泛型方法的泛型与类的泛型是相互独立不影响的
public class Generic<T> {
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
public <E> E getValue(E obj){
return obj;
}
}
// 调用可以发现泛型方法泛型和类泛型互不影响
public static void main(String[] args){
Generic<Integer> generic = new Generic<>(111);
Integer key = generic.getKey();
String value = generic.getValue("xiaoai");
}
类型通配符
Integer 为 Number子类
- 普通泛型类
public class Box<E> {
private E first;
public E getFirst() {
return first;
}
public void setFirst(E first) {
this.first = first;
}
}
- 报错
public class BoxTest {
public static void main(String[] args){
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box1.setFirst(200);
showBox(box2); // 报错,方法参数泛型不同
}
private static void showBox(Box<Number> box1) {
System.out.println(box1.getFirst());
}
}
通配符【?】
public class BoxTest {
public static void main(String[] args){
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box1.setFirst(200);
showBox(box2); // 不报错
}
// 使用泛型通配符"?" 接收任意类型
private static void showBox(Box<?> box1) {
System.out.println(box1.getFirst());
}
}
通配符上限【? extents】
- 要求该泛型的类型,只能是实参类型,或实参类型的子类类型。
public class BoxTest {
public static void main(String[] args){
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box1.setFirst(200);
showBox(box2); // 不报错
}
// 使用泛型通配符"?" 只能接收Number及其子类型
private static void showBox(Box<? extends Number> box1) {
System.out.println(box1.getFirst());
}
}
- 使用通配符上限修饰,如果是列表则不能添加元素,因为【?】上限限定子类也能接收,所以无法确定接收的是何种类型。
public static void main(String[] args){
List<? extends Number> list = new ArrayList<>();
list.add(222); // 报错
// 确定类型可以添加子类型
List<Number> listNumber = new ArrayList<>();
List<Integer> listInteger = new ArrayList<>();
listInteger.add(111); // 不报错
listNumber.add(111); // 不报错
listNumber.addAll(listInteger); // 不报错
}
通配符下限【? super】
- 要求该泛型的类型,只能是实参类型,或实参类型的父类类型。
public class BoxTest {
public static void main(String[] args){
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
Box<Integer> box2 = new Box<>();
box1.setFirst(200);
showBox(box2); // 报错
}
// 使用泛型通配符"?" 只能接收Number及其父类型
private static void showBox(Box<? super Number> box1) {
System.out.println(box1.getFirst());
}
}
- 下限通配符,如果是列表可以添加数据,但不保证数据类型。
类型擦除
类型擦除:泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是,泛型代码能够很好地和之前版本的代码兼容。那是因为,泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉。
public class myTest {
public static void main(String[] args){
ArrayList<Integer> intList = new ArrayList<>();
ArrayList<String> strList = new ArrayList<>() ;
System.out.println(intList.getClass().getSimpleName()); // ArrayList
System. out.println(strList.getClass().getSimpleName ()); // ArrayList
System. out. println(intList.getClass() == strList.getClass()); // true
}
}
无限制类型擦除
有限制类型擦除
擦除方法中类型定义的参数
桥接方法
泛型数组
- 可以声明带泛型的数组引用,但是不能直接创建带泛型的数组对象
public static void main(String[] args){
ArrayList<String>[] listArr1 = new ArrayList<>[5]; //报错
ArrayList<String>[] listArr2 = new ArrayList<String>[5]; //报错
ArrayList[] list = new ArrayList[5];
ArrayList<String>[] listArr3 = list; //不报错 但有弊端
}
// 弊端例如:
public static void main(String[] args){
ArrayList[] list = new ArrayList[5];
ArrayList<String>[] listArr3 = list; //不报错
ArrayList<Integer> intList = new ArrayList<>();
intList.add(100);
list[0] = intList;
System.out.println(listArr3[0].get(0)); // 类型转换异常,因为存入Integer类型 取的时候用泛型String取
}
// 建议
public static void main(String[] args){
ArrayList<String>[] listArr3 = new ArrayList[5]; //不报错
ArrayList<Integer> intList = new ArrayList<>();
intList.add(100);
listArr3[0] = intList; // 编译时即会报错
ArrayList<String> strList = new ArrayList<>();
intList.add("xiaoai");
listArr3[0] = strList; // 不会报错
System.out.println(listArr3[0].get(0));
}
- 可以通过java.lang.reflect.Array的newInstance (Class,int)创建T[]数组
public class Fruit<T> {
private T[] array;
public Fruit(Class<T>clz,int length){
//通过Array.newInstance创建泛型数组
array = (T[]) Array.newInstance(clz,length);
}
/**
* 添加元素
* @param index
* @param item
*/
public void put(int index,T item){
array[index] = item;
}
/**
* 获取元素
* @param index
* @return
*/
public T get(int index){
return array[index];
}
/**
* 获取数组
* @return
*/
public T[] getArray(){
return array;
}
}
反射与泛型
- Person类
public class Person {
private String name;
private String age;
}
- 反射指定泛型
public static void main(String[] args)throws Exception {
// 使用泛型
Class<Person> personClass = Person.class;
Constructor<Person> constructor = personClass.getConstructor();
Person person = constructor. newInstance ();
// 不使用泛型
Class personClass = Person.class;
Constructor constructor = personClass. getConstructor();
Object p = constructor. newInstance() ;
}