java 泛型理解

List和List的区别

类型参数“”主要用于声明泛型类或泛型方法
无界通配符“主要用于泛型类或泛型方法。

  • 声明泛型类的类型参数
public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable
{}
  • 声明泛型方法
 public  class aaa   {
        public   void fun(T b) {
        }
    }
 public  class aaa   {
        public   void fun(T b) { 
        }
    }

//类后面的泛型T 和 方法前面的泛型T 不是同一个泛型, 可以理解T 和E

 public  class aaa   {
        public   void fun(E b) { 
        }
    }
  • 的使用
List list = new ArrayList();

通配符会捕获具体的类型String,但是编译器不叫他String 而是起一个临时代号,所以不能往里面存任何非null元素

? super T和? extends T区别

  • :上界通配符(Upper Bounds Wildcards)
    包括T在内的任何T的子类
List foo3 = new ArrayList();
List foo3 = new ArrayList();
List foo3 = new ArrayList(); //编译不通过

  1. 读取操作通过以上给定的赋值语句,可以读取到Number,因为以上的列表要么包含Number元素,要么包含Number的类元素
  2. 添加操作, 不能往List中插入任何类型的对象,因为不能保证列表实际指向的类型是什么,你并不能保证列表中实际存储什么类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。
  • :下界通配符(Lower Bounds Wildcards)
    包括T在内的任何T的父类
List foo3 = new ArrayList();
List foo3 = new ArrayList();
List foo3 = new ArrayList(); //编译报错

  1. 读取操作通过以上给定的赋值语句,你不能保证读取到Integer,因为foo3可能指向List或者List
    唯一可以保证的是,你可以读取到Object或者Object子类的对象(你并不知道具体的子类是什么)。

  2. 写入操作通过以上给定的赋值语句,你可以插入Integer对象,因为上述声明的列表都支持Integer。你可以插入Integer的子类的对象,因为Integer的子类同时也是Integer,原因同上。

  3. 使用场景

    • PECS :生产者(Producer)使用extends,消费者(Consumer)使用super。
    1. 生产者使用extends
      如果你需要一个列表提供T类型的元素(即你想从列表中读取T类型的元素),你需要把这个列表声明成,比如List,因此你不能往该列表中添加任何元素。

    2. 消费者使用super
      如果需要一个列表使用T类型的元素(即你想把T类型的元素加入到列表中),你需要把这个列表声明成,比如List,因此你不能保证从中读取到的元素的类型。

    public static  void copy(List dest, List src) {
            int srcSize = src.size();
            if (srcSize > dest.size())
                throw new IndexOutOfBoundsException("Source does not fit in dest");
    
            if (srcSize < COPY_THRESHOLD ||
                (src instanceof RandomAccess && dest instanceof RandomAccess)) {
                for (int i=0; i di=dest.listIterator();
                ListIterator si=src.listIterator();
                for (int i=0; i

    java.util.Collections里的copy方法使用到了PECS原则,实现了对参数的保护。

    • 类型兼容
        class A {
    
        }
        class B extends A {
    
        }
        private void testFun () {
            ArrayList a = new ArrayList(); //编译报错
        }
    

    编译报错, 编译器在确定 ArrayList 元素类型的时候不会考虑 A 和 B 的继承关系,编译器无法承认第二行代码是合法的。为了解决这个问题引入了通配符的概念。
    ArrayList
    a = new ArrayList(); 改为 ArrayList a = new ArrayList(); 编译成功

    • 类型限制
      Rxjava Observable.map方法数据转换时,将源数据和返回数据使用了通配符限制
     public final  Observable map(Func1 func) {
            return lift(new OperatorMap(func));
        }
    

    自定义泛型类时候,限制参数类型

    public static class aaa   {
            public  void call(func f) {
                f.call(1);
            }
        }
        public static class bbb   {
            private T t;
            public  void call(func f) {
                f.call(t);
            }
        }
    
        public interface func {
            void call(T t);
        }
        public static void main() {
            new aaa().call(new func() {
                @Override
                public void call(Number number) {
                    
                }
            });
          
            new bbb().call(new func() {
                @Override
                public void call(Number o) {
                    
                }
            });
    
        }
    

    误区

     public static class bbb   {
            private T t;
            public  void call(func f) {
                f.call(t);
            }
        }
    
        public interface func {
            void call(T t);
        }
        public static void main() {
         
            // 这里传入子类  为什么没有报错
            new bbb().call(new func() {
                @Override
                public void call(Number o) {
                    
                }
            });
    
        }
    

    因为 new bbb() 这个一般叫做泛型构造方法, 和 new bbb() 是两回事

        public static class bbb   {
            private T t;
             bbb(E e){
    
            }
         
        }
        public static void main() {
            new bbb(1).call(new func() {
                @Override
                public void call(String o) {
    
                }
            });
    
        }
    

    正确写法应该是这样
    https://ask.csdn.net/questions/7711251?weChatOA=

    你可能感兴趣的:(java 泛型理解)