学习笔记:Java之 泛型

泛型(generic):   即为一般的类型、广泛的类型。

1. 泛型的作用与目的:

    如果给集合指定泛型,那么该集合只能存放指定类型的元素。【其中,泛型取值不能为基本类型,为引用类型

    试想,如果没有泛型。那么,集合将可以可以存储任意对象,这些对象在集合中,其类型并不明确。当从集合中取出这些元素,他们都将会被编译为Object类型。想要明确类型,就要进行强制转换,此时就可能会引起 ClassCastException。

/*
    会引起异常的代码
*/
private static void method() {
        //有一个存放人的集合(未指定泛型)
        ArrayList list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        //这里没有却存放了人的一个编号
        list.add(9527); 

        for(Object element : list){
            //为了找出长度为4的元素,强转为string,用其length方法
            String name = (String) element;
            System.out.println(name.length());
        }
    }

    虽说没有泛型不影响写代码,但是这种设计不仅使集合存放的元素类型不明确,也会引起异常增加了编程的复杂性。所以,泛型的出现,目的是为了:将运行时期出现的异常(ClassCastException),提前到编译时期发现,避免类型转换。

    其本质上,是一种安全提醒 机制

    

2. 泛型类

    当我们定义一个      ArrayList<Integer> list = new ArrayList<>();   并且调用其add()方法是,发现其方法参数,与泛型一致。

        这是为什么?

    集合中的这个机制,就是基于泛型类,典型的泛型类,如: ArrayList.

    泛型类语法(如何让一个普通类成为泛型类):

public class GenericClassDemo {

    public static void main(String[] args) {
        //此时T为String,那么这个对象所有涉及T的均为String
        MyList<String> stringMyList = new MyList<>();
        //泛型为String,添加的参数为String
        stringMyList.add("aaa");
        //泛型为String,方法返回值为String
        String s = stringMyList.get();
    }
}
/*
    泛型类:
        1. 定义: 类名<泛型的变量名>,任意大小写字母,习惯上用大写字母T 或  E
        2. 泛型的赋值 : 必须是引用类型
        3. 泛型类的泛型 : 是在使用这个类的指定泛型
 */
class MyList<T>{
    T t;  //可以看做引用类型,只是还未明确指定
    public void add(T t){
        this.t = t;
    }
    public T get(){
        return t;
    }
}

3. 泛型接口

public class GenericInterfaceDemo {
    public static void main(String[] args) {


    }
}

//泛型接口(语法与泛型方法一直)
interface MyColl<Q> {
    void add(Q q);
}

//  实现方式1:实现类在 继承接口的时候 就已经指定 泛型了,那么这个类就不需要是泛型类
class MyInter implements MyColl<String> {
    @Override
    public void add(String s) {

    }
}

// 实现方式2:保留泛型,但必须在类后面指定泛型,那么这个类就是泛型类
class MyInter2<Q> implements MyColl<Q> {
    @Override
    public void add(Q q) {
    }

}

4. 泛型方法

public class GenericMethodDemo {

    public static void main(String[] args) {

        MyMethod mm = new MyMethod();
        mm.add(1);

        Boolean play1 = mm.play(true);


    }
}
/**
    泛型方法:
        定义 : 在返回值 前面 <T>
        赋值 : 在方法调用的时候,进行传参
 */
//普通类
class MyMethod{
    //普通方法
    public void show(Object msg){
    }
    /*
        语法:返回值前加<泛型变量>
     */
    public <T>void add(T t){

    }
    //传什么类型的参数,我就返回什么类型的值 (联动)
    public <T>T play(T t){
        return t;
    }
    //你传什么类型的数组,我就返回什么类型的元素 (联动)
    public <T>T num(T[] t){
        return t[0];
    }
}

 现在  有两个集合,如何用一个方法,同时遍历这两个集合?

ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();

    因为泛型没有“继承”的概念。既: ArrayList<Object> 不是 ArrayList<String> 的父类,两者的本质都是容器,

    所以无法将方法参数的泛型指定为Object.   

    用泛型方法就可以解决:

private static <T>void method0(ArrayList<T> list1 ) {
    for(Object t : list1){}
}

5. 泛型通配符

    上述问题,除了用泛型方法外,还有种更简便的方法,就是用泛型通配符

/*
    泛型通配符 : ?
        ? --> 指代 任意的引用类型 (是一个范围的概念),泛型方法中 T 是 未知的引用类型
        此时  T 被 ? 赋值(任意引用类型) 单一的值
 */
private static void method(ArrayList<?> list) {
        for(Object t : list){}
}

     当直接使用List<?>这种形式时,既明确明确这个list集合可以是任何泛型list的父类。但还有一种特殊情形,程序不希望这个List<?>是任何泛型的父类,只希望他代表某一类型的父类。

    上下限概念:

//定义两个类
class Person{

}
class Student extends Person{

}

//定义一个方法
//上限 : ? extends Person  --> Person 及其子类
private static void method000(ArrayList<? extends Person> list) {
    for(Object t : list){}
}

public static void main(String[] args) {
        //list3的元素 是 list4的元素 父类
        // 将list4中的所有元素 添加 list3中
        ArrayList<Person> list3 = new ArrayList<>();
        list3.add(new Person());
        list3.add(new Student());

        ArrayList<Student> list4 = new ArrayList<>();
        
        list3.addAll(list4);
}

猜你喜欢

转载自blog.csdn.net/weixin_38816084/article/details/82631539