Java基础知识之泛型简单介绍

Posted smileNicky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础知识之泛型简单介绍相关的知识,希望对你有一定的参考价值。

1、什么是java泛型?

java泛型:英文名称是generics,泛型是jdk5引入的一个新特性,java泛型的本质就是参数化类型,就是所有的操作数据类型被指定为一个参数。对参数化类型进行操作的实体(例如类、接口或方法)称为泛型实体。

2、java泛型类

泛型类:必须先声明,再使用;声明是通过<T,E, ...>实现的;约定泛型可以使用单个大写字母T、E、K、V等表示


import java.lang.reflect.Field;

public class GenericsSimpleExample {

    public static void main(String[] args) {
        A<String , Integer> a0 = new A<>();
        a0.t= "testStr";
        A<Integer , Integer> a1 = new A<>();
        a1.t = 100;
         //  泛型参数在使用时要引用数据类型,不能是基本数据类型,比如int等等
        //A<Integer , int> a2 = new A<>();

        // 泛型类如果不指定具体的参数类型,默认数据类型是object
        Class<A> cls = A.class;
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName() + ":" + field.getType().getSimpleName());
        }

        // 泛型类在具体实现上可以看出不同数据类型,实践上是相同的数据类型,可以通过hashcode进行验证
        System.out.println(a0.getClass().hashCode());
        System.out.println(a1.getClass().hashCode());
    }

    static class A <T , E> {
        public T t;
        public void test0(T  t) {

        }
    }

}

注意要点:

  • 泛型类的参数类型不能是基本数据类型,要使用引用数据类型
  • 泛型类在不指定具体数据类型时候,默认是使用object类型的
  • 泛型类具体使用上可以使用不同的数据类型,实践上是相同的数据类型

3、从泛型类派生子类

  • 1、子类是泛型的情况,子类要和父类的泛型类型一致
class A<T> extends B<T>{}
  • 2、子类不是泛型的情况,父类要明确泛型的数据类型
class A extends  B<String>{}

4、泛型接口

泛型接口语法:

interface 接口名称 <泛型标识,泛型标识, ...>{
  泛型标识 方法名();
  ...
}
  • 1、实现类也是泛型类,泛型类型要和接口一致
interface B <T,V> {}
class A<T,V> implements B<T,V>{}
  • 2、实现类不是泛型类,接口要指定具体的类型
class B implements B<String,Integer>{}

5、泛型方法

泛型方法语法:

修饰符 <T,E,...> 返回值类型 方法名 (形参列表){
  方法体;
}

泛型方法特征:

  • 只有声明了<T>的方法才是泛型方法,仅仅传参使用了泛型的,不是泛型方法
  • 和泛型类一样,也可以使用K、V、T、E等等参数表示泛型

public class GenericsMethodExample {

    public static void main(String[] args) {
        A0 a0 = new A0();
        a0.test0("hello");

        A1<Integer> a1 = new A1<>();
        a1.test("hi", "hello");
        A1.test1("hello world");

    }

    static class A0 {
        public <T, E> T test0(T t) {
            System.out.println("t = " + t);
            return null;
        }
    }

    static class A1<K> {

        /**
         * 泛型方法的类型和泛型类一致时,以具体方法的为准
         * @param k
         * @param t
         */
        public <T, K> T test(T t , K k) {
            System.out.println("t = " + t);
            System.out.println("k = " + k);
            return null;
        }

        /**
         * static方法要使用泛型,必须指定为泛型方法加上{@code <K>}
         * @param k
         */
        public static <K> void test1(K k) {

        }
    }
}

归纳:

  • 泛型方法的类型和泛型类一致时,以具体方法的为准
  • static方法要使用泛型,必须指定为泛型方法加上

6、泛型通配符

类型通配符一般是使用?代替具体的类型实参,所以类型通配符是类型实参,而不是类型形参

public class GenericsWildcardExample {

    public static void main(String[] args) {
        A<String> a0 = new A<>();
        show(a0);

        A<Integer> a1 = new A<>();
        show(a1);

    }

    public static void show(A<?> a){
        System.out.println(a.getClass());
    }

    static class A<T> {

    }
}

7、类型通配符上限

语法:

/接口 <? extends 实参类型>

要求改泛型类型只能是实参类型或者实参的子类类型


  public class GenericsWildcardExample {

    public static void main(String[] args) {
 
        A<A1> a11 = new A<>();
        A<A2> a12 = new A<>();
        A<A3> a13 = new A<>();

        // 只能使用A2及其子类
        show0(a12);
        show0(a13);
    }

    public static void show0(A<? extends A2> a) {}

    static class A<T> {

    }

    static class A1{}

    static class A2 extends A1{}

    static class A3 extends A2{}
}

8、类型通配符下限

语法:

/接口 <? super 实参类型>

要求改泛型类型只能是实参类型或者实参的父类类型

public class GenericsWildcardExample {

    public static void main(String[] args) {

        A<A1> a11 = new A<>();
        A<A2> a12 = new A<>();
        A<A3> a13 = new A<>();

        // 只能使用A2及其父类
        show1(a11);
        show1(a12);

    }

    public static void show1(A<? super A2> a){}

    static class A<T> {

    }

    static class A1{}

    static class A2 extends A1{}

    static class A3 extends A2{}
}

9、什么是泛型擦除?

泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型有关的信息会被擦除
掉,我们称之为 类型擦除

9.1、无限制类型擦除


import java.lang.reflect.Field;


public class GenericsWipeExample {

    public static void main(String[] args) {
        Class<?> cls0 = A.class;
        Field[] fields = cls0.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName() + ":" + field.getType().getSimpleName());
        }

    }


    static class A <T>{
        T t;
    }
}

打印:

t:Object

9.2、有限制类型擦除


import java.lang.reflect.Field;


public class GenericsWipeExample {

    public static void main(String[] args) {
 

        Class<?> cls1 = A1.class;
        Field[] fields1 = cls1.getDeclaredFields();
        for (Field field : fields1) {
            System.out.println(field.getName() + ":" + field.getType().getSimpleName());
        }

    }

    static  class A1<T extends Number> {
        T t;
    }

}

打印:

t:Number

9.3、方法类型擦除


import java.lang.reflect.Method;

public class GenericsWipeExample {

    public static void main(String[] args) {
      

        Class<?> cls2 = A2.class;
        Method[] methods = cls2.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + ":" + method.getReturnType().getSimpleName());
        }
    }

    static class A2<T extends Number> {
        T t;
        public <K extends Number> K test(K k) {
            return null;
        }
    }

}

打印

test:Number

9.4、桥接方法

interface MyInter<T>{
  T fun1();
}
class DD implements MyInter<String>{
  @Override
  public String fun1() {
    return null;
 }
}

import java.lang.reflect.Method;


public class GenericsWipeExample {

    public static void main(String[] args) {
   
        Class<?> cls3 = A3.class;
        Method[] methodss = cls3.getDeclaredMethods();
        for (Method method : methodss) {
            System.out.println(method.getName() + ":" + method.getReturnType().getSimpleName());
        }
    }

    interface MyInter<T>{
        T test();
    }
    class A3 implements MyInter<String> {
        @Override
        public String test() {
            return null;
        }
    }

}

打印:

test:String
test:Object

10、泛型和反射

 Class<?> cls0 = A.class;
Field[] fields = cls0.getDeclaredFields();
for (Field field : fields) {
    System.out.println(field.getName() + ":" + field.getType().getSimpleName());
}

以上是关于Java基础知识之泛型简单介绍的主要内容,如果未能解决你的问题,请参考以下文章

Java基础之泛型

javaSE之泛型(Generics)

Java基础之泛型的使用

Java基础知识(JAVA之泛型)

java5核心基础之泛型-泛型作用于编译阶段-怎样将String对象传入Integer类型的泛型对象中?

Java8基础之泛型