泛型
泛型
泛型是JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
泛型格式:<数据类型>
注意:泛型只能用引用数据类型
如果不加泛型,那么在添加数据的时候会默认为是Object类,但是多态的弊端是不能访问子类的特有功能,而且进行强转的话也会出问题,如果有一个是Integer,你要强转成String类型,肯定会报错。
泛型的好处:
- 统一数据类型
- 把运行期间的问题提前到了编译期间,避免强制类型转换可能出现的异常,因为在编译阶段类型就确定下来了。
扩展知识:泛型在Java中是伪泛型,只在编译阶段有效。编译为class字节码文件的时候,泛型就消失,这种现象叫做泛型的擦除。
泛型的细节:
- 泛型中不能写基本数据类型。
- 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型。
- 如果不写泛型,类型默认是Object
泛型可以在很多地方进行定义。
使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类。
泛型类
自己重写ArrayList
public class MyArrayList<E> {
    Object[] obj = new Object[10];
    int size;
    public boolean add(E e){
        obj[size] = e;
        size++;
        return true;
    }
    public E getIndex(int index) {
        return (E) obj[index];
    }
    @Override
    public String toString() {
        return Arrays.toString(obj);
    }
}
泛型方法
方法中形参类型不确定时
- 
可以使用类名后面定义的泛型 
- 
在方法上申明定义自己的泛型 public class MyArrayList{ public <E> boolean add(E e){ obj[size] = e; size++; return true; } }
案例:
定义一个工具类ListUtil,类中定义一个静态方法addAll,用来添加多个集合的元素
public class ListUtil {
    private ListUtil(){
    }
    /**
     * 参数一:集合
     * 参数二 ~ 最后 要添加的数据
     */
    public static <E> void addAll(ArrayList<E> list,E e1,E e2,E e3,E e4){
        list.add(e1);
        list.add(e2);
        list.add(e3);
        list.add(e4);
    }
    public static <E> void addAll(ArrayList<E> list,E...e){
        for (E element : e) {
            list.add(element);
        }
    }
}
泛型接口
public interface 接口名<E>{
    
}
重点:如何使用泛型接口?
- 
实现类给出具体类型 public class MyArrayList2 implements List<String>{ }
- 
实现类延续泛型,创建对象时再确定。 public class MyArrayList2 implements List<E>{ } //创建该对象 MyArrayList2<String> list = new MyArrayList2<>();
泛型的继承和通配符
- 
泛型不具备继承性,但是数据具有继承性。 定义几个类,父类 Ye 子类Fu 子类Zi 
 public static void method(ArrayList<Ye> list){
        
 }
main方法{
    ArrayList<Ye> list1 = new ArrayList<>();
    ArrayList<Fu> list2 = new ArrayList<>();
    ArrayList<Zi> list3 = new ArrayList<>();
    method(list1);
    method(list2);  //报错
    method(list3);  //报错   method方法指定泛型类型为Ye,泛型不能继承,所以子类使用会报错
}
泛型方法里面写什么类型,传递的就只能是什么类型的数据,
弊端:
 它可以接收任意数据类型
我希望:本方法虽然不确定类型,但是我只希望只能传递Ye Fu Zi
此时我们就可以使用泛型的通配符:
 ?也表示不确定的类型
 但是它可以进行类型限定
 ? extends E :表示可以传递E或者E所有的子类类型
 ? super E :表示可以传递E 或者 E 所有的父类类型。
应用场景:
1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符
泛型的通配符:
关键点:可以限定类型的范围。
综合练习
需求:
 定义一个继承结构:
 动物
 丨 丨
 猫 狗
 丨 丨 丨 丨
 波斯猫 狸花猫 泰迪 哈士奇
属性:名字、年龄
行为:吃东西
 方法体打印:一只叫XXX的,X岁的波斯猫,正在吃小饼干
 方法体打印:一只叫XXX的,X岁的狸花猫,正在吃鱼
 方法体打印:一只叫XXX的,X岁的泰迪,正在吃骨头,边吃边蹭
 方法体打印:一只叫XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家
测试类中定义一个方法,用于饲养动物:
public static void keepPet(ArrayList<???> list){
	//遍历集合,调用动物的eat方法
}
要求1:该方法能养所有品种的猫,但不能养狗。
要求2:该方法能养所有品种的狗,但不能养猫。
要求3:该方法能养所有品种的猫,但不能养狗。
在测试类前,根据继承结构创建各个对象,各结点类型为抽象类,叶子结点实现自己的父类并且进行方法重写即可
public class Test {
    public static void main(String[] args) {
        ArrayList<PersianCat> list1 = new ArrayList<>();
        ArrayList<LiHuaCat> list2 = new ArrayList<>();
        ArrayList<TeddyDog> list3 = new ArrayList<>();
        ArrayList<HuskyDog> list4 = new ArrayList<>();
        list1.add(new PersianCat("aaa",3));
        list2.add(new LiHuaCat("bbb",3));
        keepCat(list1);
        keepCat(list2);
        list3.add(new TeddyDog("ccc",3));
        list4.add(new HuskyDog("ddd",3));
        keepDog(list3);
        keepDog(list4);
    }
    public static void keepCat(ArrayList<? extends Cat> list){
        for (int i = 0; i < list.size(); i++) {
            Cat cat = list.get(i);
            cat.eat();
        }
    }
    public static void keepDog(ArrayList<? extends Dog> list){
        for (int i = 0; i < list.size(); i++) {
            Dog dog = list.get(i);
            dog.eat();
        }
    }
    public static void keepAnimal(ArrayList<? extends Animal> list){
        for (int i = 0; i < list.size(); i++) {
            Animal animal = list.get(i);
            animal.eat();
        }
    }
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号