泛型的类型通配符以及上下限-----java小知识

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在java中数组是可以协变的(就是在<>里写父类类型的数组,子类类型数组也可以写入,程序不会报错);但是集合不能协变(也就是说虽然类之间继承了,但是父类集合和子类集合没关系。)

所以Java泛型提供了类型通配符“”。


一、类型通配符是什么?

一个可以匹配任何类型的符号。 符号为:“?
作用:“ ”可以在 “使用泛型” 的时候表示一切类型。
(E T K V)等符号是在 “定义泛型” 的时候使用。

二、为什么要有上下限?

通配符可以表示任意类型,那么我们无法限制用户输入类型,相当于一个果蔬店混进了卖猪肉,牛肉,百货的,这样是不行的,所以要通过上下限进行约束。
定义:<? extends 父类类名>

三、使用步骤

1.数组可以协调的代码(方便对照集合)

代码如下(示例):

class Fruitsandvegetables{
	String name;
	double price;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public Fruitsandvegetables(String name, double price) {
		super();
		this.name = name;
		this.price = price;
	}
	public Fruitsandvegetables() {
		super();
	}
	@Override
	public String toString() {
		return "Fruitsandvegetables [name=" + name + ", price=" + price + "]";
	}
	
}
class Fruit extends Fruitsandvegetables{

	public Fruit() {
		super();
	}

	public Fruit(String name, double price) {
		super(name, price);
	}
	
}
class Vegetable extends Fruitsandvegetables{

	public Vegetable() {
		super();
	}

	public Vegetable(String name, double price) {
		super(name, price);
	}
	
}
public class dem3 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Fruit[] t=new Fruit[2]; 
		t[0]=new Fruit("苹果", 9.9);
		t[1]=new Fruit("草莓", 30);
		sale(t);
	}
	public static void sale(Fruitsandvegetables[] fv) {
		System.out.println(fv[0].toString()+" "+fv[1].toString());//类中重写了toString()方法
	}
}

输出结果:

Fruitsandvegetables [name=苹果, price=9.9] Fruitsandvegetables [name=草莓, price=30.0]

2.集合不协变(错误演示)

代码如下:

import java.util.ArrayList;
import java.util.List;
class Fruitsandvegetables{
	String name;
	double price;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public Fruitsandvegetables(String name, double price) {
		super();
		this.name = name;
		this.price = price;
	}
	public Fruitsandvegetables() {
		super();
	}
	@Override
	public String toString() {
		return "Fruitsandvegetables [name=" + name + ", price=" + price + "]";
	}
	
}
class Fruit extends Fruitsandvegetables{

	public Fruit() {
		super();
	}

	public Fruit(String name, double price) {
		super(name, price);
	}
	
}
class Vegetable extends Fruitsandvegetables{

	public Vegetable() {
		super();
	}

	public Vegetable(String name, double price) {
		super(name, price);
	}
	
}
public class dem3 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		List<Fruit> f=new ArrayList<>();
		f.add(new Fruit("苹果",9.9));
		f.add(new Fruit("草莓",30.0));
		List<Vegetable> v=new ArrayList<>();
		v.add(new Vegetable("白菜",1.2));
		v.add(new Vegetable("胡萝卜",8.0));
		sale(f);
		sale(v);
	}
	public static void sale(List<Fruitsandvegetables> fv) { //泛型类型为父类名
		System.out.println(fv.toString());
	}
}

结果:

Exception in thread "main" java.lang.Error: 无法解析的编译问题:
	类型 dem3 中的方法 sale(List<Fruitsandvegetables>)对于参数(List<Fruit>)不适用
	类型 dem3 中的方法 sale(List<Fruitsandvegetables>)对于参数(List<Vegetable>)不适用

3.利用通配符改正集合不协变(正确演示)

代码如下(前面代码一致,仅仅展示主函数):


public class dem3 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		List<Fruit> f=new ArrayList<>();
		f.add(new Fruit("苹果",9.9));
		f.add(new Fruit("草莓",30.0));
		List<Vegetable> v=new ArrayList<>();
		v.add(new Vegetable("白菜",1.2));
		v.add(new Vegetable("胡萝卜",8.0));
		sale(f);
		sale(v);
	}
	public static void sale(List<?> fv) {  //将父类类型名改为通配符  ?
		System.out.println(fv.toString());
	}
}

4.通配符的漏洞 (错误演示)

import java.util.ArrayList;
import java.util.List;
class Fruitsandvegetables{
	String name;
	double price;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public Fruitsandvegetables(String name, double price) {
		super();
		this.name = name;
		this.price = price;
	}
	public Fruitsandvegetables() {
		super();
	}
	@Override
	public String toString() {
		return "Fruitsandvegetables [name=" + name + ", price=" + price + "]";
	}
	
}
class Fruit extends Fruitsandvegetables{

	public Fruit() {
		super();
	}

	public Fruit(String name, double price) {
		super(name, price);
	}
	
}
class Vegetable extends Fruitsandvegetables{

	public Vegetable() {
		super();
	}

	public Vegetable(String name, double price) {
		super(name, price);
	}
	
}
class chicken{
	String cName;
	double cPrice;
	public chicken(String cName, double cPrice) {
		super();
		this.cName = cName;
		this.cPrice = cPrice;
	}
	public chicken() {
		super();
	}
	public String getcName() {
		return cName;
	}
	public void setcName(String cName) {
		this.cName = cName;
	}
	public double getcPrice() {
		return cPrice;
	}
	public void setcPrice(double cPrice) {
		this.cPrice = cPrice;
	}
	@Override
	public String toString() {
		return "chicken [cName=" + cName + ", cPrice=" + cPrice + "]";
	}
	
}
public class dem3 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		List<Fruit> f=new ArrayList<>();
		f.add(new Fruit("苹果",9.9));
		f.add(new Fruit("草莓",30.0));
		List<Vegetable> v=new ArrayList<>();
		v.add(new Vegetable("白菜",1.2));
		v.add(new Vegetable("胡萝卜",8.0));
		List<chicken> c=new ArrayList<>();
		c.add(new chicken("大白鸡",50));
		sale(f);
		sale(v);
		sale(c);
	}
	public static void sale(List<?> fv) {
		System.out.println(fv.toString());
	}
}

结果:

[Fruitsandvegetables [name=苹果, price=9.9], Fruitsandvegetables [name=草莓, price=30.0]]
[Fruitsandvegetables [name=白菜, price=1.2], Fruitsandvegetables [name=胡萝卜, price=8.0]]
[chicken [cName=大白鸡, cPrice=50.0]]   //混进来了

不是吧,不是吧,果蔬店怎么可以卖鸡肉呢!!!

4.利用上下限约束通配符 (正确演示)

代码如下(与上面的代码仅仅存在主函数上的区别,所以只展示主函数):

public class dem3 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		List<Fruit> f=new ArrayList<>();
		f.add(new Fruit("苹果",9.9));
		f.add(new Fruit("草莓",30.0));
		List<Vegetable> v=new ArrayList<>();
		v.add(new Vegetable("白菜",1.2));
		v.add(new Vegetable("胡萝卜",8.0));
		List<chicken> c=new ArrayList<>();
		c.add(new chicken("大白鸡",50));
		sale(f);
		sale(v);
		sale(c);
	}
	public static void sale(List<? extends Fruitsandvegetables> fv) {
		System.out.println(fv.toString());
	}
}

结果:

Exception in thread "main" java.lang.Error: 无法解析的编译问题:
	类型 dem3 中的方法 sale(List<? extends Fruitsandvegetables>)对于参数(List<chicken>)不适用

快看,快看,鸡肉被发现了,不可以让他卖!!!
当我们删除鸡肉后

public class dem3 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		List<Fruit> f=new ArrayList<>();
		f.add(new Fruit("苹果",9.9));
		f.add(new Fruit("草莓",30.0));
		List<Vegetable> v=new ArrayList<>();
		v.add(new Vegetable("白菜",1.2));
		v.add(new Vegetable("胡萝卜",8.0));
		List<chicken> c=new ArrayList<>();
		c.add(new chicken("大白鸡",50));
		sale(f);
		sale(v);
	}
	public static void sale(List<? extends Fruitsandvegetables> fv) {
		System.out.println(fv.toString());
	}
}

结果:

[Fruitsandvegetables [name=苹果, price=9.9], Fruitsandvegetables [name=草莓, price=30.0]]
[Fruitsandvegetables [name=白菜, price=1.2], Fruitsandvegetables [name=胡萝卜, price=8.0]]

这才是果蔬店嘛,别的不能有!!!


总结

很简单,大家看看就懂了。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值