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泛型的使用到这里结束了。