第24 章 : 反射与简单Java类
109 传统属性赋值弊端
简单Java类,setter,getter过多,代码重复
通过反射(Object类直接操作属性或方法)实现相同功能类的重复操作的抽象处理
110 属性自动赋值实现思路
类设计的基本机构:
应该由一个专门的ClassInstanceFactory类负责反射处理
接收反射对象与要设置的属性内容,同时可以获取指定类的实例化对象
class ClassInstanceFactory{
private ClassInstanceFactory(){}
/**
* 实例化对象的创建方法,该对象可以根据传入的字符串结构“属性:内容|属性:内容”
* @param clazz 要进行反射实例化的Class对象,有Class就可以反射实例化对象
* @param value 要设置给对象的属性内容
* @return 一个已经配置好属性内容的Java类对象
*/
public static <T> T getInstance(Class clazz, String value){
return null;
}
}
111 单级属性赋值
完成2项内容:
1、通过反射进行指定类对象的实例化处理
2、进行内容设置 Field Method
必须要有无参构造
处理流程
Class<?>
-Field
-Method 调用setter
Utils
-BeanUtils 获取类型,属性设置
-StringUtils 首字母大写
ClassInstanceFactory<T> 对象实例化并设置属性
main 测试类
即使类中的属性再多,也可以实现属性赋值
StringUtil.java
package util;
class StringUtil{
/**
* 首字母大写
*/
public static String capitalize(String str){
if(str == null || "".equals(str)){
return str;
}
if(str.length() == 1){
return str.toUpperCase();
} else{
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}
}
BeanUtil.java
package util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BeanUtil {
/**
* 对象属性赋值
* @param obj
* @param value 数据结构"key:value|key:value"
*/
public static void setValue(Object obj, String value){
String[] attrs = value.split("\\|");
// System.out.println(Arrays.toString(attrs));
for(String attr : attrs){
String[] keyValue = attr.split(":");
String key = keyValue[0];
String val = keyValue[1];
String setName = "set" + StringUtil.capitalize(key);
// System.out.println(key + val + setName);
try{
Field field = obj.getClass().getDeclaredField(key);
Method method = obj.getClass().getDeclaredMethod(setName, field.getType());
method.setAccessible(true);
method.invoke(obj, val);
} catch (Exception e){
e.printStackTrace();
}
}
}
}
Demo.java
import util.BeanUtil;
class Person{
private String name;
public Person() {
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
/**
* 属性赋值工厂类
*/
class ClassInstanceFactory{
private ClassInstanceFactory(){}
public static <T> T getInstance(Class<T> clazz, String value) {
try {
Object obj = clazz.getDeclaredConstructor().newInstance();
BeanUtil.setValue(obj, value);
return (T) obj;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
}
class Demo{
public static void main(String[] args) {
Person person = ClassInstanceFactory.getInstance(Person.class, "name:Tom");
System.out.println(person);
// Person{name='Tom'}
}
}
112 设置多种数据类型
简单Java类中属性类型
long(Long)
int(Integer)
double(Double)
String
在 BeanUtil.java中添加类型转换方法
package util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BeanUtil {
public static void setValue(Object obj, String value){
String[] attrs = value.split("\\|");
for(String attr : attrs){
String[] keyValue = attr.split(":");
String key = keyValue[0];
String val = keyValue[1];
String setName = "set" + StringUtil.capitalize(key);
try{
Field field = obj.getClass().getDeclaredField(key);
Method method = obj.getClass().getDeclaredMethod(setName, field.getType());
method.setAccessible(true);
Object convertVal = convertValue(field.getType().getName(), val);
method.invoke(obj, convertVal);
} catch (Exception e){
e.printStackTrace();
}
}
}
public static Object convertValue(String type, String value){
if ("java.lang.String".equals(type)){
return value;
} else if("int".equals(type)){
return Integer.parseInt(value);
} else{
return null;
}
}
}
Person类添加int类型的age属性,和修改测试Demo类传入参数
import util.BeanUtil;
class Person{
private String name;
private int age;
public void setAge(int age) {
this.age = age;
}
public Person() {
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Demo{
public static void main(String[] args) {
Person person = ClassInstanceFactory.getInstance(Person.class, "name:Tom|age:23");
System.out.println(person);
// Person{name='Tom', age=23}
}
}
如果要做一个完整的产品,需要考虑所有可能的类型
113 级联对象实例化
例如:
一个员工属于一个部门,一个部门属于一个公司
约定使用.
作为级联关系
eg:
company.dept.dname:财务部
考虑代码简洁性
114 级联属性赋值
完整代码
StringUtil.java
package util;
class StringUtil{
/**
* 首字母大写
*/
public static String capitalize(String str){
if(str == null || "".equals(str)){
return str;
}
if(str.length() == 1){
return str.toUpperCase();
} else{
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}
}
BeanUtil.java
package util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BeanUtil {
/**
* 对象属性赋值
*
* @param values 数据结构"key:value|key.subKey.subKey:value"
*/
public static void setValues(Object obj, String values) {
String[] attrs = values.split("\\|");
for (String attr : attrs) {
String[] keyValue = attr.split(":");
String key = keyValue[0];
String val = keyValue[1];
try {
// 级联关系,通过点. 分隔 eg: company.name
if (key.contains(".")) {
String[] objKeys = key.split("\\.");
Object currentObject = obj;
// 对象链
for (int i = 0; i < objKeys.length - 1; i++) {
String objKey = objKeys[i];
Object tempObject = getValue(currentObject, objKey);
// 没有实例化
if (tempObject == null) {
tempObject = getFieldInstance(currentObject, objKey);
setValue(currentObject, objKey, tempObject);
}
currentObject = tempObject;
}
// 最后一个就是属性
String attrKey = objKeys[objKeys.length - 1];
setValue(currentObject, attrKey, convertFieldValue(currentObject, attrKey, val));
}
// 单级关系
else {
setValue(obj, key, convertFieldValue(obj, key, val));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 给对象设置属性值
*/
public static void setValue(Object obj, String key, Object value) {
try {
Field field = obj.getClass().getDeclaredField(key);
String setName = "set" + StringUtil.capitalize(key);
Method method = obj.getClass().getDeclaredMethod(setName, field.getType());
method.setAccessible(true);
method.invoke(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取对象属性值
*/
public static Object getValue(Object obj, String key) {
Object value = null;
try {
String getName = "get" + StringUtil.capitalize(key);
Method getMethod = obj.getClass().getDeclaredMethod(getName);
getMethod.setAccessible(true);
value = getMethod.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
/**
* 获取对象属性对应类的实例化对象
*/
public static Object getFieldInstance(Object obj, String key) {
Object fieldObj = null;
try {
Field field = obj.getClass().getDeclaredField(key);
Constructor constructor = field.getType().getConstructor();
constructor.setAccessible(true);
fieldObj = constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return fieldObj;
}
/**
* 转换字符串为对应类型的值
*/
public static Object convertValue(String type, String value) {
if ("java.lang.String".equals(type)) {
return value;
} else if ("int".equals(type)) {
return Integer.parseInt(value);
} else {
return null;
}
}
public static Object convertFieldValue(Object obj, String key, String value) {
Object val = null;
try {
Field field = obj.getClass().getDeclaredField(key);
val = convertValue(field.getType().getName(), value);
} catch (Exception e) {
e.printStackTrace();
}
return val;
}
}
Demo.java
import util.BeanUtil;
class Person {
private String name;
private int age;
private Company company;
public Person() {
}
public void setAge(int age) {
this.age = age;
}
public Company getCompany() {
return company;
}
public void setName(String name) {
this.name = name;
}
public void setCompany(Company company) {
this.company = company;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", company=" + company +
'}';
}
}
class Dept {
private String name;
public Dept() {
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
'}';
}
}
class Company {
private String name;
private Dept dept;
public Company() {
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public Dept getDept() {
return dept;
}
@Override
public String toString() {
return "Company{" +
"name='" + name + '\'' +
", dept=" + dept +
'}';
}
}
/**
* 属性赋值工厂类
*/
class ClassInstanceFactory {
private ClassInstanceFactory() {
}
public static <T> T getInstance(Class<T> clazz, String values) {
try {
Object obj = clazz.getDeclaredConstructor().newInstance();
BeanUtil.setValues(obj, values);
return (T) obj;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
class Demo {
public static void main(String[] args) {
String values = "name:Tom|age:23|company.name:Tech|company.dept.name:law";
Person person = ClassInstanceFactory.getInstance(Person.class, values);
System.out.println(person);
// Person{name='Tom', age=23, company=Company{name='Tech', dept=Dept{name='law'}}}
}
}