泛型

作者: ArcherZang | 来源:发表于2019-12-10 15:14 被阅读0次

所谓泛型,就是变量类型的参数化。
泛型是java1.5中引入的一个重要特征,通过引入泛型,可以使编译时类型安全,运行时更少抛出ClassCastException的可能。
方法、类或者接口中变量的类型定义成参数形式,然后在调用或者实例化时传入具体类型。

使用泛型时如果不提供参数类型,即泛型类没有参数化,系统只会警告,此时类型为Object。

        /**基础使用*/
        List<String> list = new ArrayList<String>();
//        list.add(1);
        list.add("aaa");
        //JDK1.7 版本可以省略后面的String
        List<String> jdkList = new ArrayList<>();
        jdkList.add("aaa");
//        jdkList.add(1);

注意点:

  1. <>中放的必须是引用数据类型, 不能是基本数据类型如int, double;
  2. 前后的泛型必须一致. 如上面所示,而不能是List<String> list = new ArrayList<Integer>()
    因此在JDK1.7时就推出了一个新特性叫菱形泛型(The Diamond), 就是说后面的泛型可以省略直接写成<>
  3. 不能创建泛型数组
  4. 无法从静态上下文中引用非静态 类型变量 T,即静态方法无法引用类的泛型,只能用方法泛型
使用泛型的好处
  1. 提高安全性: 将运行期的错误转换到编译期. 如果我们在对一个对象所赋的值不符合其泛型的规定, 就会编译报错。
  2. 省去强转的麻烦: 比如我们在使用List时, 如果我们不使用泛型
泛型中的标记符

E - Element (在集合中使用,因为集合中存放的是元素)
**T **- Type(Java 类)
**K **- Key(键)
**V **- Value(值)
**N **- Number(数值类型)
?- 表示不确定的java类型
**S、U、V ** - 2nd、3rd、4th types

Object跟这些标记符代表的java类型有啥区别呢?
Object是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型T、E等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。且泛型使用上限时可以使用父类的方法,这点Object做不到。

    @Test
    public void testFan(){
        /**基础使用*/
        List<String> list = new ArrayList<String>();
//        list.add(1);
        list.add("aaa");
        //JDK1.7 版本可以省略后面的<String>
        List<String> jdkList = new ArrayList<>();
        jdkList.add("aaa");
//        jdkList.add(1);

        /**泛型类*/
        String spring = "spring";
        TestFan<String> testFan = new TestFan(spring);
        Integer i_testE = 2;

        /**泛型方法和泛型类没有任何关系*/
        testFan.testU(i_testE);
        testFan.testT(i_testE);
        testFan.testPrintCurrentT();
        testFan.testStaticT(i_testE);

        /**泛型上限
         * 可以多边界
         * <T extends A & B & C>
         * 但是多边界使用时其实只能继承一个父类,
         * 并且要将他写在第一个位置上. 其他的都是其实现的接口, 如图十九:
         * 不在第一个位置上就会编译出错。
         * */
        TestFan<Integer> testFanInteger = new TestFan(1);
        TestFan<Float> testFanFloat = new TestFan(0.1f);
        TestFan<Double> testFanDouble = new TestFan(0.24d);
        TestFan<String> testFanString = new TestFan("nihao");
        Number number= new Number() {
            @Override
            public int intValue() {
                return 10;
            }

            @Override
            public long longValue() {
                return 10;
            }

            @Override
            public float floatValue() {
                return 10;
            }

            @Override
            public double doubleValue() {
                return 10;
            }

            @NonNull
            @Override
            public String toString() {
                return "number + 10";
            }
        };
        TestFan<Number> testFanNumber = new TestFan(number);
        testFan.testUpT(testFanInteger);
        testFan.testUpT(testFanFloat);
        testFan.testUpT(testFanDouble);
        testFan.testUpT(testFanNumber);

        //错误: 不兼容的类型: TestFan<String>无法转换为TestFan<? extends Number>
//        testFan.testUpT(testFanString);

        /**泛型下限*/
        TestFan<Integer> testFanDownInteger = new TestFan(1);
        TestFan<Float> testFanDownFloat = new TestFan(0.1f);
        TestFan<Number> testFanDownNumber = new TestFan(number);
        testFan.testDownT(testFanDownInteger);

        //错误: 不兼容的类型: TestFan<Float>无法转换为TestFan<? super Integer>
//        testFan.testDownT(testFanDownFloat);
        testFan.testDownT(testFanDownNumber);

        /**
         * 泛型接口
         */
        //1.实现时已处理
        InterfaceImplTow interfaceImplTow = new InterfaceImplTow();
        interfaceImplTow.testCall("wo yi shi xian FanXing");
        //2.实例化处理
        InterfaceImplOne<String> interfaceImplOne = new InterfaceImplOne();
        interfaceImplOne.testCall("shi li hua shi xian");

        /**泛型继承
         * 如果传入的变量类型是泛型的子类,可以传入
         * */
        TestFan<Number> testFanExtends = new TestFan<>(1);
        Integer integer =  1;
        Double aDouble = 2.1d;
        Float aFloat = 3.1f;
        testFanExtends.testClassFan(integer);
        testFanExtends.testClassFan(aDouble);
        testFanExtends.testClassFan(aFloat);
        //错误: 不兼容的类型: String无法转换为Number
//        testFanExtends.setId("String");

        /**数组不能有泛型*/
        //错误: 创建泛型数组

        /**Person 和 PersonObject区别
         * 展示了用泛型比用Object的好处,
         * 可以使用父类的方法*/
     }

     public class TestFan<T> {
         private T t;
         public TestFan(T t) {
             this.t = t;
         }

         //这里的T来自类的T
         public String testClassFan(T t) {
             this.t = t;
             return t.toString();
         }

         public <U> U testU(U e){
             System.out.println(e.toString());
             return e;
         }

         //这里是泛型方法的T与类中的T无任何关系
         public<T> T testT(T t1){
             System.out.println(t1.toString());
             return t1;
         }

         public void testPrintCurrentT(){
             System.out.println(t.toString());
         }

         //错误: 无法从静态上下文中引用非静态 类型变量 T
//         public static void testStaticT(T tStatic){
//             System.out.println(tStatic.toString());
//         }

         public static <F> void testStaticT(F tStatic){
             System.out.println(tStatic.toString());
         }

         public void testUpT(TestFan<? extends Number> testFan){
             testFan.testPrintCurrentT();
         }

         public void testDownT(TestFan<? super Integer> testFan){
             testFan.testPrintCurrentT();
         }
     }

    public interface TestFanInterface<T> {
        void testCall(T t);
    }


    public class InterfaceImplOne<T> implements TestFanInterface<T> {
         @Override
         public void testCall(T t) {
            System.out.println(t.toString());
         }
    }

     public class InterfaceImplTow implements TestFanInterface<String> {
         @Override
         public void testCall(String s) {
             System.out.println(s);
         }
     }

//    public class Person<T extends String> {
//        private T name;
//
//        public Person(T id) {
//            this.name = id;
//        }
//
//        public T getId() {
//            return name;
//        }
//
//        public void setId(T id) {
//            this.name = id;
//        }
//
//        public boolean isContainsString(String a){
//            return name.contains(a);
//        }
//    }
//
//    public class PersonObject {
//        private Object name;
//        public PersonObject(Object id) {
//            this.name = id;
//        }
//
//        public Object getId() {
//            return name;
//        }
//
//        public void setId(Object id) {
//            this.name = id;
//        }
//
//        public boolean isContainsString(String a){
//            return name.contains(a);
//        }
//    }
?和 上下边界问题

通配符不能出现在类声明上,编译器会报错。
单独的? 即表示 ?extends object。

参考下面的代码会发现:
  <? extends Person> 上边界通配符,只能get不能Add,IN。
  <? super Person>下边界通配符,只能add不能get,OUT。
  IN 表示只读,不能存数据;OUT表示存数据,不能读。官网进行了in 和 out说明

上下边界的出现是为了解决泛型无法逆变与协变的问题(关于逆变与协变问参考文章)。
  Number num = new Integer(1);
  ArrayList<Number> list = new ArrayList<Integer>(); //type mismatch编译器报错

上下边界使用场景:方法参数类型,因为通常使用变量使用我需要既能读也能存

        List<? super Student> listDown = new ArrayList<>();
        List<? extends Person> listUp;

        /**
         * 下界OUT
         */
//        listDown.add(new Person("001"));
        listDown.add(new Student("002"));
        //编译器报错类型不一致
//        Person personDown = listDown.get(0);
        //------------分界线-------------
        /**
         * 上界IN
         */
        ArrayList arrayList = new ArrayList();
        arrayList.add(new Person("003"));
        listUp = arrayList;
//        listUp.add(new Person("001"));
//        listUp.add(new Student("002"));
        Person personUp = listUp.get(0);
        System.out.println(personUp.getName());

相关文章

  • 泛型 & 注解 & Log4J日志组件

    掌握的知识 : 基本用法、泛型擦除、泛型类/泛型方法/泛型接口、泛型关键字、反射泛型(案例) 泛型 概述 : 泛型...

  • 【泛型】通配符与嵌套

    上一篇 【泛型】泛型的作用与定义 1 泛型分类 泛型可以分成泛型类、泛型方法和泛型接口 1.1 泛型类 一个泛型类...

  • 泛型的使用

    泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法 泛型类 泛型接口 泛型通配符 泛型方法 静态方法与...

  • Java 泛型

    泛型类 例如 泛型接口 例如 泛型通配符 泛型方法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型上下边...

  • 探秘 Java 中的泛型(Generic)

    本文包括:JDK5之前集合对象使用问题泛型的出现泛型应用泛型典型应用自定义泛型——泛型方法自定义泛型——泛型类泛型...

  • Web笔记-基础加强

    泛型高级应用 自定义泛型方法 自定义泛型类 泛型通配符? 泛型的上下限 泛型的定义者和泛型的使用者 泛型的定义者:...

  • 重走安卓进阶路——泛型

    ps.原来的标题 为什么我们需要泛型? 泛型类、泛型接口和泛型方法(泛型类和泛型接口的定义与泛型方法辨析); 如何...

  • Kotlin泛型的高级特性(六)

    泛型的高级特性1、泛型实化2、泛型协变3、泛型逆变 泛型实化 在Java中(JDK1.5之后),泛型功能是通过泛型...

  • Java 19-5.1泛型

    泛型类定义泛型类可以规定传入对象 泛型类 和泛型方法 泛型接口 如果实现类也无法确定泛型 可以在继承类中确定泛型:

  • 【Swift】泛型常见使用

    1、Swift泛型4种 泛型函数泛型类型泛型协议泛型约束 2、泛型约束3种 继承约束:泛型类型 必须 是某个类的子...

网友评论

      本文标题:泛型

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