一.泛型的继承和通配符:
1.泛型不具备继承性,但是数据具备继承性:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class GenericsDemo5 {
public static void main(String[] args) {
//创建集合的对象
ArrayList<Ye> list1=new ArrayList<>();
ArrayList<Fu> list2=new ArrayList<>();
ArrayList<Zi> list3=new ArrayList<>();
//调用method方法
method(list1);
/*
method(list2);
method(list3);
method方法里不能传list2和list3,
因为泛型不具备继承性
method方法的形参里集合泛型为Ye类型,传递参数时就必须是Ye类型,不能是其他类型,他的子类也不行
*/
//数据具有继承性
/*list1的泛型为Ye类型,可添加Ye类型以及他的子类型(添加的是数据)*/
list1.add(new Ye());
list1.add(new Fu());
list1.add(new Zi());
}
public static void method(ArrayList<Ye> list){
}
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
2.弊端:可以接收任意数据类型:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class GenericsDemo6 {
public static void main(String[] args) {
/* 需求:
定义一个方法,形参是一个集合,但是集合中的数据类型不确定
*/
//创建集合的对象
ArrayList<Ye> list1=new ArrayList<>();
ArrayList<Fu> list2=new ArrayList<>();
ArrayList<Zi> list3=new ArrayList<>();
ArrayList<Student2> list4=new ArrayList<>();
method(list1);
method(list2);
method(list3);
method(list4);
}
/* 弊端:
利用泛型方法有一个弊端,此时它可以接收任意的数据类型
如Ye Fu Zi 以及Student2
*/
public static<E> void method(ArrayList<E> list){
//E就是代表不确定的数据类型
}
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
class Student2{}
3.弊端的修改方案:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class GenericsDemo6 {
public static void main(String[] args) {
/* 需求:
定义一个方法,形参是一个集合,但是集合中的数据类型不确定
*/
//创建集合的对象
ArrayList<Ye> list1=new ArrayList<>();
ArrayList<Fu> list2=new ArrayList<>();
ArrayList<Zi> list3=new ArrayList<>();
ArrayList<Student2> list4=new ArrayList<>();
method(list1);
method(list2);
method(list3);
//method(list4);会报错-->因为list4的泛型是Student2,method里只能传泛型是Ye以及Ye的子类的
}
/* 弊端:
利用泛型方法有一个弊端,此时它可以接收任意的数据类型
如Ye Fu Zi 以及Student2
此时希望:虽然本方法不确定类型,但是以后只希望传递Ye Fu Zi
注:不能把方法的形参里的泛型用Ye,因为泛型不具备继承性
此时->可以利用 泛型的通配符 解决:?也表示不确定的类型
也可以进行类型的限定->两种写法:? extends E:表示可以传递E或者E所有的子类类型
? super E:表示可以传递E或者E所有的父类类型
泛型的通配符的应用场景:
1.在定义类,方法,接口的时候,如果类型不确定,就可以定义为泛型类,泛型方法,泛型接口(此时是不想限定类型的范围)
2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型的通配符
泛型的通配符:
关键点:用来限定类型的范围
*/
public static void method(ArrayList<? extends Ye> list){
//泛型用?时,前面不用再写<?>
}
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
class Student2{}
4.泛型的通配符的应用场景:
1)在定义类,方法,接口的时候,如果类型不确定,就可以定义为泛型类,泛型方法,泛型接口(此时是 不想限定类型的范围)
2)如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型的通配符(此时是想限定类型的范围)
泛型的通配符->关键点:用来限定类型的范围
5.泛型的通配符的总结:
泛型的通配符 :?表示不确定的类型 也可以进行类型的限定->两种写法:
? extends E:表示可以传递E或者E所有的子类类型
? super E:表示可以传递E或者E所有的父类类型
二.综合练习:
package com.itheima.a05test;
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) {
/*需求:
定义一个继承结构:
动物
| |
猫 狗
| | | |
波斯猫 狸花猫 泰迪 哈士奇
属性:名字,年龄
行为:吃东西
方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小鱼干
方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼
方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭
方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家
测试类中定义一个方法用于饲养动物
public static void keepPet(ArrayList<???> list){
//遍历集合,调用动物的eat方法
}
要求1:该方法能养所有品种的猫,但是不能养狗
要求2:该方法能养所有品种的狗,但是不能养猫
要求3:该方法能养所有的动物,但是不能传递其他类型
*/
//1.猫
ArrayList<BoSi> c1=new ArrayList<>();
c1.add(new BoSi("张三",1));
keepPet(c1);
ArrayList<LiHua> c2=new ArrayList<>();
c2.add(new LiHua("李四",2));
keepPet(c2);
//2.狗
ArrayList<TaiDi> d1=new ArrayList<>();
d1.add(new TaiDi("王五",3));
keepPet(d1);
ArrayList<HaShiQi> d2=new ArrayList<>();
d2.add(new HaShiQi("赵六",4));
keepPet(d2);
//3.动物
keepPet(c1);
keepPet(c2);
keepPet(d1);
keepPet(d2);
}
/*
//要求1:该方法能养所有品种的猫,但是不能养狗
public static void keepPet(ArrayList<? extends Cat> list){
//遍历集合,调用动物的eat方法
for (Cat cat : list) {
cat.eat();
}
}
*/
/*
//要求2:该方法能养所有品种的狗,但是不能养猫
public static void keepPet(ArrayList<? extends Dog> list){
for (Dog dog : list) {
dog.eat();
}
}
*/
//要求3:该方法能养所有的动物,但是不能传递其他类型
public static void keepPet(ArrayList<? extends Animal> list){
for (Animal animal : list) {
animal.eat();
}
}
}
package com.itheima.a05test;
public abstract class Animal {
/* public abstract class Animal<N,I>{
private N name;
private I age;
}
当name,age类型不确定时就可以定义泛型类,N和I表示泛型类型
*/
private String name;
private int age;
//
public Animal(){}
public Animal(String name,int age){
this.name=name;
this.age=age;
}
//
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//
public abstract void eat();
}
package com.itheima.a05test;
public abstract class Cat extends Animal{
//
public Cat(){}
public Cat(String name,int age){
super(name, age);
}
//
@Override
public abstract void eat();
}
package com.itheima.a05test;
public abstract class Dog extends Animal{
//
public Dog(){}
public Dog(String name,int age){
super(name, age);
}
//
@Override
public abstract void eat();
}
package com.itheima.a05test;
public class BoSi extends Cat{
//
public BoSi(){}
public BoSi(String name,int age){
super(name,age);
}
//
@Override
public void eat(){
System.out.println("一只叫做"+super.getName()+"的,"+
super.getAge()+"岁的波斯猫,正在吃小鱼干");
}
}
package com.itheima.a05test;
public class HaShiQi extends Dog{
//
public HaShiQi(){}
public HaShiQi(String name,int age){
super(name, age);
}
//
@Override
public void eat(){
System.out.println("一只叫做"+super.getName()+"的,"+
super.getAge()+"岁的哈士奇,正在吃骨头,边吃边拆家");
}
}
package com.itheima.a05test;
public class LiHua extends Cat{
//
public LiHua(){}
public LiHua(String name,int age){
super(name, age);
}
@Override
public void eat(){
System.out.println("一只叫做"+super.getName()+"的,"+
super.getAge()+"岁的狸花猫,正在吃鱼");
}
}
package com.itheima.a05test;
public class TaiDi extends Dog{
//
public TaiDi(){}
public TaiDi(String name,int age){
super(name, age);
}
//
@Override
public void eat(){
System.out.println("一只叫做"+super.getName()+"的,"+
super.getAge()+"岁的泰迪,正在吃骨头,边吃边蹭");
}
}