java 泛型

it2026-08-08  1

函数返回值泛型<T> T 与 T的用法

public class myTest<T> { private <T> T method1(List<T> data) { ...// 输入的T类型可以随意 } private T method2(List<T> data) { ...// 输入的T类型受到主类myTestt<T>的限制,与T保持一致 } 转自 https://blog.csdn.net/weixin_42034217/article/details/108536251?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param

 

泛型 <T>T 与 T 的区别

方法返回前的<T> 是告诉编译器,当前方法的值传入类型可以和类初始化的泛型类型不同,也是就是该方法的泛型类可以自定义,不需要跟类初始化的泛型类相同. package com.jt.test; import java.util.ArrayList; import java.util.List; /** * @Description * 有的方法返回值为 <T> T ,有的方法返回值为 T ,区别在那里 ? **/ public class Request<E> { public <T> T getObject(Class<T> tClass) throws IllegalAccessException, InstantiationException { T t = tClass.newInstance(); return t; } /** * 方法返回前的 <T> 是告诉编译器,当前方法的值传入类型可以和类初始化的泛型类型不同, * 也是就是该方法的泛型类可以自定义,不需要跟类初始化的泛型类相同 * * 参数 T * 第一个 表示是泛型 * 第二个 表示是返回是T类型的数据 * 第三个 表示限制参数类型为T * @param data * @param <T> * @return */ private <T> T getListFirst(List<T> data) { if (data == null || data.size() == 0) { return null; } return data.get(0); } /** * 这个只能传T类型的数据 * @param data * @return */ private E getListFirst2(List<E> data) { if (data == null || data.size() == 0) { return null; } return data.get(0); } public static void main(String[] args) { List<Integer> data = new ArrayList<>(); List<String> data2 = new ArrayList<>(); // 入参由List<T>的T 决定,因为返回值为<T> T ,所以入参不受 Request<T> 影响 Integer a = new Request<String>().getListFirst(data); // 编译出错,入参由Request<T> T的决定,受Request<T>影响 //new Request<String>().getListFirst2(data); // 没什么区别 String aa = new Request<String>().getListFirst(data2); String bb = new Request<String>().getListFirst2(data2); } } 转自 https://blog.csdn.net/qianzhitu/article/details/107962657

<T> 和 <?> 的 区别,首先要区分开两种不同的场景

<T> 主要用于声明一个泛型类或泛型方法

<?> 主要用于使用泛型类或泛型方法

 

================================================================================================

Java泛型<T> T与T的使用方法详解

泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。 在集合框架(Collection framework)中泛型的身影随处可见。例如,Map 类允许向一个 Map 类型的实例添加任意类的对象,即使最常见的情况在给定映射(map)中保存一个string键值对。

命名类型参数

对于常见的泛型模式,推荐的泛型类型变量:

E:元素(Element),多用于java集合框架K:关键字(Key)N:数字(Number)T:类型(Type)V:值(Value)

大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦除,正确理解泛型概念的首要前提是理解类型擦除。Java 泛型是如何工作的?什么是类型擦除?答:泛型是通过类型擦除来实现的,编译器在编译时擦除了所有泛型类型相关的信息,所以在运行时不存在任何泛型类型相关的信息,譬如 List<Integer> 在运行时仅用一个 List 来表示,这样做的动机是兼容 Java 1.5 之前版本。

泛型擦除具体来说就是在编译成字节码时首先进行类型检查,然后进行类型擦除(即所有类型参数都用他们的限定类型替换,包括类、变量和方法),最后如果类型擦除和多态性发生冲突,就在子类中使用桥接方法解决;如果调用泛型方法的返回类型被擦除,则在调用该方法时插入强制类型转换。在类型擦除中,编译器确保不会创建额外的类,并且没有运行时开销。

类型擦除原则

用通用类型的类型参数替换其绑定的有界类型参数;如果使用无界类型参数,则使用Object替换类型参数;插入类型转换以实现类型安全;生成桥接方法以在扩展通用类型中保持多态。

<T> T 和T的区别:T是Type的首字母缩写;<T> T 表示“返回值”是一个泛型,传入什么类型,就返回什么类型;而单独的“T”表示限制传入的参数类型。

<T> T 的用法

这个<T> T 表示返回值T的类型是泛型,T是一个占位符,用来告诉编译器,这个东西是先给我留着, 等我编译的时候再告诉你是什么类型。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

import org.springframework.util.CollectionUtils;

import java.util.ArrayList;

import java.util.List;

public class Demo {

  public static void main(String[] args) {

    Demo demo = new Demo();

    //获取string类型

    List<String> array = new ArrayList<String>();

    array.add("test");

    array.add("doub");

    String str = demo.getListFisrt(array);

    System.out.println(str);

    //获取Integer类型

    List<Integer> nums = new ArrayList<Integer>();

    nums.add(31);

    nums.add(32);

    Integer num = demo.getListFisrt(nums);

    System.out.println(num);

  }

 

  /**

   * 这个<T> T 可以传入任何类型的List

   * 关于参数T

   * 第一个 表示是泛型

   * 第二个 表示返回的是T类型的数据

   * 第三个 限制参数类型为T

   *

   * @param data

   * @return

   */

  private <T> T getListFisrt(List<T> data) {

    if (CollectionUtils.isEmpty(data)) {

      return null;

    }

    return data.get(0);

  }

}

T 的用法

单独的T表示限制参数的类型。这种用法一般多用于共同操作一个类对象,然后获取里面的集合信息。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

import java.util.ArrayList;

import java.util.List;

 

public class Demo2<T> {

 

  public static void main(String[] args) {

    //限制T 为String 类型

    Demo2<String> demo = new Demo2<String>();

    List<String> array = new ArrayList<String>();

    array.add("Tom");

    array.add("河南");

    String str = demo.getListFisrt(array);

    System.out.println(str);

 

    //获取Integer类型

    Demo2<Integer> demo2 = new Demo2<Integer>();

    List<Integer> nums = new ArrayList<Integer>();

    nums.add(12);

    nums.add(13);

    Integer num = demo2.getListFisrt(nums);

    System.out.println(num);

  }

 

  /**

   * 这个只能传递T类型的数据

   * 返回值 就是Demo<T> 实例化传递的对象类型

   *

   * @param data

   * @return

   */

  private T getListFisrt(List<T> data) {

    if (data == null || data.size() == 0) {

      return null;

    }

    return data.get(0);

  }

}

https://www.jb51.net/article/189936.htm

 

Java泛型详解

一,打破砂锅问到底

泛型存在的意义? 泛型类,泛型接口,泛型方法如何定义? 如何限定类型变量? 泛型中使用的约束和局限性有哪些? 泛型类型的继承规则是什么? 泛型中的通配符类型是什么? 如何获取泛型的参数类型? 虚拟机是如何实现泛型的? 在日常开发中是如何运用泛型的?

Java泛型详解.png

二,晓之以理动之以码

1,泛型的定义以及存在意义

泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。 例如:GenericClass<T>{}

一些常用的泛型类型变量: E:元素(Element),多用于java集合框架 K:关键字(Key) N:数字(Number) T:类型(Type) V:值(Value)

如果要实现不同类型的加法,每种类型都需要重载一个add方法

 

package com.jay.java.泛型.needGeneric; /** * Author:Jay On 2019/5/9 16:06 * <p> * Description: 为什么使用泛型 */ public class NeedGeneric1 { private static int add(int a, int b) { System.out.println(a + "+" + b + "=" + (a + b)); return a + b; } private static float add(float a, float b) { System.out.println(a + "+" + b + "=" + (a + b)); return a + b; } private static double add(double a, double b) { System.out.println(a + "+" + b + "=" + (a + b)); return a + b; } private static <T extends Number> double add(T a, T b) { System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue())); return a.doubleValue() + b.doubleValue(); } public static void main(String[] args) { NeedGeneric1.add(1, 2); NeedGeneric1.add(1f, 2f); NeedGeneric1.add(1d, 2d); NeedGeneric1.add(Integer.valueOf(1), Integer.valueOf(2)); NeedGeneric1.add(Float.valueOf(1), Float.valueOf(2)); NeedGeneric1.add(Double.valueOf(1), Double.valueOf(2)); } }

取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易现“java.lang. ClassCast Exception”异常。

 

package com.jay.java.泛型.needGeneric; import java.util.ArrayList; import java.util.List; /** * Author:Jay On 2019/5/9 16:23 * <p> * Description: 为什么要使用泛型 */ public class NeedGeneric2 { static class C{ } public static void main(String[] args) { List list=new ArrayList(); list.add("A"); list.add("B"); list.add(new C()); list.add(100); //1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。 //2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。 for (int i = 0; i < list.size(); i++) { // System.out.println(list.get(i)); String value= (String) list.get(i); System.out.println(value); } } }

所以使用泛型的意义在于1,适用于多种数据类型执行相同的代码(代码复用) 2, 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)

2,泛型类的使用

定义一个泛型类:public class GenericClass<T>{}

 

package com.jay.java.泛型.DefineGeneric; /** * Author:Jay On 2019/5/9 16:49 * <p> * Description: 泛型类 */ public class GenericClass<T> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } public static void main(String[] args) { GenericClass<String> genericClass=new GenericClass<>(); genericClass.setData("Generic Class"); System.out.println(genericClass.getData()); } }

3,泛型接口的使用

定义一个泛型接口:public interface GenericIntercace<T>{}

 

/** * Author:Jay On 2019/5/9 16:57 * <p> * Description: 泛型接口 */ public interface GenericIntercace<T> { T getData(); }

实现泛型接口方式一:public class ImplGenericInterface1<T> implements GenericIntercace<T>

 

/** * Author:Jay On 2019/5/9 16:59 * <p> * Description: 泛型接口实现类-泛型类实现方式 */ public class ImplGenericInterface1<T> implements GenericIntercace<T> { private T data; private void setData(T data) { this.data = data; } @Override public T getData() { return data; } public static void main(String[] args) { ImplGenericInterface1<String> implGenericInterface1 = new ImplGenericInterface1<>(); implGenericInterface1.setData("Generic Interface1"); System.out.println(implGenericInterface1.getData()); } }

实现泛型接口方式二:public class ImplGenericInterface2 implements GenericIntercace<String> {}

 

/** * Author:Jay On 2019/5/9 17:01 * <p> * Description: 泛型接口实现类-指定具体类型实现方式 */ public class ImplGenericInterface2 implements GenericIntercace<String> { @Override public String getData() { return "Generic Interface2"; } public static void main(String[] args) { ImplGenericInterface2 implGenericInterface2 = new ImplGenericInterface2(); System.out.println(implGenericInterface2.getData()); } }

4,泛型方法的使用

定义一个泛型方法: private static<T> TgenericAdd(T a, T b) {}

 

/** * Author:Jay On 2019/5/10 10:46 * <p> * Description: 泛型方法 */ public class GenericMethod1 { private static int add(int a, int b) { System.out.println(a + "+" + b + "=" + (a + b)); return a + b; } private static <T> T genericAdd(T a, T b) { System.out.println(a + "+" + b + "="+a+b); return a; } public static void main(String[] args) { GenericMethod1.add(1, 2); GenericMethod1.<String>genericAdd("a", "b"); } }

 

/** * Author:Jay On 2019/5/10 16:22 * <p> * Description: 泛型方法 */ public class GenericMethod3 { static class Animal { @Override public String toString() { return "Animal"; } } static class Dog extends Animal { @Override public String toString() { return "Dog"; } } static class Fruit { @Override public String toString() { return "Fruit"; } } static class GenericClass<T> { public void show01(T t) { System.out.println(t.toString()); } public <T> void show02(T t) { System.out.println(t.toString()); } public <K> void show03(K k) { System.out.println(k.toString()); } } public static void main(String[] args) { Animal animal = new Animal(); Dog dog = new Dog(); Fruit fruit = new Fruit(); GenericClass<Animal> genericClass = new GenericClass<>(); //泛型类在初始化时限制了参数类型 genericClass.show01(dog); // genericClass.show01(fruit); //泛型方法的参数类型在使用时指定 genericClass.show02(dog); genericClass.show02(fruit); genericClass.<Animal>show03(animal); genericClass.<Animal>show03(dog); genericClass.show03(fruit); // genericClass.<Dog>show03(animal); } }

5,限定泛型类型变量

1,对类的限定:public class TypeLimitForClass<T extends List & Serializable>{} 2,对方法的限定:public static<T extends Comparable<T>>T getMin(T a, T b) {}

 

/** * Author:Jay On 2019/5/10 16:38 * <p> * Description: 类型变量的限定-方法 */ public class TypeLimitForMethod { /** * 计算最小值 * 如果要实现这样的功能就需要对泛型方法的类型做出限定 */ // private static <T> T getMin(T a, T b) { // return (a.compareTo(b) > 0) ? a : b; // } /** * 限定类型使用extends关键字指定 * 可以使类,接口,类放在前面接口放在后面用&符号分割 * 例如:<T extends ArrayList & Comparable<T> & Serializable> */ public static <T extends Comparable<T>> T getMin(T a, T b) { return (a.compareTo(b) < 0) ? a : b; } public static void main(String[] args) { System.out.println(TypeLimitForMethod.getMin(2, 4)); System.out.println(TypeLimitForMethod.getMin("a", "r")); } }

 

/** * Author:Jay On 2019/5/10 17:02 * <p> * Description: 类型变量的限定-类 */ public class TypeLimitForClass<T extends List & Serializable> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } public static void main(String[] args) { ArrayList<String> stringArrayList = new ArrayList<>(); stringArrayList.add("A"); stringArrayList.add("B"); ArrayList<Integer> integerArrayList = new ArrayList<>(); integerArrayList.add(1); integerArrayList.add(2); integerArrayList.add(3); TypeLimitForClass<ArrayList> typeLimitForClass01 = new TypeLimitForClass<>(); typeLimitForClass01.setData(stringArrayList); TypeLimitForClass<ArrayList> typeLimitForClass02 = new TypeLimitForClass<>(); typeLimitForClass02.setData(integerArrayList); System.out.println(getMinListSize(typeLimitForClass01.getData().size(), typeLimitForClass02.getData().size())); } public static <T extends Comparable<T>> T getMinListSize(T a, T b) { return (a.compareTo(b) < 0) ? a : b; }

6,泛型中的约束和局限性

1,不能实例化泛型类 2,静态变量或方法不能引用泛型类型变量,但是静态泛型方法是可以的 3,基本类型无法作为泛型类型 4,无法使用instanceof关键字或==判断泛型类的类型 5,泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的 6,泛型数组可以声明但无法实例化 7,泛型类不能继承Exception或者Throwable 8,不能捕获泛型类型限定的异常但可以将泛型限定的异常抛出

 

/** * Author:Jay On 2019/5/10 17:41 * <p> * Description: 泛型的约束和局限性 */ public class GenericRestrict1<T> { static class NormalClass { } private T data; /** * 不能实例化泛型类 * Type parameter 'T' cannot be instantiated directly */ public void setData() { //this.data = new T(); } /** * 静态变量或方法不能引用泛型类型变量 * 'com.jay.java.泛型.restrict.GenericRestrict1.this' cannot be referenced from a static context */ // private static T result; // private static T getResult() { // return result; // } /** * 静态泛型方法是可以的 */ private static <K> K getKey(K k) { return k; } public static void main(String[] args) { NormalClass normalClassA = new NormalClass(); NormalClass normalClassB = new NormalClass(); /** * 基本类型无法作为泛型类型 */ // GenericRestrict1<int> genericRestrictInt = new GenericRestrict1<>(); GenericRestrict1<Integer> genericRestrictInteger = new GenericRestrict1<>(); GenericRestrict1<String> genericRestrictString = new GenericRestrict1<>(); /** * 无法使用instanceof关键字判断泛型类的类型 * Illegal generic type for instanceof */ // if(genericRestrictInteger instanceof GenericRestrict1<Integer>){ // return; // } /** * 无法使用“==”判断两个泛型类的实例 * Operator '==' cannot be applied to this two instance */ // if (genericRestrictInteger == genericRestrictString) { // return; // } /** * 泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的 */ System.out.println(normalClassA == normalClassB);//false System.out.println(genericRestrictInteger == genericRestrictInteger);// System.out.println(genericRestrictInteger.getClass() == genericRestrictString.getClass()); //true System.out.println(genericRestrictInteger.getClass());//com.jay.java.泛型.restrict.GenericRestrict1 System.out.println(genericRestrictString.getClass());//com.jay.java.泛型.restrict.GenericRestrict1 /** * 泛型数组可以声明但无法实例化 * Generic array creation */ GenericRestrict1<String>[] genericRestrict1s; // genericRestrict1s = new GenericRestrict1<String>[10]; genericRestrict1s = new GenericRestrict1[10]; genericRestrict1s[0]=genericRestrictString; } }

 

/** * Author:Jay On 2019/5/10 18:45 * <p> * Description: 泛型和异常 */ public class GenericRestrict2 { private class MyException extends Exception { } /** * 泛型类不能继承Exception或者Throwable * Generic class may not extend 'java.lang.Throwable' */ // private class MyGenericException<T> extends Exception { // } // // private class MyGenericThrowable<T> extends Throwable { // } /** * 不能捕获泛型类型限定的异常 * Cannot catch type parameters */ public <T extends Exception> void getException(T t) { // try { // // } catch (T e) { // // } } /** *可以将泛型限定的异常抛出 */ public <T extends Throwable> void getException(T t) throws T { try { } catch (Exception e) { throw t; } } }

7,泛型类型继承规则

1,对于泛型参数是继承关系的泛型类之间是没有继承关系的 2,泛型类可以继承其它泛型类,例如: public class ArrayList<E> extends AbstractList<E> 3,泛型类的继承关系在使用中同样会受到泛型类型的影响

 

/** * Author:Jay On 2019/5/10 19:13 * <p> * Description: 泛型继承规则测试类 */ public class GenericInherit<T> { private T data1; private T data2; public T getData1() { return data1; } public void setData1(T data1) { this.data1 = data1; } public T getData2() { return data2; } public void setData2(T data2) { this.data2 = data2; } public static <V> void setData2(GenericInherit<Father> data2) { } public static void main(String[] args) { // Son 继承自 Father Father father = new Father(); Son son = new Son(); GenericInherit<Father> fatherGenericInherit = new GenericInherit<>(); GenericInherit<Son> sonGenericInherit = new GenericInherit<>(); SubGenericInherit<Father> fatherSubGenericInherit = new SubGenericInherit<>(); SubGenericInherit<Son> sonSubGenericInherit = new SubGenericInherit<>(); /** * 对于传递的泛型类型是继承关系的泛型类之间是没有继承关系的 * GenericInherit<Father> 与GenericInherit<Son> 没有继承关系 * Incompatible types. */ father = new Son(); // fatherGenericInherit=new GenericInherit<Son>(); /** * 泛型类可以继承其它泛型类,例如: public class ArrayList<E> extends AbstractList<E> */ fatherGenericInherit=new SubGenericInherit<Father>(); /** *泛型类的继承关系在使用中同样会受到泛型类型的影响 */ setData2(fatherGenericInherit); // setData2(sonGenericInherit); setData2(fatherSubGenericInherit); // setData2(sonSubGenericInherit); } private static class SubGenericInherit<T> extends GenericInherit<T> { }

8,通配符类型

1,<? extends Parent> 指定了泛型类型的上届 2,<? super Child> 指定了泛型类型的下届 3, <?> 指定了没有限制的泛型类型

通配符测试类结构.png

 

/** * Author:Jay On 2019/5/10 19:51 * <p> * Description: 泛型通配符测试类 */ public class GenericByWildcard { private static void print(GenericClass<Fruit> fruitGenericClass) { System.out.println(fruitGenericClass.getData().getColor()); } private static void use() { GenericClass<Fruit> fruitGenericClass = new GenericClass<>(); print(fruitGenericClass); GenericClass<Orange> orangeGenericClass = new GenericClass<>(); //类型不匹配,可以使用<? extends Parent> 来解决 // print(orangeGenericClass); } /** * <? extends Parent> 指定了泛型类型的上届 */ private static void printExtends(GenericClass<? extends Fruit> genericClass) { System.out.println(genericClass.getData().getColor()); } public static void useExtend() { GenericClass<Fruit> fruitGenericClass = new GenericClass<>(); printExtends(fruitGenericClass); GenericClass<Orange> orangeGenericClass = new GenericClass<>(); printExtends(orangeGenericClass); GenericClass<Food> foodGenericClass = new GenericClass<>(); //Food是Fruit的父类,超过了泛型上届范围,类型不匹配 // printExtends(foodGenericClass); //表示GenericClass的类型参数的上届是Fruit GenericClass<? extends Fruit> extendFruitGenericClass = new GenericClass<>(); Apple apple = new Apple(); Fruit fruit = new Fruit(); /* * 道理很简单,? extends X 表示类型的上界,类型参数是X的子类,那么可以肯定的说, * get方法返回的一定是个X(不管是X或者X的子类)编译器是可以确定知道的。 * 但是set方法只知道传入的是个X,至于具体是X的那个子类,不知道。 * 总结:主要用于安全地访问数据,可以访问X及其子类型,并且不能写入非null的数据。 */ // extendFruitGenericClass.setData(apple); // extendFruitGenericClass.setData(fruit); fruit = extendFruitGenericClass.getData(); } /** * <? super Child> 指定了泛型类型的下届 */ public static void printSuper(GenericClass<? super Apple> genericClass) { System.out.println(genericClass.getData()); } public static void useSuper() { GenericClass<Food> foodGenericClass = new GenericClass<>(); printSuper(foodGenericClass); GenericClass<Fruit> fruitGenericClass = new GenericClass<>(); printSuper(fruitGenericClass); GenericClass<Apple> appleGenericClass = new GenericClass<>(); printSuper(appleGenericClass); GenericClass<HongFuShiApple> hongFuShiAppleGenericClass = new GenericClass<>(); // HongFuShiApple 是Apple的子类,达不到泛型下届,类型不匹配 // printSuper(hongFuShiAppleGenericClass); GenericClass<Orange> orangeGenericClass = new GenericClass<>(); // Orange和Apple是兄弟关系,没有继承关系,类型不匹配 // printSuper(orangeGenericClass); //表示GenericClass的类型参数的下界是Apple GenericClass<? super Apple> supperAppleGenericClass = new GenericClass<>(); supperAppleGenericClass.setData(new Apple()); supperAppleGenericClass.setData(new HongFuShiApple()); /* * ? super X 表示类型的下界,类型参数是X的超类(包括X本身), * 那么可以肯定的说,get方法返回的一定是个X的超类,那么到底是哪个超类?不知道, * 但是可以肯定的说,Object一定是它的超类,所以get方法返回Object。 * 编译器是可以确定知道的。对于set方法来说,编译器不知道它需要的确切类型,但是X和X的子类可以安全的转型为X。 * 总结:主要用于安全地写入数据,可以写入X及其子类型。 */ // supperAppleGenericClass.setData(new Fruit()); //get方法只会返回一个Object类型的值。 Object data = supperAppleGenericClass.getData(); } /** * <?> 指定了没有限定的通配符 */ public static void printNonLimit(GenericClass<?> genericClass) { System.out.println(genericClass.getData()); } public static void useNonLimit() { GenericClass<Food> foodGenericClass = new GenericClass<>(); printNonLimit(foodGenericClass); GenericClass<Fruit> fruitGenericClass = new GenericClass<>(); printNonLimit(fruitGenericClass); GenericClass<Apple> appleGenericClass = new GenericClass<>(); printNonLimit(appleGenericClass); GenericClass<?> genericClass = new GenericClass<>(); //setData 方法不能被调用, 甚至不能用 Object 调用; // genericClass.setData(foodGenericClass); // genericClass.setData(new Object()); //返回值只能赋给 Object Object object = genericClass.getData(); } }

9,获取泛型的参数类型

Type是什么 这里的Type指java.lang.reflect.Type, 是Java中所有类型的公共高级接口, 代表了Java中的所有类型. Type体系中类型的包括:数组类型(GenericArrayType)、参数化类型(ParameterizedType)、类型变量(TypeVariable)、通配符类型(WildcardType)、原始类型(Class)、基本类型(Class), 以上这些类型都实现Type接口.

参数化类型,就是我们平常所用到的泛型List、Map; 数组类型,并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[] ; 通配符类型, 指的是<?>, <? extends T>等等 原始类型, 不仅仅包含我们平常所指的类,还包括枚举、数组、注解等; 基本类型, 也就是我们所说的java的基本类型,即int,float,double等

 

public interface ParameterizedType extends Type { // 返回确切的泛型参数, 如Map<String, Integer>返回[String, Integer] Type[] getActualTypeArguments(); //返回当前class或interface声明的类型, 如List<?>返回List Type getRawType(); //返回所属类型. 如,当前类型为O<T>.I<S>, 则返回O<T>. 顶级类型将返回null Type getOwnerType(); }

 

/** * Author:Jay On 2019/5/11 22:41 * <p> * Description: 获取泛型类型测试类 */ public class GenericType<T> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } public static void main(String[] args) { GenericType<String> genericType = new GenericType<String>() {}; Type superclass = genericType.getClass().getGenericSuperclass(); //getActualTypeArguments 返回确切的泛型参数, 如Map<String, Integer>返回[String, Integer] Type type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; System.out.println(type);//class java.lang.String } }

10,虚拟机是如何实现泛型的

Java泛型是Java1.5之后才引入的,为了向下兼容。Java采用了C++完全不同的实现思想。Java中的泛型更多的看起来像是编译期用的 Java中泛型在运行期是不可见的,会被擦除为它的上级类型。如果是没有限定的泛型参数类型,就会被替换为Object.

 

GenericClass<String> stringGenericClass=new GenericClass<>(); GenericClass<Integer> integerGenericClass=new GenericClass<>();

C++中GenericClass<String>和GenericClass<Integer>是两个不同的类型 Java进行了类型擦除之后统一改为GenericClass<Object>

 

/** * Author:Jay On 2019/5/11 16:11 * <p> * Description:泛型原理测试类 */ public class GenericTheory { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("Key", "Value"); System.out.println(map.get("Key")); GenericClass<String, String> genericClass = new GenericClass<>(); genericClass.put("Key", "Value"); System.out.println(genericClass.get("Key")); } public static class GenericClass<K, V> { private K key; private V value; public void put(K key, V value) { this.key = key; this.value = value; } public V get(V key) { return value; } } /** * 类型擦除后GenericClass2<Object> * @param <T> */ private class GenericClass2<T> { } /** * 类型擦除后GenericClass3<ArrayList> * 当使用到Serializable时会将相应代码强制转换为Serializable * @param <T> */ private class GenericClass3<T extends ArrayList & Serializable> { } }

对应的字节码文件

 

public static void main(String[] args) { Map<String, String> map = new HashMap(); map.put("Key", "Value"); System.out.println((String)map.get("Key")); GenericTheory.GenericClass<String, String> genericClass = new GenericTheory.GenericClass(); genericClass.put("Key", "Value"); System.out.println((String)genericClass.get("Key")); }

三,学以致用

1,泛型解析JSON数据封装

api返回的json数据

 

{ "code":200, "msg":"成功", "data":{ "name":"Jay", "email":"10086" } }

BaseResponse .java

 

/** * Author:Jay On 2019/5/11 20:48 * <p> * Description: 接口数据接收基类 */ public class BaseResponse { private int code; private String msg; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }

UserResponse.java

 

/** * Author:Jay On 2019/5/11 20:49 * <p> * Description: 用户信息接口实体类 */ public class UserResponse<T> extends BaseResponse { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } }

2,泛型+反射实现巧复用工具类

 

/** * Author:Jay On 2019/5/11 21:05 * <p> * Description: 泛型相关的工具类 */ public class GenericUtils { public static class Movie { private String name; private Date time; public String getName() { return name; } public Date getTime() { return time; } public Movie(String name, Date time) { this.name = name; this.time = time; } @Override public String toString() { return "Movie{" + "name='" + name + '\'' + ", time=" + time + '}'; } } public static void main(String[] args) { List<Movie> movieList = new ArrayList<>(); for (int i = 0; i < 5; i++) { movieList.add(new Movie("movie" + i, new Date())); } System.out.println("排序前:" + movieList.toString()); GenericUtils.sortAnyList(movieList, "name", true); System.out.println("按name正序排:" + movieList.toString()); GenericUtils.sortAnyList(movieList, "name", false); System.out.println("按name逆序排:" + movieList.toString()); } /** * 对任意集合的排序方法 * @param targetList 要排序的实体类List集合 * @param sortField 排序字段 * @param sortMode true正序,false逆序 */ public static <T> void sortAnyList(List<T> targetList, final String sortField, final boolean sortMode) { if (targetList == null || targetList.size() < 2 || sortField == null || sortField.length() == 0) { return; } Collections.sort(targetList, new Comparator<Object>() { @Override public int compare(Object obj1, Object obj2) { int retVal = 0; try { // 获取getXxx()方法名称 String methodStr = "get" + sortField.substring(0, 1).toUpperCase() + sortField.substring(1); Method method1 = ((T) obj1).getClass().getMethod(methodStr, null); Method method2 = ((T) obj2).getClass().getMethod(methodStr, null); if (sortMode) { retVal = method1.invoke(((T) obj1), null).toString().compareTo(method2.invoke(((T) obj2), null).toString()); } else { retVal = method2.invoke(((T) obj2), null).toString().compareTo(method1.invoke(((T) obj1), null).toString()); } } catch (Exception e) { System.out.println("List<" + ((T) obj1).getClass().getName() + ">排序异常!"); e.printStackTrace(); } return retVal; } }); } }

3,Gson库中的泛型的使用-TypeToken

 

/** * Author:Jay On 2019/5/11 22:11 * <p> * Description: Gson库中的泛型使用 */ public class GsonGeneric { public static class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public static void main(String[] args) { Gson gson = new Gson(); List<Person> personList = new ArrayList<>(); for (int i = 0; i < 5; i++) { personList.add(new Person("name" + i, 18 + i)); } // Serialization String json = gson.toJson(personList); System.out.println(json); // Deserialization Type personType = new TypeToken<List<Person>>() {}.getType(); List<Person> personList2 = gson.fromJson(json, personType); System.out.println(personList2); } }

测试代码

作者:JayDroid 链接:https://www.jianshu.com/p/986f732ed2f1 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

 

 

==============================================================

个人写法示例

在接口中,创建带泛型的方法 package com.×××.×××.×××.×××; public interface ITest{ <T> T getObject(String str, Class<T> c); } package com.yuanian.dashboard.client.components; import com.alibaba.fastjson.JSONObject; public class TestImp implements ITest { @Override public <T> T getObject(String str, Class<T> c) { return JSONObject.parseObject(str,c); } } package com.×××.×××.×××.×××; import com.×××.×××.×××.×××.Apps; public class TestMain { public static void main(String[] args) { ITesttest = new TestImp(); Apps app = test.getObject("json str", Apps.class); } }

 

最新回复(0)