泛型&反射笔记,应用场景
泛型
什么是泛型
泛型允许在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。
上下限通配符 ? extend Type , ? super Type
? extends Type: 只能是Type,或Type的子类
? super Type:只能是Type,或Type的父类
泛型方法
泛型方法意义在于在编写代码时不具体指定参数的具体类型,从而可以达到在使用时指定类型的效果,使方法的泛用性更强,更精简。
创建泛型方法,在修饰符后面添加 T为泛型类型,参数指定为T
/**
* 泛型方法
* @param t
*/
public <T> void testGeneric01(T t) throws IllegalAccessException {
Field[] allFields = t.getClass().getDeclaredFields();
for (Field field : allFields) {
field.setAccessible(true);
String fieldName = field.getName();
Object vlaue = field.get(t);
if(null == value) {
continue;
}
String desc = String.format("fieldName:%s -- value:%s",fieldName,vlaue);
System.out.println(desc);
}
}
测试一下
public static void main(String[] args) throws IllegalAccessException {
GenericMethod genericMethod = new GenericMethod();
HeadLine headLine = new HeadLine();
headLine.setLineLink("lineLink");
headLine.setLineImg("lineImg");
genericMethod.testGeneric0(headLine);
ShopCategory shopCategory = new ShopCategory();
shopCategory.setShopCategoryDesc("shopCategoryDesc");
shopCategory.setShopCategoryName("shopCategoryName");
genericMethod.testGeneric0(shopCategory);
}
执行结果
fieldName:lineLink -- value:lineLink
fieldName:lineImg -- value:lineImg
fieldName:shopCategoryName -- value:shopCategoryName
fieldName:shopCategoryDesc -- value:shopCategoryDesc
创建多个泛型的泛型方法,在修饰符后添加<T,E>,并将参数类型指定为T和E
/**
* 多个泛型的泛型方法
* @param t
* @param e
* @param <T>
* @param <E>
* @throws IllegalAccessException
*/
public <T,E> void testGeneric1(T t, E e) throws IllegalAccessException {
Field[] allFieldsForT = t.getClass().getDeclaredFields();
for (Field field : allFieldsForT) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(t);
if(null == value) {
continue;
}
String desc = String.format("fieldName:%s -- value:%s",fieldName,value);
System.out.println(desc);
}
Field[] allFieldsForE = e.getClass().getDeclaredFields();
for (Field field : allFieldsForE) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(e);
if(null == value) {
continue;
}
String desc = String.format("fieldName:%s -- value:%s",fieldName,value);
System.out.println(desc);
}
}
测试一下
public static void main(String[] args) throws IllegalAccessException {
HeadLine headLine = new HeadLine();
headLine.setLineLink("lineLink");
headLine.setLineImg("lineImg");
ShopCategory shopCategory = new ShopCategory();
shopCategory.setShopCategoryDesc("shopCategoryDesc");
shopCategory.setShopCategoryName("shopCategoryName");
GenericMethod genericMethod = new GenericMethod();
genericMethod.testGeneric1(headLine,shopCategory);
}
执行结果
fieldName:lineLink -- value:lineLink
fieldName:lineImg -- value:lineImg
fieldName:shopCategoryName -- value:shopCategoryName
fieldName:shopCategoryDesc -- value:shopCategoryDesc
泛型类型
定义一个不带类型的list,可以添加任意类型的元素
因为它本质上是List<Object>
List list = new ArrayList();
list.add(1);
list.add(2);
list.add("one");
使用指定的数据类型规范List的类型:
List<String> strList = new ArrayList<>();
strList.add("one");
strList.add("two");
如果在指定数据类型的list中添加其他类型属性,编译不通过,并且报错。泛型可以规范代码。
java: 对于add(int), 找不到合适的方法
方法 java.util.Collection.add(java.lang.String)不适用
(参数不匹配; int无法转换为java.lang.String)
方法 java.util.List.add(java.lang.String)不适用
(参数不匹配; int无法转换为java.lang.String)
泛型类
在类名后加上<T>,其中的T为泛型类型。由外部调用处指定。
类中所使用的T和类指定的T的类型为同一类型。
泛型类可以指定多个泛型
定义一个泛型类,泛型类规范了类中的类型。
单个泛型的泛型类
/**
* @author :tanfuxing
* @date :2023/1/10
* @description :
*/
@Data
public class TreeNode<T> {
private Boolean color;
private T value;
//父节点
private TreeNode<T> parent;
//左子树
private TreeNode<T> left;
//右子树
private TreeNode<T> right;
public TreeNode(T t,boolean color) {
this.value = t;
this.color = color;
}
public int getHashCode() {
return value.hashCode();
}
/**
* 比较器
* this>treeNode,返回1
* this<treeNode,返回-1
* this=treeNode,返回0
* @param treeNode
* @return
*/
public int compare(TreeNode<T> treeNode) {
if(this.getHashCode()> treeNode.getHashCode()) {
return 1;
} else if(this.getHashCode()< treeNode.getHashCode()) {
return -1;
} else {
return 0;
}
}
public String toString() {
String result = "{\"value\":\"%s\", \n \"color\":\"%s\", \n \"left\":%s, \n \"right\":%s}";
result = String.format(result,this.value, RBTreeColorEnum.getDescByKey(this.color),getToString(this.left),getToString(this.right));
return result;
}
/**
* 返回toString字符串
* @param treeNode
* @return
*/
private String getToString(TreeNode<T> treeNode) {
return null == treeNode ? null : treeNode.toString();
}
}
多个泛型的泛型类
指定了T和E的类型必须是GenericeParent或其子类。不一定要指定上下通配符
public class GenericClassExample<T extends GenericParent,E extends GenericParent> {
public GenericClassExample(T t,E e) {
this.t = t;
this.e = e;
}
private T t;
private E e;
public void doTMethod() {
t.sayHello();
}
public void doEMethod() {
e.sayHello();
}
}
定义一个泛型父类,目的是在上面类中可以调用到sayHello()方法
public abstract class GenericParent {
public abstract void sayHello();
}
public class GenericTExample extends GenericParent {
@Override
public void sayHello() {
System.out.println("hello, 我是T实体类");
}
}
public class GenericEExample extends GenericParent {
@Override
public void sayHello() {
System.out.println("你好, Im E entity");
}
}
测试一下
public static void main(String[] args) {
GenericTExample t = new GenericTExample();
GenericEExample e = new GenericEExample();
GenericClassExample<GenericTExample, GenericEExample> genericExample = new GenericClassExample<>(t,e);
genericExample.doTMethod();
genericExample.doEMethod();
}
运行结果
hello, 我是T实体类
你好, Im E entity
泛型擦除
Java泛型实际上是“伪泛型”,它只是在编译期存在当程序到运行时则会被Java虚拟机进行类型擦除,同时Java虚拟机通过桥接的方式将编译期和运行期的程序(泛型类和原始类)连接了起来,从而实现了泛型的整个过程。另外对于Java泛型的许多限制都可以通过类型擦除和泛型的设计初衷来解释(将可能出现的运行时异常移至编译其解决)。
反射
什么是反射
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。
Class对象
Class类的实例表示正在运行的java应用程序中的类和接口。java中的各种类型都被映射成为一个Class对象。
Class没有公共构造方法,Class对象是在加载类时有jvm以及通过调用类加载器中的defineClass方法自动构造的。
获取Class对象的方式:
1.直接通过类型.class获取类的Class对象
Class pClass = Person.class;
2.通过Class.forName()
方法获取Class对象
Class aClass = Class.forName("com.tfxing.persondaily.entity.po.Person");
3.通过getClass()方法获取Class对象
Person person = new Person();
Class clazz = person.getClass();
Class对象中常用的方法
Person person = new Person();
Class clazz = person.getClass();
//获取所有的字段
Field[] allFields = clazz.getDeclaredFields();
//获取指定的字段
Field field = clazz.getDeclaredField("personName");
//无视字段的访问权限
field.setAccessible(true);
//获取字段的名称
String fieldName = field.getName();
//获取字段的值,参数为获取值的指定对象
Object value = field.get(person);
//获取无参构造方法并创建一个实例
Object obj = clazz.getConstructor().newInstance();
//获取所有的方法
Method[] allMethods = clazz.getDeclaredMethods();
//获取指定的方法
Method method = clazz.getDeclaredMethod("getPersonName");
//执行方法,参数为使用方法的指定对象,该方法的参数
method.invoke(person,"param");
//获取所有的注解
Annotation[] annotations = clazz.getAnnotations();
//获取指定的注解
Annotation annotation = clazz.getAnnotation(Data.class);
项目中的应用场景
需求:根据各个阶段需要复制各个阶段对应的字段值。复制对象与对象之间的属性
导入excel字段校验,多个字段的校验规则相同,可以做成一个通用的校验方法