泛型究竟是什么

泛型的好处

1.不会在运行期报错,避免代码在上线后运行你报错,提前在编译期告诉用户哪里错误
2.不用强制转换

泛型类

子类是泛型类,子类和父类的泛型类型要一致,如父类是E,子类是T,子类继承父类时,父类也要用T,而不是写E。子类可以扩展泛型,如A<T,S>,该泛型类定义后,相当于字段的用法,如构造方法初始化,使用setter和getter方法。
子类不是泛型类,则继承的父类要明确具体类型。
泛型类型只能是包装类,因为都是继承Object
两者不指定父类是什么类型,则为Object类型。
泛型接口和泛型类使用一致。
List和List对象的类型是一样的,一样是List类型。

泛型方法

方法用到了泛型列表才是泛型方法,如,而T的方法还是普通方法,并不是泛型方法。
泛型方法的泛型类型跟泛型类或接口的泛型类型无关。支持静态
成员方法的泛型类型则要遵从泛型类或接口的泛型类型,即普通方法。不支持静态
泛型方法支持可变参数,如 void a(E… e)
能用泛型方法就不要用泛型类,因为泛型方法更加灵活。

类型通配符

类型通配符:表示具体的实参,如?,他相当于Object,他是类型实参,不是类型形参

类型通配符上限

<? extends A>:只能是A的子类或者是A。上限最大是AA则为上限。遍历是A,因为都是A的子类。
方法参数是ArrayList< ? extends A >, 则方法里不能添加具体类型,如list.add(new A()) ,因为类型不确定。

类型通配符下限

<? super A>:只能是A或者A的父类,A则为下限。遍历只能是Object
方法参数是ArrayList<? super A>, 则方法里可以添加任何具体类型,因为他遍历的是Object,即他的父类不能确定,只能用Object接收。

类型擦除

为了兼容jdk1.5,只在编译时有泛型存在,编译完成后就擦除泛型。如

public class ErasedTypeEquivalence {
  public static void main(String[] args) { 
      Class c1 = new ArrayList<String>().getClass(); 
      Class c2 = new ArrayList<Integer>().getClass(); 
      System.out.println(c1 == c2); 
  } 
}

结果为true,因为他们的实际类型是ArrayList,而不是ArrayList和ArrayList,因为类型被擦除了。

无限制类型擦除

public class Erasure<T> {
	private T key;

	public T getKey() {
		return key;
	}

	public void setKey(T key) {
		this.key = key;
	}
}
public class Test {
	public static void main(String[] args) {
		Erasure<Integer> era = new Erasure<>();

		// 反射,获取Erasure类的字节码文件的Class类对象
		Class<? extends Erasure> class1 = era.getClass();

		// 获取所有的成员变量
		Field[] declaredFields = class1.getDeclaredFields();

		// 遍历数组,打印成员变量的名称和类型
		for (Field f : declaredFields) {
			System.out.println(f.getName() + ":" + f.getType().getSimpleName());
		}

	}
}

执行结果如图
在这里插入图片描述

有限制类型擦除

public class Erasure<T extends Number> {
	private T key;

	public T getKey() {
		return key;
	}

	public void setKey(T key) {
		this.key = key;
	}
}
public class Test {
	public static void main(String[] args) {
		Erasure<Integer> era = new Erasure<>();

		// 反射,获取Erasure类的字节码文件的Class类对象
		Class<? extends Erasure> class1 = era.getClass();

		// 获取所有的成员变量
		Field[] declaredFields = class1.getDeclaredFields();

		// 遍历数组,打印成员变量的名称和类型
		for (Field f : declaredFields) {
			System.out.println(f.getName() + ":" + f.getType().getSimpleName());
		}

	}
}

结果如图
在这里插入图片描述

擦除方法中类型定义的参数

public class Erasure<T extends Number> {
	private T key;

	public T getKey() {
		return key;
	}

	public void setKey(T key) {
		this.key = key;
	}

	// 泛型方法,上限为List
	public <T extends List> T show(T t) {
		return t;
	}
}
		Erasure<Integer> era = new Erasure<>();

		// 反射,获取Erasure类的字节码文件的Class类对象
		Class<? extends Erasure> class1 = era.getClass();
		
		//擦除方法中类型定义的参数
		// 获取Erasure下所有的方法
		Method[] declaredMethods = class1.getDeclaredMethods();
		for (Method m : declaredMethods) {
//			打印方法名和方法的返回值类型
			System.out.println(m.getName() + ":" + m.getReturnType().getSimpleName());
		}

执行结果如图
在这里插入图片描述

桥接方法

/**
 * 
 * 泛型接口
 * @param <T>
 */

public interface Info<T> {
	T info(T t);
}

public class InfoImpl implements Info<Integer> {

	@Override
	public Integer info(Integer value) {
		return value;
	}

}

		/**
		 * 桥接方法
		 */
		Class<InfoImpl> infoClass = InfoImpl.class;
		//获取所有方法
		Method[] infoImplMethods = infoClass.getDeclaredMethods();
		for (Method m : infoImplMethods) {
			//打印方法名和方法的返回值类型
			System.out.println(m.getName() + ":" + m.getReturnType().getSimpleName());
		}

结果如下图
在这里插入图片描述

泛型数组

public class Fruit<T> {

    private T[] array;

    public Fruit(Class<T> clz,int length){
        //创建泛型数组
        array = (T[]) Array.newInstance(clz,length);
    }
    
    //数组赋值
    public void put(int index,T t){
        array[index] = t;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值