您的位置 首页 > 腾讯云社区

java泛型详解---用户3625239

这次写一篇关于java泛型的文章,java泛型说难也不难,说容易也不容易,泛型的出现主要是为了帮助我们在编码时在编译时期就可以预先检查可能出现的错误类型转换问题。

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

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

例如:GenericClass<T>{}

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

如果要实现不同类型的加法,每种类型都需要重载一个add方法。可以发现用了泛型,我们只需要写一个add方法就可以了

package com.wpw.springbootjuc.generic; /** * 为什么使用泛型? * * @author wpw */ public class NeedGeneric1 { 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(); } 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; } 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.ClassCastException"异常。

package com.wpw.springbootjuc.generic; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.util.ArrayList; import java.util.List; /** * 为什么要使用泛型? * * @author wpw */ public class NeedGeneric2 { @NoArgsConstructor @Builder @Accessors(chain = true) @Data 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); /** * 当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,该对象的编译类型 * 变成了Object类型,但其运行时类型任然为其本身类型。 * 因此,//1出取出集合元素时需要人为的强制类型转换到具体的目标类型,且很容易出现"java.lang.ClassCastException"异常。 * */ for (int i = 0, size = list.size(); i < size; i++) { System.out.println(list.get(i)); String value = (String) list.get(i); System.out.println(value); } } }

上面由于我们没有进行泛型的设置,当使用String类型接收数据时就会出现类型转换异常。

Exception in thread "main" java.lang.ClassCastException: com.wpw.springbootjuc.generic.NeedGeneric2$C cannot be cast to java.lang.String at com.wpw.springbootjuc.generic.NeedGeneric2.main(NeedGeneric2.java:39)

所以这里就体现了使用泛型的意义。

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

关于泛型的使用,一般是泛型类,泛型接口,泛型方法的使用上,所以接下来我们按照上面的顺序进行定义和使用。

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

package com.wpw.springbootjuc.generic; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; /** * 泛型类的使用 * * @author wpw */ @Data @AllArgsConstructor @NoArgsConstructor @Builder @Accessors(chain = true) public class GenericClass<T> { private T data; public static void main(String[] args) { GenericClass<String> genericClass = new GenericClass<>(); genericClass.setData("Generic Class"); System.out.println(genericClass.getData()); } }

3,泛型接口的使用

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

package com.wpw.springbootjuc.generic; /** * 泛型接口 * * @author wpw */ public interface GenericInterface<T> { /** * 获取数据 * * @return 数据 t */ T getData(); }

实现泛型接口方式一:

public class GenericInterfaceImpl<T> implements GenericInterface<T>{}

package com.wpw.springbootjuc.generic; import lombok.Getter; import lombok.Setter; /** * 泛型接口实现类-泛型类实现方式 * * @author wpw */ public class GenericInterfaceImpl1<T> implements GenericInterface<T> { @Getter @Setter private T data; @Override public T getData() { return data; } public static void main(String[] args) { GenericInterfaceImpl1 genericInterfaceImpl1 = new GenericInterfaceImpl1(); genericInterfaceImpl1.setData("Generic Interface1"); System.out.println(genericInterfaceImpl1.getData()); } }

实现泛型接口方式二:

public class GenericInterfaceImpl2 implements GenericInterface<String>{}

package com.wpw.springbootjuc.generic; /** * 泛型接口实现类-指定具体类型实现方式 * * @author wpw */ public class GenericInterfaceImpl2 implements GenericInterface<String> { @Override public String getData() { return "Generic Interface2"; } public static void main(String[] args) { GenericInterfaceImpl2 genericInterfaceImpl2 = new GenericInterfaceImpl2(); System.out.println(genericInterfaceImpl2.getData()); } }

4,泛型方法的使用

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

package com.wpw.springbootjuc.generic; /** * 泛型方法 * * @author wpw */ 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); String str = GenericMethod1.genericAdd("a", "b"); System.out.println("str = " + str); } }

和文章最开始说的一样,泛型的作用就是为了更加精确的保证在编译时期类型是安全的。

package com.wpw.springbootjuc.generic; /** * 泛型方法 * * @author wpw */ 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 void show02(T t) { System.out.println(t.toString()); } public void show03(T t) { System.out.println(t.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 static <T extends Comparable<T>> T getMin(T a,T b){}

package com.wpw.springbootjuc.generic; import java.io.Serializable; /** * 类型变量的限定-方法 * * @author wpw */ public class TypeLimitForMethod { /** * 计算最小值,如果要实现这样的功能就需要对泛型方法的类型做出限定 * * @param a * @param b * @param <T> * @return */ private static <T extends Comparable> T getMin(T a, T b) { return (a.compareTo(b) > 0) ? a : b; } /** * 限定类型使用extends关键字指定,可以使类,接口,类放在前面,接口放在后面用&符号分隔 * * @param a * @param b * @param <T> * @return */ public static <T extends Comparable & Serializable> T getMinBySerializable(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.getMinBySerializable("a", "r")); System.out.println("a".hashCode()); System.out.println("b".hashCode()); } }

2,对类的限定

public class TypeLimitForClass<T extends List & Serializable>{}

package com.wpw.springbootjuc.generic; import lombok.Data; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * 类型变量的限定-类 * * @author wpw */ @Data public class TypeLimitForClass<T extends List & Serializable> { private T 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())); } private static <T extends Comparable<T> & Serializable> T getMinListSize(T a, T b) { return a.compareTo(b) < 0 ? a : b; } }

学以致用,接下来看下如何在实际的场景中如何使用泛型。

package com.wpw.springbootjuc.generic; import lombok.Data; /** * 接口数据接收基类 * @author wpw */ @Data public class BaseResponse { private int code; private String msg; } package com.wpw.springbootjuc.generic; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.io.Serializable; /** * 用户基础类 * * @author wpw */ @Data @AllArgsConstructor @NoArgsConstructor @Builder @Accessors(chain = true) public class User<T extends UserResponse & Serializable> implements Serializable { private String name; private String email; } package com.wpw.springbootjuc.generic; import com.google.gson.Gson; import lombok.Data; /** * 用户信息接口实体类 * * @author wpw */ @Data public class UserResponse<T> extends BaseResponse { private T data; public static void main(String[] args) { UserResponse userResponse=new UserResponse(); userResponse.setData(new User<>().setName("Jay").setEmail("10086")); userResponse.setCode(200); userResponse.setMsg("成功"); Gson gson=new Gson(); String json = gson.toJson(userResponse); System.out.println("json = " + json); } }

输出的内容信息如下

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

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

package com.wpw.springbootjuc.generic; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.springframework.util.CollectionUtils; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.time.LocalDateTime; import java.util.*; /** * 泛型相关的工具类 * * @author wpw */ public class GenericUtils { @Data @AllArgsConstructor @NoArgsConstructor @Builder @Accessors(chain = true) public static class Movie { private String name; private LocalDateTime 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, LocalDateTime.now())); } 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逆序 * @param <T> */ public static <T> void sortAnyList(List<T> targetList, final String sortField, final boolean sortMode) { if (targetList == null || CollectionUtils.isEmpty(targetList) || targetList.size() < 2 || sortField == null || sortField.length() == 0) { return; } Collections.sort(targetList, (o1, o2) -> { int retVal = 0; try { String methodStr = "get" + sortField.substring(0, 1).toUpperCase() + sortField.substring(1); Method method1 = o1.getClass().getMethod(methodStr, null); Method method2 = o2.getClass().getMethod(methodStr, null); if (sortMode) { retVal = method1.invoke(o1, null).toString().compareTo(method2.invoke(o2, null).toString()); } else { retVal = method2.invoke(o2, null).toString().compareTo(method1.invoke(o1, null).toString()); } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { System.out.println("List<" + o1.getClass().getName() + ">排序异常"); e.printStackTrace(); } return retVal; }); } }

Gson库中的泛型的使用-TypeToken

package com.wpw.springbootjuc.generic; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; /** * Gson库中的泛型使用 * * @author wpw */ public class GsonGeneric { @Data @AllArgsConstructor @NoArgsConstructor @Builder @Accessors(chain = true) public static class Person { private String name; private int age; } public static void main(String[] args) { List<Person> personList = new ArrayList<>(); for (int i = 0; i < 5; i++) { personList.add(new Person("name" + i, 18 + i)); } //Serialization Gson gson = new Gson(); String json = gson.toJson(personList); System.out.println("json = " + json); //Deserialization Type personType = new TypeToken<List<Person>>() { }.getType(); List<Person> personList2 = gson.fromJson(json, personType); System.out.println("personList2 = " + personList2); } }

最后写个工具类简单使用一下

package com.wpw.springbootjuc.generic; import lombok.Builder; import lombok.Data; import lombok.experimental.Accessors; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * 工具类 * * @author wpw */ public class GenericUtil<T> { public static <T extends Number & Serializable> Set<T> getList(List<T> list) { return new HashSet<>(list); } public static void main(String[] args) { List<Student> studentList = new ArrayList<>(); studentList.add(Student.builder().build().setName("公众号WwpwW").setId(1)); studentList.add(Student.builder().build().setName("公众号WwpwW2").setId(2)); studentList.add(Student.builder().build().setName("公众号WwpwW3").setId(3)); studentList.add(Student.builder().build().setName("公众号WwpwW4").setId(4)); studentList.add(Student.builder().build().setName("公众号WwpwW5").setId(1)); Set<Integer> set = getList(studentList.stream().map(Student::getId).collect(Collectors.toList())); set.stream().sorted(Integer::compareTo).forEach(x -> System.out.print(x + "t")); } @Data @Builder @Accessors(chain = true) static class Student { private Integer id; private String name; } } 文章参考www.jianshu.com/p/986f732ed2f1

java泛型的使用到这里结束了。

---来自腾讯云社区的---用户3625239

关于作者: 瞎采新闻

这里可以显示个人介绍!这里可以显示个人介绍!

热门文章

留言与评论(共有 0 条评论)
   
验证码: