zoukankan      html  css  js  c++  java
  • JavaSE笔记-泛型

    定义带泛型的类

    public class Cat<T> {
        //可以用T定义实例变量
        private T name;
        //可以用T定义形参
      //构造器没有<> public Cat(T name){ this.name = name; } //可以作为返回值 public T forget(){ System.out.println("我叫啥来着?"); return this.name; } public static void main(String[] args){ Cat<String> cat = new Cat<>("阿猫"); System.out.println(cat.forget()); } }

    构造泛型对象可省略类型参数

    List<String> list = new ArrayList<>();
    //等价于List<String> list = new ArrayList<String>();
    //编译器会自己推出后边的类型是String

    泛型方法

    1.泛型方法可以在普通类或者泛型类

    2.类型参数放在修饰符之后,返回值之前

    public static <T> void test();

    不能在静态变量或者静态方法中使用泛型变量,不能实例化泛型变量

    因为泛型是要在对象创建的时候才知道是什么类型的,而对象创建的代码执行先后顺序是static的部分,然后才是构造函数等等。所以在对象初始化之前static的部分已经执行了,如果你在静态部分引用的泛型,那么毫无疑问虚拟机根本不知道是什么东西,因为这个时候类还没有初始化。因此在静态方法、数据域或初始化语句中,为了类而引用泛型类型参数是非法的

    public class Entry<k,v>{
    //以下2种方式是错误的
    private static V value;
    
    public static void setValue(V value){};
    
    }

    泛型不同类型相同

            List<String> list1 = new ArrayList<>();
            List<Integer> list2 = new ArrayList<>();
            System.out.println(list1.getClass() == list2.getClass());

    上面的代码返回值是true,因此list1和list2都是List类型,与泛型不泛型无关。

    类型通配符(?)

        public void getFamaleCat(List<?> list){
            for(int i=0;i<list.size();i++){
                System.out.println(list.get(i));
            }
        }

    1.当不确定传入的类型时,使用类型通配符?,不要使用List<Object>,当你想要传入一个List<String>作为参数时,程序编译不会通过,而使用?则可以通过

    2.当确定类型是某个类的子类型时,使用<? extends Father>,这时传入的类型只能是Father及其子类

    public class Util{
        /*    
        方法实现将src中的数据复制到dest中
        那么src中的数据类型只能是dest中数据类型的子类型
        比如:src中类型是Integer,dest中可以是Integer,Number,Object   
         */
        public static <T> void copy(List<T> dest,List<? extends T> src){
            for(T d : src){
                dest.add(d);
            }
        }
    
        public static void main(String[] args){
            List<Integer> src = new ArrayList<>();
            src.add(1);
            src.add(2);
            List<Number> dest = new ArrayList<>();
            //泛型的匹配方式是直接把参数拿过来和T比
         //因为dest的类型是Number,所以推出T是Number,所以dest集合中的类型都是Number
            copy(dest,src);
        }
    }

    3.当确定类型时某个类的父类型时,使用<? super son>,这时传入的类型只能是son及son的父类

    上面的例子最后dest中的数据类型都是Number,但是我们清楚的知道其实dest中每个数据的类型都是Integer,使用<? super son>改造

    public class Util{
        public static <T> void copy(List<? super T> dest,List<T> src){
            for(T d : src){
                dest.add(d);
            }
        }
    
        public static void main(String[] args){
            List<Integer> src = new ArrayList<>();
            src.add(1);
            src.add(2);
            List<Number> dest = new ArrayList<>();
            //dest集合中元素都是Integer类型
            copy(dest,src);
        }
    }

     4.泛型可以重载,不要包括2个意思相同的泛型方法

     public static <T> void copy(List<? super T> dest,List<T> src);
     public static <T> void copy(List<T> dest,List<? extends T> src);

    如果我们把这2个方法定义在同一个类里,main调用copy,编译器不能确定到底调用哪个方法

        public static void main(String[] args){
            List<Integer> src = new ArrayList<>();
            src.add(1);
            src.add(2);
            List<Number> dest = new ArrayList<>();
            copy(dest,src);
        }

    类型擦除

    所有的泛型类型会被编译成一个原始类型

    这样并不会不安全

    例如:List<String>,因为泛型会在编译的时候起作用,实际上你传入集合的所用元素都只能是String类型

    public class Cat<Object> {
        private Object name;
    
        public Cat(Object name){
            this.name = name;
        }
    
        public Object forget(){
            System.out.println("我叫啥来着?");
            return this.name;
        }
    }
  • 相关阅读:
    赠与今年的大学毕业生(胡适先生30年代的文章,仍不过时)
    统一管理磁盘上的开源代码
    生成sqlite导入库的做法
    提高二维矢量绘图效率之一般做法
    boost库命名规则的优点
    如何把腾讯微博挂到CSDN博客上
    fatal error C1902 Program database manager mismatch; please check your installation问题的解决
    智能指针变量做函数参数的一个值得注意的地方
    PC会消亡吗?
    软件制造问题的微软答案
  • 原文地址:https://www.cnblogs.com/vshen999/p/8361453.html
Copyright © 2011-2022 走看看