• java语言基础2--泛型


      泛型特性出来之前,大家都使用Object类型来创建一般化的类,但是它们不能以安全的方式进行工作,泛型可以安全的工作,因为不再需要显式的强制转换,此外泛型还可以扩展重用代码的能力。

    基本知识

      下面是一个简单的泛型例子

    public class Gen<T> {
        T val;
        
        Gen(T t){ val = t;}
        
        public T getVal() { return val; }
    
        void showType() {
            System.out.println(val.getClass().getName());
        }
    }
    public class Test {
        public static void main(String[] args) {
            //T 类型将被指定为Integer 类型。实际上编译器并没有创建不同版本的Gen类,编译器只是移除泛型所有泛型信息,进行了类型替换,这个过程叫泛型擦除
            Gen<Integer> gen1 = new Gen<Integer>(100);
            gen1.showType();//输出 java.lang.Integer
            System.out.println(gen1.getVal());//输出100
            
    //        gen1 = new Gen<Double>(10.0);//上面已经将gen1 指定为了Gen<Integer>类型了,不能再指定为Gen<Double> 这种检查是泛型的特点之一,保证了类型的安全
            
            //T 类型将被指定为String 类型
            Gen<String> gen2 = new Gen<String>("I am a String");
            gen2.showType();//输出java.lang.String
            System.out.println(gen2.getVal());//输出 I am a String
        }
    }

    有界泛型 语法<T extends superClass> , 或者<T extends superClass & myInterface>  这里的接口也使用extends关键字来修饰

      T能传递所有类型,这当然很好,但有时候,我们需要做一个限定,比如当我们想对一组数据求平和,那么类型肯定要数值类型才行的。因此我们需要做限定。

    public class Stats<T extends Number> {
        T[] nums;
        
        Stats(T[] param){this.nums=param;}
        
        double average() {
            double sum = 0.0;
            for(int i = 0;i<nums.length;i++) {
                sum +=nums[i].doubleValue();
            }
            return sum;
        }
    }
    public class Test {
        public static void main(String[] args) {
            Integer [] arr = {1,2,3,4,5};
            Stats<Integer> s = new Stats<Integer>(arr);
            System.out.println(s.average());//输出 15.0
            
            BigDecimal [] arr1 = {new BigDecimal("1.1"),new BigDecimal("2.2"),new BigDecimal("3.3"),new BigDecimal("4.4"),new BigDecimal("5.5")};
            Stats<BigDecimal> s1 = new Stats<BigDecimal>(arr1);
            System.out.println(s1.average());//输出16.5
              
            String[] arr2 = {"1.1","2.2"};
    //        Stats<String> s2 = new Stats<String>(arr2);//String  不是Number类型 ,因此编译失败
        }
    }


     通配符 ?

      有时候我们有以下需求,比较两个数组的求和是否相等,Integer[] arrr1={1,2,3} 和 Double arr2={1.0,2.0,3.0};期望返回true;于是我们可能会像下面这样写

    public class Stats<T extends Number> {
        T[] nums;
        
        Stats(T[] param){this.nums=param;}
        
        double average() {
            double sum = 0.0;
            for(int i = 0;i<nums.length;i++) {
                sum +=nums[i].doubleValue();
            }
            return sum;
        }
        
        boolean sameAverage(Stats<T> t) {
            return this.average()==t.average();
        }
    }
    public class Test {
        public static void main(String[] args) {
            Integer [] arr = {1,2,3,4,5};
            Stats<Integer> s = new Stats<Integer>(arr);
            System.out.println(s.average());//输出 15.0
            
            BigDecimal [] arr1 = {new BigDecimal("1.1"),new BigDecimal("2.2"),new BigDecimal("3.3"),new BigDecimal("4.4"),new BigDecimal("5.5")};
            Stats<BigDecimal> s1 = new Stats<BigDecimal>(arr1);
            System.out.println(s1.average());//输出16.5
              
            if(s.sameAverage(s1.average())) {//这里会编译失败 ,因为调用者是Stats<Integer>类型的 ,而比较对象是Stats<BigDecimal>,类型不兼容,导致编译失败
                System.out.println("求和相同");
            }else {
                System.out.println("求和不同");
            }
        }
    }

     为了将 sameAverage方法 泛型化,我们需要使用通配符?,表示未知类型,修改以上代码,即可通过编译

        boolean sameAverage(Stats<?> t) {//这里 Stats<?>和所有Stats对象匹配
            return this.average()==t.average();
        }

    有界通配符  语法<? extneds superClass> 上界,<? super subClass>  下界(注意与<T extneds superClass>的区别)

     泛型方法

    public class Generic {
        static <T extends Comparable<T>,V extends T> boolean isIn(T x,V[] arr) {
            boolean flag = false;
            for(int i=0;i<arr.length;i++) {
                if(x.equals(arr[i])) {
                    flag=true;
                    break;
                }
            }
            return flag;
        }
        public static void main(String[] args) {
            Integer[] arr1 = {1,2,3,4};
            System.out.println(isIn(3, arr1));//输出true
            
            String[] arr2 = {"a","b","c"};
            System.out.println(isIn("a", arr2));//输出true
        }
    }
    static <T extends Comparable<T>,V extends T> boolean isIn(T x,V[] arr)
    泛型方法 语法格式是将参数置于返回类型之前,这里是T继承Comparable<T>,同时V extends T的限制,返回类型前的<>的内容仅仅是对类型做一个限制

    也可以将构造方法泛型化
    public class GenCons {
        private double val;
    
        <T extends Number> GenCons(T t) {
            this.val = t.doubleValue();
        }
    
        public double getVal() {
            return val;
        }
    
        public void setVal(double val) {
            this.val = val;
        }
        
        public static void main(String[] args) {
             GenCons con1 = new GenCons(100);
             System.out.println(con1.getVal());
             
             GenCons con2 = new GenCons(100.99);
             System.out.println(con2.getVal());
        }
    }

      泛型接口,

    public interface  MinMax<T extends Comparable<T>> {
        T min();
        T max();
    }
    public class MyClass<T extends Comparable<T>>  implements MinMax<T> {
        T[] vals;
        MyClass(T[] vals){
            this.vals=vals;
        }
    
        @Override
        public T min() {
            T min = vals[0];
            for(int i=0;i<vals.length;i++) {
                if(vals[i].compareTo(min)<0) {
                    min=vals[i];
                }
            }
            return min;
        }
    
        @Override
        public T max() {
            T max = vals[0];
            for(int i=0;i<vals.length;i++) {
                if(vals[i].compareTo(max)>0) {
                    max=vals[i];
                }
            }
            return max;
        }
        
        public static void main(String[] args) {
            Integer[] arr1 = {1,2,3,4};
            MyClass<Integer> m1 = new MyClass<>(arr1);
            System.out.println(m1.min());//输出 1
            System.out.println(m1.max());//输出 4
            
            String[] arr2 = {"a","b","c","d"};
            MyClass<String> m2 = new MyClass<>(arr2);
            System.out.println(m2.min());//输出  a
            System.out.println(m2.max());//输出  d
        }
    }

      看一下泛型接口的声明interface   MinMax<T extends Comparable<T>>  和普通类差不多

      看一下实现类class MyClass<T extends Comparable<T>> implements MinMax<T>,因为MyClass实现MinMax 所以界限和接口的界限一致,此外这个界限不需要在implements 子句中指定,参数可以原封不动的传递给接口,一般来说 一个类实现泛型接口,那么这个类也需要是泛型化的比如以下方式就是错误的

    public class MyClass implements MinMax<T>//错误 T类型未知

      因为没有声明参数,所以无法传递类型参数给接口,编译器会报 T类型未知的错误

      当然,如果实现的是一个具体的泛型接口,那么类是无需泛型化的,如以下是合法的

    public class MyClass implements MinMax<Integer> 

       泛型类的继承的时候,也可以指定为子泛型类设置多个参数,如下

    public class Gen<T> {
        T ob;
    
        public T getOb() {
            return ob;
        }
    
        public void setOb(T ob) {
            this.ob = ob;
        }
    
    }
    //这里的T 将传递给Gen,V将作为自己的类型
    public class Gen2<T,V> extends Gen<T> {
        V v;
    
        public Gen2(V v) {
            super();
            this.v = v;
        }
    }

     非泛型类也可以作为泛型类的父类 如下

    class Gen<T> extends  NonGen{
    }

    使用instanceof 在运行时对泛型进行类型判断

    public class Gen<T> {
        T ob;
        public Gen(T ob) {
            super();
            this.ob = ob;
        }
    
        public T getOb() {
            return ob;
        }
    }
    public class Gen2<T> extends Gen<T> {
    
        public Gen2(T o) {
            super(o);
        }
        
        public static void main(String[] args) {
            Gen<Integer> g1 = new Gen<Integer>(10);
            System.out.println(g1 instanceof Gen<?>);//输出true
            
            Gen2<Integer> g2 = new Gen2<Integer>(20);
            System.out.println(g2 instanceof Gen<?>);//输出true
    //        System.out.println(g2 instanceof Gen2<Integer>);//编译失败 不能讲g2 与特定的类型比较
            
            Gen<Integer> test = (Gen<Integer>) g2;//也可以对泛型进行强制转换
            
            Gen<String> g3 = new Gen<String>("Hello");
            System.out.println(g3 instanceof Gen2<?>);//输出fasle
        }
    }

    泛型擦除:编译java代码时,所有的泛型信息将被移除,意味着使用它们的界定类型替换类型参数,如果没有显式的指定类型,将使用Object代替。

    使用泛型的注意事项

    public class Gen<T> {
    //    static T test;  // 不能静态成员不能使用 泛型参数
        T ob;
        public Gen(T ob) {
    //        ob = new T();  // T只是占位符  不能实例化, 因为jvm不知道T是哪种类型
        }
    
        public T getOb() {
            return ob;
        }
    }

    暗示

  • 相关阅读:
    Python Scarpy安装包
    pip install 出现报asciii码错误的问题
    pyhton 27 pip命令无法使用 没有Scripts文件夹 的解决方法
    北漂
    15再见,16你好。
    selenium By.xpath 用法
    java.util.NoSuchElementException解决办法
    Android版之数据库增删改查图书信息
    Android studio连接sqlserver数据库
    Android简易版图书管理系统
  • 原文地址:https://www.cnblogs.com/tjqBlog/p/9778531.html
Copyright © 2020-2023  润新知