提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
在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]]
这才是果蔬店嘛,别的不能有!!!
总结
很简单,大家看看就懂了。