Java学习笔记===》16.泛型深入

泛型以及Set系列集合

一、泛型深入

1.泛型:

​ 是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查

2.泛型的格式

​ < 数据类型 >

3.注意

​ ★泛型只支持引用数据类型,没有泛型约束的时候,可以往集合中添加任意类型的数据

​ ★但是遍历集合得到的数据聚类形是Object类型的,而多态的弊端是不能访问子类的特有功能

​ ★虽然可以使用强制转换,但是并不能明确知道强转的类型

4.结论:

​ ★如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型的

​ ★此时可以往集合中太假任意的数据类型

​ ★带来一个坏处,我们在获取数据的时候,无法使用它的特有行为

​ ★此时推出了泛型,可以在添加数据的时候,就把类型进行统一

​ ★而且我们在获取数据的升级后,也省的强转了,比较的方便

package com_06Gather._01gatherStructure._02SetTest;
import com_06Gather._01gatherStructure.Student;

import java.util.ArrayList;
import java.util.Iterator;

public class GenericsTest01 {
    public static void main(String[] args) {
/*没有泛型的时候,集合如何存储数据
结论
★如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型的
★此时可以往集合中太假任意的数据类型
★带来一个坏处,我们在获取数据的时候,无法使用它的特有行为
★此时推出了泛型,可以在添加数据的时候,就把类型进行统一
★而且我们在获取数据的升级后,也省的强转了,比较的方便
 */
        //1.创建集合的对象
        ArrayList list = new ArrayList();
        
        //2.添加数据
        list.add(123); //Integer
        list.add("abc"); //String
        list.add(new Student("zhangsan",12)); //Student
        
        
        //3.遍历集合获取里面的每一个元素
        Iterator it = list.iterator();
        while(it.hasNext()){
            Object obj = it.next();
            //堕胎的弊端是 不能访问子类的特有方法
            System.out.println(obj);
        }
    }
}

5.泛型的好处

​ ★统一数据类型

​ ★把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来

6.扩展知识点

★Java中的泛型其实是伪泛型:
在这里插入图片描述

7.泛型的细节

★泛型中不能写基本数据类型

★指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类型

★如果不写泛型,类型默认是Object

8.泛型可以在很多地方进行定义

(1)类后面===》泛型类

①使用场景:

​ 当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

②格式:
修饰符  class 类名 < 类型 > {
    
}

//例如:
public class ArrayList<E>{   //这里的E代表不确定的类型,但是创建该类对象时,E就确定类型
    //此处E可以理解为变量,但不是用来记录数据的,而是用来记录类型的,可以写成:T\K\E\V等
}
package com_06Gather._01gatherStructure._02SetTest;

public class GenericsTest03_MyArrayListTest02 {
    public static void main(String[] args) {
        GenericsTest02_MyArrayList<String> list = new GenericsTest02_MyArrayList<>();

        list.add("wewew");
        String s = list.get(0);

        System.out.println(list);
        System.out.println(s);

        GenericsTest02_MyArrayList<Integer> list2 = new GenericsTest02_MyArrayList<>();
        list2.add(123);
        list2.add(456);
        list2.add(789);
        Integer i = list2.get(2);
        System.out.println(i);
        System.out.println(list2);
    }
}

(2)方法上面===》泛型方法

①使用场景

​ 当方法中形参类型不确定时,可以使用类名后面定义的泛型< E >

​ 方案一:使用类名后面定义的泛型===》所有方法都能使用

​ 方案二:在方法申明上定义自己的泛型===》只能本方法使用

//格式
修饰符 < 类型 > 返回值类型 方法名 (类型  变量名){
    
}

//例如
    public < E > boolean add(E e){ //只有在调用这个方法时,才会确定变量的类型
        //此处E可以理解为变量,但是不是用来记录数据的,而是记录类型的,可以写成:T\K\E\V等
        
    }
②练习
/*需求:
定义一个工具类:ListUtil
类中定义一个静态方法,用来添加多个集合的元素
*/
package com_06Gather._01gatherStructure._02SetTest;

import java.util.ArrayList;

/*需求:
定义一个工具类:ListUtil
类中定义一个静态方法,用来添加多个集合的元素
*/


//编写工具类
public class GenericsTest04_ListUtil {
    private ListUtil(){}
    //类中定义一个静态方法addAll,用来添加多个集合的元素。

    /*
     *   参数一:集合
     *   参数二~最后:要添加的元素
     *
     * */
    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);
    }
    //不确定形参类型以及个数的时候可以使用 E ... e
   public static<E> void addAll2(ArrayList<E> list, E...e){
        for (E element : e) {
            list.add(element);
        }
    }
    public void show(){
        System.out.println("尼古拉斯·纯情·天真·暖男·阿玮");
    }
}




//编写测试类
package com_06Gather._01gatherStructure._02SetTest;

import java.util.ArrayList;

public class GenericsTest04_ListUtilTest {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        GenericsTest04_ListUtil.addAll(list1, "aaa", "bbb", "ccc", "ddd");
        System.out.println(list1);


        ArrayList<Integer> list2 = new ArrayList<>();
        GenericsTest04_ListUtil.addAll(list2,1,2,3,4);
        System.out.println(list2);
    }
}


(3)接口后面===》泛型接口

//格式
修饰符  interface 接口名 <类型> {
    
}

//例如
public interface List<E>{
    
}
①重点:如何使用一个带泛型的接口

方式一:实现类给出具体类型
package com_06Gather._01gatherStructure._02SetTest;

public class GenericsTest05_Interface {
    public static void main(String[] args) {
/*
泛型接口的两种使用方式
    1.实现类给出库提的接口
    2.实现类延续泛型,创建实现类对象时再确定
 */
        GenericsTest06_MyArrayList_interface list = new GenericsTest06_MyArrayList_interface();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        GenericsTest07_MyArrayList2_interface<String> list2 = new GenericsTest07_MyArrayList2_interface<>();
        list2.add("aaa");
        list2.add("bbb");
        list2.add("ccc");
    }
}
package com_06Gather._01gatherStructure._02SetTest;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;



//第一种实现类给出具体的类型
public class GenericsTest06_MyArrayList_interface implements List<String> {
    @Override
    public int size() {
        return 0;
    }
   
}

方式二:实现类延续泛型,创建对象时再确定
package com_06Gather._01gatherStructure._02SetTest;

public class GenericsTest05_Interface {
    public static void main(String[] args) {
/*
泛型接口的两种使用方式
    1.实现类给出库提的接口
    2.实现类延续泛型,创建实现类对象时再确定
 */
        GenericsTest06_MyArrayList_interface list = new GenericsTest06_MyArrayList_interface();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        //第二种,在创建实现类对象的时候确定类型
        GenericsTest07_MyArrayList2_interface<String> list2 = new GenericsTest07_MyArrayList2_interface<>();
        list2.add("aaa");
        list2.add("bbb");
        list2.add("ccc");
    }
}

package com_06Gather._01gatherStructure._02SetTest;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class GenericsTest07_MyArrayList2_interface<E> implements List<E> {
    
}

9.泛型的继承和通配符

(1)泛型不具备继承性,但是数据具备继承性

package com_06Gather._01gatherStructure._02SetTest._01Generics;

import java.util.ArrayList;

public class GenericsTest08_extends {
    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);
        //此时泛型里面写的什么数据,那么就只能传递什么类型的数据


        //但是数据具备继承性
        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)泛型的通配符===》 ?(可以限定类型的范围)

? 也表示不确定的类型,但是可以进行类型的限定

① 限定方式:

★ ? extends E :表示可以传递E或者E所有的子类类型
★ ? super E :表示可以传递E或者E所有的父类类型

②应用场景:

​ ★如果我们在定义类、方法、接口的时候,如果类型不确定,就可以使用泛型类、泛型方法、泛型接口

​ ★如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型通配符

package com_06Gather._01gatherStructure._02SetTest._01Generics;

import java.util.ArrayList;

public class GenericsTest09_extends {
    public static void main(String[] args) {
        //需求:定义一个方法,形参是一个集合,但是集合中的数据类型不确定
        ArrayList<ye1> list1 = new ArrayList<>();
        ArrayList<fu1> list2 = new ArrayList<>();
        ArrayList<zi1> list3 = new ArrayList<>();
        ArrayList<Student> list4 = new ArrayList<>();



        //调用method方法
        method(list1);
        method(list2);
        method(list3);
        method(list4);


    }

    //方法一:泛型方法
    //弊端:它可以接受任意的数据类型
    //希望:本方法虽然不确定类型,但是以后我希望只能传递想要的类型
    //此时就可以使用泛型的通配符==》?
    // ? 也表示不确定的类型,但是可以进行类型的限定
    //限定方式:
    // ? extends E :表示可以传递E或者E所有的子类类型
    // ? super   E :表示可以传递E或者E所有的父类类型
    public static<E> void method(ArrayList<E>list){ }
    //方法二:使用通配符
    public static void method2(ArrayList<? extends ye1>list){}
    public static void method3(ArrayList<? super zi1>list){}
}
class ye1 { }

class fu1 extends ye { }

class zi1 extends fu { }

class Student{ }

(3)泛型通配符练习

 /*
            需求:
                定义一个继承结构:
                                    动物
                         |                           |
                         猫                          狗
                      |      |                    |      |
                   波斯猫   狸花猫                泰迪   哈士奇


                 属性:名字,年龄
                 行为:吃东西
                       波斯猫方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干
                       狸花猫方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼
                       泰迪方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭
                       哈士奇方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家

            测试类中定义一个方法用于饲养动物
                public static void keepPet(ArrayList<???> list){
                    //遍历集合,调用动物的eat方法
                }
            要求1:该方法能养所有品种的猫,但是不能养狗
            要求2:该方法能养所有品种的狗,但是不能养猫
            要求3:该方法能养所有的动物,但是不能传递其他类型
         */
//定义Animal类以及所有的动物属性
public abstract class Animal {
    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();
    public String toString() {
        return "Animal{name = " + name + ", age = " + age + "}";
    }
}


//定义猫类继承于Aniaml类
public abstract class Cat extends Animal {
}
//定义狗类继承于Aniaml类
public abstract class Dog extends Animal {
}

//定义猫的子类:狸花猫和波斯猫,定义每个猫特有的属性

//狸花猫
public class LihuaCat extends Cat{
    @Override
    public void eat(){
        System.out.println("一只叫做"+getName()+"的"+getAge()+"岁的狸花猫,正在吃鱼");
    }
}
//波斯猫
public class BosiCat extends Cat{
    @Override
    public void eat(){
        System.out.println("一只叫做"+getName()+"的"+getAge()+"岁的波斯猫,正在吃小饼干");
    }
}

//定义狗的子类:泰迪和哈士奇,定义每个狗特有的属性

//哈士奇
public class Hashiqi extends Dog{
    @Override
    public void eat (){
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的哈士奇,正在吃骨头,边吃边拆家");
    }
}
//泰迪
public class Taidi extends Dog{
    @Override
    public void eat (){
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的泰迪,正在吃骨头,边吃边蹭");
    }
}


//定义测试类
import java.util.ArrayList;
public class Test {
    public static void main(String[] args) {       

        ArrayList<BosiCat> list1 = new ArrayList<>();
        ArrayList<LihuaCat> list2 = new ArrayList<>();
        ArrayList<Taidi> list3 = new ArrayList<>();
        ArrayList<Hashiqi> list4 = new ArrayList<>();

        keepPet(list1);
        keepPet(list2);
        keepPet2(list3);
        keepPet2(list4);

        keepPet3(list1);
        keepPet3(list2);
        keepPet3(list3);
        keepPet3(list4);

    }
    //要求1:该方法能养所有品种的猫,但是不能养狗
    public static  void keepPet(ArrayList <? extends Cat> list){}
    //要求2:该方法能养所有品种的狗,但是不能养猫
    public static  void keepPet2(ArrayList <? extends Dog> list){}
    //要求3:该方法能养所有的动物,但是不能传递其他类型
    public static  void keepPet3(ArrayList <? extends Animal> list){}

}

10.泛型总结

(1)什么是泛型

​ JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查

(2)泛型的好处

​ ★统一数据类型

​ ★把运行时期遇到的问题提前到了编译时间,避免了强制转换可能出现的异常,因为在编译阶段就能确定下来

(3)泛型的细节

​ ★泛型中不能写基本数据类型

​ ★指定反省的具体类型后,传递数据时,可以传入该类型和它的子类型

​ ★如果不写泛型。类型默认是Object类型

(4)哪里定义泛型

​ ★泛型类:在类名里面定义泛型,创建该类对象的时候,确定类型

​ ★泛型方法:在修饰符后面定义方法,调用该方法的时候,确定类型

​ ★泛型接口:在接口名后面定义泛型,实现类确定类型,实现类延续类型

(5)泛型的继承和通配符

​ ★泛型不具备继承性,但是数据具备降级成型

​ ★泛型的通配符:?

​ ===》 ? extends E:

​ ===》 ? super E:

(6)使用场景

​ ★定义类、方法、接口的时候i,如果类型不确定,就可以定义泛型

​ ★如果类型不确定,但是能知道是哪个继承体系中的,可以是使用泛型的通配符

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值