泛型详解实例

请添加图片描述

什么是泛型?

  泛型就是,适用于很多种的类型.关于这种类型有一个比较直观的例子就是object数组,那为什么有object数组还要使用泛型呢?
举个例子:
  object数组类似于,开盲盒,你不知道下一个开出来的是什么.关键在于,你想要使用这个盲盒,你就必须知道这个盲盒中的东西是什么性质,而再去探究盲盒中的东西性质,无疑更加重我们的使用负担.
  我们更希望不是开盲盒,而是开刮刮乐,里面开出来的都是我们需要的(钱),这样我们就可以拿来就用.
  而泛型恰恰是实现指定类型,来实现一个类,这个类型可以是任意的,这样我们在使用泛型的时候就可以很明确的知道,这个类的返回类型是什么,从而更好的使用它
所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查

泛型语法

代码案例

class 泛型类名称<类型形参列表> {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
// 可以只使用部分类型参数
}

具体代码实现

class MyArray<T> {
	public T[] array = (T[])new Object[10];//1
	public T getPos(int pos) {
		return this.array[pos];
	}
public void setVal(int pos,T val) {
	this.array[pos] = val;
	}
}
public class TestDemo {
	public static void main(String[] args) {
		MyArray<Integer> myArray = new MyArray<>();//2
		myArray.setVal(0,10);
		myArray.setVal(1,12);
		int ret = myArray.getPos(1);//3
		System.out.println(ret);
		myArray.setVal(2,"bit");//4
	}
}

代码解释
①类名后的 代表占位符,表示当前类是一个泛型类

一些常见占位符
E 表示 Element
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 - 第二、第三、第四个类型

②注释1处:泛型数组不能直接实例化

也就是说T[] ts = new T[5];//是不对的
原因为:我们希望,

注释2处:使用泛型需要指定传参,传参类型必须是包装类
注释3处:不需要进行强制类型转换
注释4处:代码编译报错,此时因为在注释2处指定类当前的类型,此时在注释4处,编译器会在存放元素的时候帮助我们进行类型检查

泛型类的使用

泛型类<类型实参> 变量名; // 定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象
注:new 后面的类型实参,可以省略,这是因为类型推导,下面回讲.

代码例子

 MyArray<Integer> list = new MyArray<Integer>();

泛型的类型推导

泛型的类型推导为:当编译器可以根据上下文,来推出这个类型实参时,就可以省略不写这个类型实参.

泛型机制有哪些?

擦除机制

泛型的擦除机制指的是:在编译期间,编译器会把所有类型都擦除为object数组
举个例子:比如你去寄快递,不管你寄送的是什么,最后都是由一层包装显示的,只保留贵重物品等信息.

通过命令:javap -c 查看字节码文件,所有的T都是Object (借用一下图,侵删)
在这里插入图片描述

所以就引出了俩个问题
  上文中说:T[] ts = new T[5]; 是不对的.编译的时候,擦除机制将T类型替换为Object,不是相当于:Object[] ts = new Object[5]吗?那还怎么实现类型指定?
  原因为:返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,运行的时候,直接转给Integer类型的数组,编译器认为是不安全的

泛型的上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束

语法

class 泛型类名称<类型形参 extends 类型边界> {
...
}
public class MyArray<E extends Number> {
...
}

注: 没有指定类型边界 E,可以视为 E extends Object

public class MyArray<E extends Comparable<E>> {
...
}

注:E必须是实现了Comparable接口的

泛型方法

上面讲了,泛型类的使用,那么当然,泛型同样可以指定方法.

语法:方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { … }

public class Util {
//静态的泛型方法 需要在static后用<>声明泛型类型参数
	public static <E> void swap(E[] array, int i, int j) {
		E t = array[i];
		array[i] = array[j];
		array[j] = t;
	}
}

通配符

通配符’?'与上面的T标志作用差不多,只不过?在于泛型可以匹配更广泛的类型


通配符的使用情况:但我们想要可以接收所有的泛型类型,但是又不能够让用户随意修改。这种情况就需要使用通配符"?"来处理
俩种限制
? extends 类:设置通配符上限
? super 类:设置通配符下限

通配符的上界,不能进行写入数据,只能进行读取数据,因为你无法确定写入的是那个子类,所以只能读取
举个直观例子:比如你有一家餐饮店,你是总店,任何支店的信息,你都可以接收,但如果是让你修改某一具体的规则,你会因为不知道是哪一个地方的支店而不能修改(PS:要么你就去改总店的规则,这样下去所有的支店都会有这个规则)

<? extends 上界>
<? extends Number>//可以传入的实参类型是Number或者Number的子类
class Food {}
class Fruit extends Food {}
class Apple extends Fruit {}class Banana extends Fruit {
}
class Message<T> { // 设置泛型
	private T message ;
	public T getMessage() {
	return message;
}
public void setMessage(T message) {
	this.message = message;
	}
}
public class TestDemo {
	public static void main(String[] args) {
		Message<Apple> message = new Message<>() ;
		message.setMessage(new Apple());
		fun(message);
		Message<Banana> message2 = new Message<>() ;
		message2.setMessage(new Banana());
		fun(message2);
} // 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
	public static void fun(Message<? extends Fruit> temp){
		//temp.setMessage(new Banana()); //仍然无法修改!
		//temp.setMessage(new Apple()); //仍然无法修改!
		System.out.println(temp.getMessage());
	}
}

通配符的下界,不能进行读取数据,只能写入数据。
举个例子:你是一家连锁店,你可以写信息发送给总店,但是你看不了其他店的信息.

<? super 下界>
<? super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类类型
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值