反射案例
目录
反射案例
1. 目标
1. 字符串数据解析 ==> JavaBean 规范对象 ==> 存储到 ArrayList 集合中
2. 存储 JavaBean 规范类对象中的 ArrayList 数据 ==> 字符串
2. 字符串内容
className=com.qfedu.entity.Student;[id=1,name=王嚣张,age=99,gender=男,score=0.5];[id=2,name=王周董,age=16,gender=男,score=5.5];[id=3,name=王乾,age=9,gender=男,score=9.5];[id=4,name=王强哥,age=25,gender=男,score=99.5];
1. 根据字符串信息内容分析 JavaBean 规范对象成员变量数据类型选择。
package com.qfedu.entity;
class Student {
private int id;
private String name;
private int age;
private char gender;
private float score;
// 根据所需完成对应的 Setter 和 Getter 以及 Constructor 方法
}
2. [id=1,name=王嚣张,age=99,gender=男,score=0.5] ==> JavaBean 规范 Student 对象
得到哪些东西???需要哪些技术???
1. String 字符串切割 substring
2. 类型转换. String ==> int char float
例如:
"id=1" ==> split("=") ==> String[] {"id", "1"}
"id" ==> Student 类内成员变量名称为 id 的 Field 对象 【反射】
"1" ==> id Field 对象所需的【int】类型
String ==> 转换为其他数据类型 基本数据类型包装类
3. 字符串转基本类型方法
package com.qfedu.demo;
/*
* 字符串转其他类型相关方法
*/
public class Demo1 {
public static void main(String[] args) {
/*
String => byte short int long
String => float
String => double
String => char
String => boolean
包装类:
Java 把基本数据类型设定了一个符合 Java 万物皆对象的思想 完成对应基本数据类型的包装类。
byte ==> Byte
short ==> Short
int ==> Integer
long ==> Long
float ==> Float
double ==> Double
char ==> Character
boolean ==> Boolean
操作使用和基本数据类型操作一致,多辅助了一些相关的方法
String 解析对应数据方法
*/
String str1 = "100";
int i = Integer.parseInt(str1);
System.out.println(i);
/*
* Integer
* static int parseInt(String)
*
* Short Byte Long 都有类似的方法
* static short parseShort(String)
* static byte parseByte(String)
* static long parseLong(String)
*/
String str2 = "99.5";
float f = Float.parseFloat(str2);
double d = Double.parseDouble(str2);
System.out.println(f);
System.out.println(d);
/*
* Float Double
* static float parseFloat(String)
* static double parseDouble(String)
*/
/*
* Character
* String 类方法
* char charAt(0);
*/
String str3 = "true";
boolean b = Boolean.parseBoolean(str3);
System.out.println(b);
/*
* Boolean
* static boolean parseBoolean(String)
*/
/*
* String 转基本数据类型操作方法
* Byte Short Long Float Double Boolean
* static xxx parseXXXX(String)
*
* Integer
* static int parseInt(String);
*
* Character
* char charAt(0);
*/
}
}
4. 反射反思
1. Class 对象获取 ==>
.class字节码文件在内存【方法区】对应内存空间。==>
.class文件对应 Java文件 ==>
对应 Java程序或者对应数据类型。
2. 通过 Class 对象 获取成员变量 Field 对象。
a. Field 对象是否可以获取【成员变量名称】???
获取【成员变量名称】 方法 是什么?
Field 类内方法 String getName(); 获取当前成员变量名称。
b. Field 对象是否可以获取【成员变量数据类型】???
获取【成员变量数据类型】 方法 是什么?
Field 类内方法 Class getType(); 获取当前成员变量数据类型 Class
3. 通过 Class 对象 获取成员变量 Method 对象。
String getName();
Method 类内方法 获取当前成员方法名称
Class[] getParameterTypes();
Method 类内方法 获取当前成员方法形式参数列表数据类型 Class 数组
Class getReturnType();
Method 类内方法 获取当前成员方法返回值数据类型 Class 对象
例如:
public int test(int n1, int n2);
Class cls;
Method m1 = cls.getMethod("test", int.class, int.class);
m1.getName(); ==> "test"
m1.getParameterTypes() ==> Class[] types = {int.class, int.class}
m1.getReturnType(); ==> Class returnType = int.class;
5. 字符串转JavaBean规范对象
5.1 Class 对象获取
className=com.qfedu.entity.Student;[id=1,name=a,age=99,gender=男,score=0.5];[id=2,name=c,age=16,gender=男,score=5.5];[id=3,name=d,age=9,gender=男,score=9.5];[id=4,name=e,age=25,gender=男,score=99.5];
className=com.qfedu.entity.Student
包含对应数据类型的完整的包名.类名 ==> 对应的 Class 对象 【为所欲为】
className=com.qfedu.entity.Student;[id=1,name=王嚣张,age=99,gender=男,score=0.5];[id=2,name=周董,age=16,gender=男,score=5.5];[id=3,name=王乾,age=9,gender=男,score=9.5];[id=4,name=强哥,age=25,gender=男,score=99.5];
==> 执行 split(";") ==> String[]
String[] arr = {
"className=com.qfedu.entity.Student", // 想要获取的数据信息
"[id=1,name=a,age=99,gender=男,score=0.5]",
"[id=2,name=b,age=16,gender=男,score=5.5]",
"[id=3,name=c,age=9,gender=男,score=9.5]",
"[id=4,name=d,age=25,gender=男,score=99.5]"
}
String className = arr[0].substring(arr[0].indexOf("=") + 1);
Class Class.forName(className); ==> 得到对应的 Class 对象
5.2 解析信息字符串
String[] arr = {
"className=com.qfedu.entity.Student", // 包名.类名
"[id=1,name=a,age=99,gender=男,score=0.5]",
"[id=2,name=b,age=16,gender=男,score=5.5]",
"[id=3,name=c,age=9,gender=男,score=9.5]",
"[id=4,name=d,age=25,gender=男,score=99.5]"
}
arr[1] = "[id=1,name=王嚣张,age=99,gender=男,score=0.5]"
String infoStr = arr[1].substring(arr[1].indexOf('[') + 1 , arr[1].lastIndexOf(']'));
infoStr ==> "id=1,name=王嚣张,age=99,gender=男,score=0.5";
String[] infoArr = infoStr.split(",");
infoArr = { // 键值对模型数组 成员变量=数据
"id=1",
"name=a",
"age=99",
"gender=男",
"score=0.5"
};
重点信息:
1. 成员名称
2. 成员变量对应数据字符串信息
int index = infoArr[0].indexOf('=');
String filedName = infoArr[0].substring(0, index);
String value = infoArr[0].substring(index + 1);
5.3 BeanUtils工具类 setProperty 方法实现
package com.qfedu.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 符合 JavaBean 规范类对象操作工具类
*/
public class BeanUtils {
/**
* 给予符合 JavaBean 规范类对象,根据成员变量名 fieldName,给予对应成员变量数据赋值操作, 数据对应类型为String
* 类型,要求在方法中,转换其类型为成员变量对应类型
*
* @param bean 符合 JavaBean 规范类对象
* @param fieldName 指定成员变量名称
* @param value 对应当前成员变量赋值使用数据,String 类型
* @throws SecurityException 安全异常
* @throws NoSuchFieldException 没有对应成员变量异常
* @throws NoSuchMethodException 没有对应成员方法异常
* @throws InvocationTargetException 执行目标异常
* @throws IllegalArgumentException 非法参数异常
* @throws IllegalAccessException 非法权限异常
*/
public static void setProperty(Object bean, String fieldName, String value)
throws NoSuchFieldException, SecurityException, NoSuchMethodException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
// 1. 通过 bean 获取对应 Class 对象
Class<?> cls = bean.getClass();
// 2. 获取成员变量 Field 类对象,因为 JavaBean 规范成员变量都是 private 私有化修饰,需要【暴力反射】
Field field = cls.getDeclaredField(fieldName);
// 3. JavaBean 规范成员变量都是 private 修饰,如果不给予操作权限,无法执行其他任何方法。操作之前,给予对应使用权限
field.setAccessible(true);
// 4. 获取成员变量数据类型,才可以指定 value 字符串数据对应的目标数据类型是什么
Class<?> type = field.getType();
/*
* 1. Byte Short Long Double Float Boolean ==> parse数据类型名(String)
*
* 2. Integer ==> parseInt(String)
*
* 3. Character ==> charAt(0);
*
* 4. 字符串 直接用
*
* 最终执行的方法: field.set(bean, parseValue); tips: parseValue 是 value
* 根据当前成员变量数据类型转换之后的结果。
*/
// 分支结构走起!!!
// parseValue 用于最终赋值成员变量使用的数据,采用 Object 类型,方便后期临时存储转换之后的数据结果
Object parseValue = null;
if (type == String.class) {
// 成员变量数据类型为 String 类型
parseValue = value;
} else if (type == char.class || type == Character.class) {
// 成员变量数据类型为 char or Character 类型。一定要判断 char or Character
parseValue = value.charAt(0);
} else if (type == int.class || type == Integer.class) {
// 成员变量数据类型为 int or Integer 类型。
parseValue = Integer.parseInt(value);
} else {
/*
* 剩下以下类型需要转换 1. Byte Short Long Double Float Boolean ==> parse数据类型名(String)
*/
/*
* 获取数据类型名称 type ==> Float 类型 name = java.lang.Float
*/
String name = type.getName();
/*
* substring 操作之后 name = Float
*/
name = name.substring(name.lastIndexOf('.') + 1);
/*
* 拼接 parseXXX 方法名称 parseFloat 方法名
*/
String parseMethodName = "parse" + name;
/*
* 通过当前成员变量数据类型获取对应的 parseXXX 解析字符串方法 得到 parseFloat 方法 public static float
* java.lang.Float.parseFloat(java.lang.String)
*
*/
Method parseMethod = type.getMethod(parseMethodName, String.class);
/*
* 通过该 Method 对象执行 invoke 方法 因为方法为 static 方法,第一个执行方法对象可以 null
*/
parseValue = parseMethod.invoke(null, value);
}
field.set(bean, parseValue);
}
}