泛型-通配符-------(2)

1,匹配任意类型的通配符

在开发中,对象的引用传递是最常见的,但是如果在泛型类的操作中,在进行引用传递的时候,泛型类型必须匹配才可以传递,否则是无法传递的

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo12{
	public static void main(String args[]){
		Info<String> i = new Info<String>() ;		// 使用String为泛型类型
		i.setVar("MLDN") ;							// 设置内容
		fun(i) ;
	}
	public static void fun(Info<Object> temp){		// 接收Object泛型类型的Info对象
		System.out.println("内容:" + temp) ;
	}
};

运行结果:
这里写图片描述
发现报错了,编译报错提示,object类型的泛型不能接收string类型的泛型。Info<String> Info<Object>

泛型对象进行引用传递的时候,类型必须一致,否则无法传递,因为泛型本身就是一个标识符,具体的类型是从外面确定外面传入的,
编译器只判断是不是相同的标识符,不是相同的标识符就编译报错了

问题:

对于上面的问题,泛型类型不一致所以无法传递引用数据类型,但是如果现在我坚持,非要这么传递呢?该怎么办呢?

解决

其实,也简单,可以将fun方法中Info参数的泛型取消掉。

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo13{
	public static void main(String args[]){
		Info<String> i = new Info<String>() ;		// 使用String为泛型类型
		i.setVar("MLDN") ;							// 设置内容
		fun(i) ;
	}
	public static void fun(Info temp){		// 接收Object泛型类型的Info对象
		System.out.println("内容:" + temp) ;
	}
};

这里写图片描述

解决的不彻底,引入了新问题

发现,执行没有任何问题,取消掉参数的泛型以后,可以正常执行,但是这样似乎不太妥当,因为毕竟Info在声明的时候是指定了泛型的,

那么,如何解决这个不太妥当的问题呢?

整理一下现状:
在这个fun方法的参数中,加入泛型,会可能导致类型不匹配而报异常无法执行程序,不加泛型,又似乎不太妥当,代码并不是那么严密,在精细的开发中这样是不允许的,
那么这个问题,怎么解决呢?

解决

对于这个问题,就需要使用泛型的通配符来处理了。

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo14{
	public static void main(String args[]){
		Info<String> i = new Info<String>() ;		// 使用String为泛型类型
		i.setVar("MLDN") ;							// 设置内容
		fun(i) ;
	}
	public static void fun(Info<?> temp){		// 可以接收任意的泛型对象
		System.out.println("内容:" + temp) ;
	}
};

这里写图片描述
在程序的fun()方法中使用Info<?>的代码形式,表示可以使用任意泛型类型对象,这样做的话,fun()方法定义的就比较合理了,
但是在使用以上语法的时候,也需要注意一点:
如果使用了“?”接收泛型对象的时候,则不能修改接收到的内容。

也就是说,使用了“?”可以接收任意的内容,但是此内容无法直接使用<?>修饰的泛型对象进行修改。
什么意思呢,比如说:

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo15{
	public static void main(String args[]){
		Info<?> i = new Info<String>() ;		// 使用 ?接收String泛型类型
		i.setVar("MLDN") ;							// 设置内容
	}
};

这里写图片描述
发现编译时报错了,在使用“?”的时候,只能接收,不能修改。
并不表示某个具体的泛型类型,问号表示并不知道内部是什么泛型,只是黑盒接收该泛型过来而已,并不能修改。
使用只能接收,不能修改;

2,受限泛型

之前设置泛型的时候,实际上都是可以任意设置的,只要是类就可以设置,比如String,Float,Integer。。。。。。但是在Java的泛型中可以指定一个泛型的 上限和下限。即表示,泛型最大到哪个父类,最小到哪个子类;

在应用传递中,泛型的曹组可以设置一个泛型对象的范围上限和范围下限。
范围上限使用extends关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类;而范围下限使用super进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至object类。
这里写图片描述

设置上限,使用extends:

上限及表示,最大是本类及本类的子类

class Info<T extends Number>{

<T extends Number>表示上限:最高就是Number的类型,或者是Number的子类的数据类型。不能高于Number,比如Number之上的Object就是不可以的

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo17{
	public static void main(String args[]){
		Info<Integer> i1 = new Info<Integer>() ;		// 声明Integer的泛型对象
		Info<Float> i2 = new Info<Float>() ;			// 声明Float的泛型对象
		i1.setVar(30) ;									// 设置整数,自动装箱
		i2.setVar(30.1f) ;								// 设置小数,自动装箱
		fun(i1) ;
		fun(i2) ;
	}
	public static void fun(Info<? extends Number> temp){	// 只能接收Number及其Number的子类
		System.out.print(temp + "、") ;
	}
};

这里写图片描述

错误用法:

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo18{
	public static void main(String args[]){
		Info<String> i1 = new Info<String>() ;		// 声明String的泛型对象
		i1.setVar("hello") ;
		fun(i1) ;
	}
	public static void fun(Info<? extends Number> temp){	// 只能接收Number及其Number的子类
		System.out.print(temp + "、") ;
	}
};

这里写图片描述

在类上使用泛型上限:最大是Number或者是Number的子类。String并不是Number的子类,所以fun()方法并不能接收String的泛型对象,编译会报错。


class Info<T extends Number>{	// 此处泛型只能是数字类型
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo19{
	public static void main(String args[]){
		Info<Integer> i1 = new Info<Integer>() ;		// 声明Integer的泛型对象
		// 错误,无法声明String的泛型对象,Info在定义的
		Info<String> i1 = new Info<String>() ;		
	}
};
class Info<T extends Number>{	// 此处泛型只能是数字类型
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo20{
	public static void main(String args[]){
		// 错误,无法声明String的泛型对象,Info在定义的时候已经声明,只能接收Number及其子类的泛型类型
		Info<String> i1 = new Info<String>() ;		
	}
};

在这里插入图片描述
Info在定义的时候已经声明,只能接收Number及其子类的泛型类型,最高不能超过Number。传入String类型,编译时候肯定会报错,因为String并不是Number的子类,。

设置下限,使用super

下限表示,最低到哪个类型。
当使用的泛型只能在本类以及父类类型上应用的时候,就必须使用泛型的范围下限配置。使用super。

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo21{
	public static void main(String args[]){
		Info<String> i1 = new Info<String>() ;		// 声明String的泛型对象
		Info<Object> i2 = new Info<Object>() ;		// 声明Object的泛型对象
		i1.setVar("hello") ;
		i2.setVar(new Object()) ;
		fun(i1) ;
		fun(i2) ;
	}
	public static void fun(Info<? super String> temp){	// 只能接收String或Object类型的泛型
		System.out.print(temp + "、") ;
	}
};

运行结果,看到没有任何问题。
这里写图片描述


Info<? super String>泛型的上限是String或者String的父类,也就是Object。如果使用Integer作为作为泛型类型,则不满足泛型类型的下限。

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo22{
	public static void main(String args[]){
		Info<Integer> i1 = new Info<Integer>() ;		// 声明Integer的泛型对象
		i1.setVar(30) ;
		fun(i1) ;
	}
	public static void fun(Info<? super String> temp){	// 只能接收String或Object类型的泛型
		System.out.print(temp + "、") ;
	}
};

运行结果看到了,fun(Info<? super String>)方法中泛型最低的下限到String,现在传入的是Integer,并不符合条件,所以无法设置。
这里写图片描述

泛型的上限,下限就是extends与super关键字。

3,泛型与子类继承的限制

一个类的子类可以通过对象的多态性,为其父类实例化,也就是父类可以接收子类对象,
但是在泛型的操作中,子类的泛型类型是无法使用父类的泛型类型接收的,泛型类型必须完全一致才可以接收。但是可以使用通配符进行接收,这样的话当然接得接收收后不能修改的限制。
比如:Info<String> 不能使用Info<Object>接收。但是可以使用通配符进行接收。

这里写图片描述

class Info<T>{
	private T var ;		// 定义泛型变量
	public void setVar(T var){
		this.var = var ;
	}
	public T getVar(){
		return this.var ;
	}
	public String toString(){	// 直接打印
		return this.var.toString() ;
	}
};
public class GenericsDemo23{
	public static void main(String args[]){
		Info<String> i1 = new Info<String>() ;		// 泛型类型为String
		Info<Object> i2 = null ;
		Info<?> i3=null;
		i2 = i1 ;//这是错误的
		i3=i1;//这就没问题了,正确
	}
};

这是无法执行的,只能使用通配符来接收。

这里写图片描述

总结:

1,使用“?”可以接收任意的泛型对象。
2,泛型的上限:Info<? extends Number> 泛型数据类型是Number或者Number的子类。
3,泛型的下限:Info<? super String> 泛型的数据类型是String以及String的父类都是可以的
4,为什么泛型子类之间的继承无法直接转换的原因。子类的泛型类型是无法使用父类的泛型类型接收的,泛型类型必须完全一致才可以接收。但是可以使用通配符进行接收,这样的话当然接得接收收后不能修改的限制。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值