泛型

作者: Amy木婉清 | 来源:发表于2021-05-17 09:52 被阅读0次

    1.泛型类的定义

    泛型的实质就是一个类型占位符(T W E均可以代替),或指定其类型,如String Integer等。
    List源码中占位符如下图:


    image.png

    不知道传什么类型,用泛型来占位。
    List后就是一个泛型,E表示占位,即传什么类型就是什么类型。


    image.png
    例如:E的位置传的是string,那就是string类型,后面的泛型可写可不写,因为会根据前面指定的泛型自动匹配。
    image.png
    泛型的类型传string后,调用add方法只能add String类型
    image.png

    泛型的类型传Integer后,调用add方法只能add Integer类型


    image.png
    故:泛型类型传什么类型,就只能使用什么类型。
    泛型是为了确定数据添加的指定类型而加入的。
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description:  确定属性的类型时可直接给定
     */
    public class Person {
        private String name;
        private String address;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Person person = new Person();
            person.setName("zhangsan");
            System.out.println(person.getName());
        }
    }
    

    运行结果:zhangsan
    泛型类:在不知道未来属性类型时,可以使用类型占位符来占位,这时定义一个泛型类,即把代码中所有特定类型换成类型占位符。

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 如果说在不知道未来name和address类型的时候,可以使用类型占位符来进行占位
     * 定义一个泛型类
     * 定义泛型类实质就是将现在代码中所有的特定类型换成类型占位符
     */
    public class FxPerson<T> {
        private T name;
        private T address;
    
        public T getName() {
            return name;
        }
    
        public void setName(T name) {
            this.name = name;
        }
    
        public T getAddress() {
            return address;
        }
    
        public void setAddress(T address) {
            this.address = address;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            FxPerson<String> fxPerson = new FxPerson<>();
            fxPerson.setName("lisi");
            System.out.println(fxPerson.getName());
        }
    }
    

    运行结果:lisi
    泛型类型传递什么类型,使用的时候只能用什么类型。如下图所示:


    image.png
    image.png

    多个类型的泛型类:

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 传多个参数泛型类
     */
    public class FxPersonMore<K,V> {
        private K name;
        private V address;
    
        public K getName() {
            return name;
        }
    
        public void setName(K name) {
            this.name = name;
        }
    
        public V getAddress() {
            return address;
        }
    
        public void setAddress(V address) {
            this.address = address;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            //多个类型的泛型类
            FxPersonMore<String,Integer> fxPersonMore = new FxPersonMore<>();
            fxPersonMore.setName("wangwu");
            fxPersonMore.setAddress(123);
            System.out.println(fxPersonMore.getAddress());
            System.out.println(fxPersonMore.getName());
        }
    }
    

    运行结果:123
    wangwu

    传递什么类型,使用什么类型:


    image.png

    2.泛型方法

    2.1 泛型普通方法

    给类指定一个泛型,通过类的泛型确定方法参数的泛型

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 给类指定一个泛型,通过类的泛型确定方法参数的泛型
     */
    public class FxPersonM<T> {
        public void show(T name){
            System.out.println(name+"正在演讲!");
    
        }
    }
    
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 泛方法
     */
    public class TestFxMethod {
        public static void main(String[] args) {
            FxPersonM<String> fxPersonM = new FxPersonM<>();
            fxPersonM.show("heiliu");
        }
    }
    

    运行结果:heiliu正在演讲!

    2.2 泛型静态方法

    静态泛型方法中的类型占位符和类中的泛型占位符是没有关系的,如下图:


    image.png

    未经过标识的占位符不可使用,如下图



    静态方法中的占位标识符在使用前必须经过标识,如下图:
    image.png

    泛型静态方法示例:

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 给类指定一个泛型,通过类的泛型确定方法参数的泛型
     */
    public class FxPersonM<T> {
        /**
         * 2.泛型静态方法
         * 静态泛型方法中的类型占位符和类中的泛型占位符是没有关系的
         * @param name
         */
        public static<W> void show1(W name){
            System.out.println(name+":静态方法正在演讲!");
        }
    }
    
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 泛型方法
     */
    public class TestFxMethod {
        public static void main(String[] args) {
            // 2.泛型静态方法
            FxPersonM.show1("lisa");
            FxPersonM.show1(123);
        }
    }
    

    运行结果:
    lisa:静态方法正在演讲!
    123:静态方法正在演讲!
    有返回值的静态泛型方法:

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 给类指定一个泛型,通过类的泛型确定方法参数的泛型
     */
    public class FxPersonM<T> {
        /**
         * 有返回值类型的静态泛型方法占位符
         * @param name
         * @param <E> 占位符
         * @return
         */
        public static<E> E show2(E name){
            return name;
        }
    }
    
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 泛型方法
     */
    public class TestFxMethod {
        public static void main(String[] args) {
            //有返回值的静态泛型方法
            System.out.println(FxPersonM.show2("David"));
        }
    }
    

    运行结果:David

    3.泛型方法补充说明:

    如果你想让普通方法的类型不与类方法的类型一致,该怎么实现呢?
    例如:类方法的泛型占位符为外部传入的任意类型,但普通方法只想要用String类型
    只要是方法,就可以自定义泛型占位符

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 给类指定一个泛型,通过类的泛型确定方法参数的泛型
     */
    public class FxPersonM<T> {
        //3.普通方法自定义占位符
        public <W> void selfShow(W name) {
            System.out.println(name + "正在演讲!");
        }
    }
    
    image.png
     fxPersonM.selfShow("alic");
     fxPersonM.selfShow(45);
    

    运行结果:
    alic正在演讲!
    45正在演讲!

    4.泛型接口

    定义一个泛型接口,不指定具体泛型类型

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 泛型接口
     */
    public interface PerInterface<T>{
        public void show(T name);
    }
    

    定义一个实现泛型接口的类;实现泛型接口,将泛型接口中占位符指定为某一类型。

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 实现泛型接口的类
     * 1.实现泛型接口,将泛型接口中占位符指定为某一类型
     * 2.泛型接口的实现类可以指定具体的泛型接口的具体泛型的类型
     */
    public class PerIntImpl implements PerInterface<String>{
    
        @Override
        public void show(String name) {
            System.out.println(name);
        }
    }
    

    测试实现泛型接口的类

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 测试实现泛型接口的类
     */
    public class TestInterface {
        public static void main(String[] args) {
            PerIntImpl perInt = new PerIntImpl();
            perInt.show("li");
        }
    }
    

    运行结果:li

    定义一个实现泛型接口的类;实现泛型接口,不指定泛型类型。

    //泛型接口的实现类如果没有指定具体的泛型,必须要在这个实现类中声明一个泛型给泛型类型
    //这种情况外部调用show方法可以传任意类型
    public class PerIntImpl<T> implements PerInterface<T>{
    
        @Override
        public void show(T name) {
            System.out.println(name);
        }
    }
    

    5.泛型擦除模式

    定义一个泛型类

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 泛型擦除模式
     */
    public class FxPerErase<T> {
        private T name;
        public  void show(){
            System.out.println("方法被调用");
        }
    }
    

    测试类:

    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 擦除模式
     */
    public class TestEras {
        public static void main(String[] args) {
            FxPerErase<String> fxPerErase = new FxPerErase<>();
            FxPerErase<String> fxPerErase1 = new FxPerErase<>();
            System.out.println(fxPerErase.getClass()==fxPerErase1.getClass());
        }
    }
    

    运行结果:true
    如果把fxPerErase1前面的类型变成Integer,结果还是true。
    即:

      FxPerErase<Integer> fxPerErase1 = new FxPerErase<>();
    

    此时就涉及到一个名词叫擦除模式
    Java中的泛型只存在于编码编译阶段,在运行期间泛型的类型是会被去除掉的。
    擦除模式实质就是在代码运行期间将所有的泛型全部去掉
    Ques:为什么要使用擦除模式?
    Ans:为了兼容jdk老版本的编码

    6.泛型通配符

    (Integer是Number的子类)


    image.png

    Java中的继承并不是泛型中的继承
    Java中的父子类关系 在泛型中 并不是父子类关系,示例如下图所示:


    image.png
    解决上述问题,使用通配符
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 泛型擦除模式
     */
    public class FxPerErase<T> {
        private T name;
    
        public T getName() {
            return name;
        }
    
        public void setName(T name) {
            this.name = name;
        }
    
        public  void show(FxPerErase<?> fxPerErase){
            this.setName((T)fxPerErase.getName());
        }
    }
    
    image.png
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 擦除模式
     * 通配符:由于java中继承关系,在泛型中不做任何声明修饰的情况下是被认可的,所以要使用通配符来进行处理
     * 会使用通配符在泛型中将java中的继承关系 重新绑定
     * 通配符一般使用?来表示  可以理解为?是泛型中所有类的父类
     * 通配符的上边界  下边界问题
     * java中的继承 并不是泛型中的继承
     * java中的父子类关系  在泛型中 并不是父子类关系
     */
    public class TestEras {
        public static void main(String[] args) {
            FxPerErase<Number> fxPerErase = new FxPerErase<>();
            FxPerErase<Integer> fxPerErase1 = new FxPerErase<>();
            FxPerErase<String> fxPerErase2 = new FxPerErase<>();
            fxPerErase1.setName(111);
            fxPerErase.show(fxPerErase1);//fxPerErase fxPerErase1 fxPerErase2均可
            System.out.println(fxPerErase.getName());
        }
    }
    

    运行结果:111

    7.泛型上边界 extends 下边界 super 关键字

    7.1.? extends T 代表的是泛型可以传入T和T的子类的类型
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 泛型擦除模式
     */
    public class FxPerErase<T> {
        private T name;
    
        public T getName() {
            return name;
        }
    
        public void setName(T name) {
            this.name = name;
        }
          //? extends T 代表的是泛型可以传入T和T的子类的类型
        public  void show(FxPerErase<? extends T> fxPerErase){
            this.setName((T)fxPerErase.getName());
        }
    }
    
    
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 擦除模式
     * 通配符:由于java中继承关系,在泛型中不做任何声明修饰的情况下是被认可的,所以要使用通配符来进行处理
     * 会使用通配符在泛型中将java中的继承关系 重新绑定
     * 通配符一般使用?来表示  可以理解为?是泛型中所有类的父类
     * 通配符的上边界 extends  下边界问题 super 关键字
     * java中的继承 并不是泛型中的继承
     * java中的父子类关系  在泛型中 并不是父子类关系
     */
    public class TestEras {
        public static void main(String[] args) {
            FxPerErase<Number> fxPerErase = new FxPerErase<>();
            FxPerErase<String> fxPerErase2 = new FxPerErase<>();
            fxPerErase2.setName("2222");
            fxPerErase.show(fxPerErase2);//fxPerErase fxPerErase1 fxPerErase2均可
            System.out.println(fxPerErase.getName());
        }
    }
    

    运行结果:2222

    7.2.? super T 代表的是泛型可以传入T和T的父类
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 泛型擦除模式
     */
    public class FxPerErase<T> {
        private T name;
    
        public T getName() {
            return name;
        }
    
        public void setName(T name) {
            this.name = name;
        }
        //? super T 代表的是泛型可以传入T和T的父类
        public  void show(FxPerErase<? super T> fxPerErase){
            //System.out.println("方法被调用");
            this.setName((T)fxPerErase.getName());
        }
    }
    
    package com.example.fxtest;
    
    /**
     * @author zwp
     * @description: 擦除模式
     * 通配符:由于java中继承关系,在泛型中不做任何声明修饰的情况下是被认可的,所以要使用通配符来进行处理
     * 会使用通配符在泛型中将java中的继承关系 重新绑定
     * 通配符一般使用?来表示  可以理解为?是泛型中所有类的父类
     * 通配符的上边界 extends  下边界问题 super 关键字
     * java中的继承 并不是泛型中的继承
     * java中的父子类关系  在泛型中 并不是父子类关系
     */
    public class TestEras {
        public static void main(String[] args) {
            FxPerErase<Number> fxPerErase = new FxPerErase<>();
            FxPerErase<Integer> fxPerErase1 = new FxPerErase<>();
            FxPerErase<String> fxPerErase2 = new FxPerErase<>();
            fxPerErase1.setName(111);
            fxPerErase2.setName("2222");
            fxPerErase.show(fxPerErase);//super 下边界
            System.out.println(fxPerErase.getName());
        }
    }
    
    7.3.什么时候用上边界 什么时候用下边界

    1.上边界 在读取T这个类型数据的时候,但不写入数据的时候使用上边界
    2.下边界 需要写入数据的时候,但不需要读取的时候使用下边界
    3.既要读又要写不使用通配符

    相关文章

      网友评论

          本文标题:泛型

          本文链接:https://www.haomeiwen.com/subject/bougdltx.html