【java基础】泛型

泛型

泛型类

  • 简单泛型类
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() ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值