• 第17章 泛型


    泛型

    1.为什么需要使用泛型

    1.存储任意类型的数据在集合中,但是取出来都是Object类型,此时就得强转
    2.约束存储到集合中的元素必须是相同的数据类型(相同的数据类型才能做比较,如TreeSet类)
    3.设计一个点(point)类,来封装坐标位置,要求坐标位置支持String类型,Integer类型,Double类型。普通做法是定义三个不同类型的类,这样做太不优雅了

    2.定义和使用通用泛型类

    1.定义
    泛型是从java5开始支持的新语法。
    什么是泛型呢?
    1.广泛通用的类型
    2.代码模板中类型不确定,谁调用该段代码谁就指明类型是什么

    泛型类:直接在类/接口上定义的泛型
    使用泛型:
    1.保证前后类型相同
    List<String> list = new ArrayList<String>();//该List集合中只能存储String类型的元素

    2.因为前后类型相同,所有java7开始,退出泛型的菱形语法<>,即后一个可以不写
    List<String> list = new ArrayList<>();

    3.泛型不存在继承的关系(错误如下)
    List<Object> list = new ArrayList<String>();

    4.从此以后,使用集合都得使用泛型来约束该集合中元素的类型
    5.通过反编译发现:泛型其实也是语法糖,底层依旧没有泛型,而且依然使用强转

    示例:

    /**
     * Created by cenyu on 16-11-21.
     * 点坐标对象
     * 在本类中,T表示一种类型,该类具体类型是什么,由调用者来决定
     * 通用几种泛型代指.T:type   E:element    K:key    V:value
     * 需要定义的类型用尖括号<>在定义的时候括起来,下面就可以将T当做一个类型来用
     */
    public class Ponit<T> {
        private T x;
        private T y;
    
        public T getX() {
            return x;
        }
    
        public T getY() {
            return y;
        }
    
        public void setX(T x) {
            this.x = x;
        }
    
        public void setY(T y) {
            this.y = y;
        }
    }
    
    
    public class PointDemo {
        public static void main(String[] args) {
            //使用String类型,Point类中T全部用String替换
            //调用的时候需要在等号做右边同时定义类型
            Ponit<String> p = new Ponit<String>();
            p.setX("3");
            String x1 = p.getX();
            System.out.println(x1);
            //使用Integer类型
            //同上
            //使用Double类型
            //同上
        }
    }
    
    

    3.定义和使用泛型方法

    泛型方法:在方法上声明泛型
    以下情况使用:
    1.泛型类中的泛型只能使用于非静态方法,如果需要给静态方法设置泛型,此时使用泛型方法
    2.泛型类中的泛型适用于整个类中多个方法,有时候只对某一个方法设置泛型即可

    一般的,把自定义的泛型作为该方法的返回类型才有意义。而且此时的泛型必须是有参数设置进来的。如果没有参数来设置泛型的具体类型,此时的方法一般返回设计为Object即可。

    /**
     * 测试泛型方法
     * Created by cenyu on 16-11-22.
     */
    public class GebericAdd {
        //定义一个泛型方法,规定返回值为double
        public <T extends Number> double add(T t1, T t2){
            double sum = 0.0;
            sum = t1.doubleValue()+t2.doubleValue();
            return sum;
        }
    
        public static void test(){
            GebericAdd addTest = new GebericAdd();
    
            int num1=3;
            int num2=4;
            System.out.println(addTest.add(num1,num2));//输入Int型,返回double
    
            float num3=3.0f;
            float num4=7.0f;
            System.out.println(addTest.add(num3,num4));//输入float型,返回double
        }
    
    
        public static void main(String[] args) {
            test();
    
        }
    }
    
    

    4.泛型的通配符和上限下限

    泛型的通配符:
    不知道使用什么类型类接收的时候,此时可以用 ? ,?号表示未知,通配符。此时只能接收数据,不能往集合中存储数据

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 测试泛型通配符
     * Created by cenyu on 16-11-22.
     */
    public class GenericTypeDemo {
        public static void main(String[] args) {
            List<Integer> list1 = new ArrayList<>();
            doWork(list1);
            List<String> list2 = new ArrayList<>();
            doWork(list2);
            
        }
        
        //此处不知道会接收什么类型,用?通配符
        private static void doWork(List<?> list){
            
        }
    }
    
    

    上限和下限
    用来限定的元素的类型必须是X类的子类或相同类,X的父类或相同类

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 测试泛型上下限
     * Created by cenyu on 16-11-22.
     */
    public class GenericTypeDemo {
        public static void main(String[] args) {
            List<Integer> list1 = new ArrayList<>();
            List<String> list2 = new ArrayList<>();
            List<Number> list3 = new ArrayList<>();
            List<Object> list4 = new ArrayList<>();
            
            doWork(list1);
    //        doWork(list2);//此处报错
            doWork(list3);
    //        doWork(list4);//此处报错
            
            
    //        doWork2(list1);//此处报错
    //        doWork2(list2);//此处报错
            doWork2(list3);
            doWork2(list4);
    
        }
    
        //泛型的上限:此时的泛型?,必须是Number类型或Number类的子类
        private static void doWork(List<? extends Number> list){
    
        }
    
        //泛型的下限:此时的泛型?,必须是Number类型或Number类的父类
        private static void doWork2(List<? super Number> list){
    
        }
    }
    
    

    5.泛型的删除和转换

    泛型的擦除:
    1.泛型编译之后就消失了(泛型自动擦除);
    2.当把带有泛型的集合赋给不带泛型的集合,此持泛型被擦除(手动擦除)
    示例:

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 测试泛型擦除
     */
    public class GenericTypeDemo {
        public static void main(String[] args) {
            //带有Integer类型的泛型
            List<Integer> list1 = new ArrayList<>();
            list1.add(123);
    
            //不带泛型的集合
            List list2 = null;
            list2 = list1 //此时泛型被擦除
            list2.add("ABC"); //如果没被擦除是不允许用String的
    
            //带有String类型的泛型
            List<String> list3 = null;
            list3 = list2;//泛型被擦除了,然后又被赋值给list3.
                            //此时编译器不会报错,但是运行的时候还会报错
            //其实是等价于:String list3 = 123
            //此时用list3.get(0),是会报错的
        }
    
    }
    
    
    

    堆污染
    上面的代码中,会有报错就是因为对污染。
    单一一个方法中既使用泛型的时候也使用可变参数,此时容易导致堆污染问题

  • 相关阅读:
    推荐7个GitHub上不错的Python机器学习项目
    值得收藏的45个Python优质资源
    9 个鲜为人知的 Python 数据科学库
    小众Python库介绍
    Sebastian Ruder : NLP 领域知名博主博士论文面向自然语言处理的神经网络迁移学习
    学习Python 新去处:Python 官方中文文档
    图像超分辨率项目帮你「拍」出高清照片
    入坑机器学习?听听MIT在读博士的AI心得
    自然语言处理领域重要论文&资源全索引
    旷视等Oral论文提出GeoNet:基于测地距离的点云分析深度网络
  • 原文地址:https://www.cnblogs.com/cenyu/p/6149787.html
Copyright © 2020-2023  润新知