进阶Java编程(10)反射与简单Java类
1,传统属性自动赋值弊端
简单Java类主要由属性构成,并且提供有setter与getter类,同时简单Java类最大的特征就是通过对象保存相应的类属性的内容。但是如果使用传统的简单Java类开发,那么也会面临非常麻烦的困难。
·范例:传统的简单Java类操作
1 package cn.demo11.demo;
2 class Emp{
3 private String ename;
4 private String job;
5 //setter、getter略
6 }
特别强调,为了方便理解,本次Emp类之中定义的ename、job两个属性都是使用String类型。按照传统的做法此时应该首先实例化Emp类的对象,而后通过实例化对象进行setter方法的调用以设置内容。
·范例:传统的调用
1 public static void main(String[] args) {
2 Emp emp=new Emp();
3 emp.setEname("万雨");
4 emp.setJob("Java开发工程师");
5 System.out.print("姓名:"+emp.getEname()+",职位:"+emp.getJob());
6 }
7 }
8 /*输出
9 姓名:万雨,职位:Java开发工程师
10 */
11
在整个进行Emp对象实例化并设置数据的操作过程之中,设置数据的部分是最麻烦的,你可以想象一下,如果Emp类里面提供有50个属性,那么对于整个程序将会成为一堆的setter方法的调用。或者再进一步说明,在实际开发之中,简单Java类的个数是非常多的,那么如果所有的简单Java列都牵扯到属性的赋值的时候,这种情况下代码编写的重复性将会非常高!!!
按照传统的直观的编程方法,所带来的问题就是代码会存在有大量的重复操作,如果想要解决对象的重复处理操作那么唯一的解决方案就是【反射机制】,反射机制最大的特定就是可以根据自身的特点【Object类直接操作、可以直接操作属性和方法】实现相同功能类的重复操作的抽象处理。
2,属性自动赋值实现思路
经过分析之后已经确认了当前简单Java类操作的问题所在,而对于开发这而言就需要想办法通过一种解决方案来实现属性内容的自动设置,那么这个时候设置强烈建议采用字符串的形式描述对应的类型。
①在进行程序开发的时候String字符串可以描述的内容有很多,并且也可以由开发者自行定义字符串的结构,下面就采用【属性:内容|属性:内容】的形式来为简单Java类进行赋值
②类设计的基本结构:应该由一个专门的ClassInstanceFactory类负责所有的反射处理,即:接收反射对象与要设置的属性内容同时可以获取指定类的实例化对象。
③设计的基本结构:
1 class ClassInstanceFactory{
2 private ClassInstanceFactory(){}//无参构造
3 /**
4 * 实例化对象的创建方法,该对象可以根据传入的字符串结构【属性:内容|属性:内容】
5 * @param clazz 要进行反射实例化的Class类对象,有Class就可以反射实例化对象
6 * @param value 要设置给对象的属性内容
7 * @param <T>
8 * @return 一个已经配置好属性内容的简单Java类对象
9 */
10 public static <T> T create(Class<?> clazz,String value){
11 return null;
12 }
13 }
那么在当前的开发之中,所需要留给用户完善的就是ClassInstanceFactory.create()处理方法。
3,单级属性配置
对于此时的Emp类里面会发现所给出的数据类型都没其他的引用关联了,只是描述了Emp本类的对象,所以这样的设置称为单级设置处理,所以此时应该处理两件事情:
①需要通过反射进行指定类对象的实例化处理;
②进行内容的设置(Field属性类型,方法名称、要设置的内容);
①定义StringUtils实现首字母大写功能
1 package cn.demo13.demo;
2
3 class StringUtils {
4 public static String initcap(String str){
5 if(str==null||"".equals(str)){
6 return str;
7 }
8 if(str.length()==1){
9 return str.toUpperCase();
10 }else{
11 return str.substring(0,1).toUpperCase()+str.substring(1);
12 }
13 }
14 }
②定义BeanUtils工具类,该工具类主要实现属性的设置
1 package cn.demo13.demo;
2
3 import java.lang.reflect.Field;
4 import java.lang.reflect.Method;
5
6 public class BeanUtils {//进行Bean处理类
7 private BeanUtils(){}
8 /**
9 * 实现指定对象的属性设置
10 * @param obj 要进行反射操作的实例化对象
11 * @param value 包含有指定内容的字符串,格式【属性:内容|属性:内容】
12 */
13 public static void setValue(Object obj,String value) {
14 String[] results=value.split("\\|");//字符串拆分
15 for(int x=0;x<results.length;x++){
16 //attval[0]保存的是属性的名称、attval[1]保存的是属性内容
17 String[] attval=results[x].split(":");//获取【属性名称】与【内容】
18 try{
19 Field field=obj.getClass().getDeclaredField(attval[0]);//获取属性成员
20 Method setMethod=obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]),field.getType());
21 setMethod.invoke(obj,attval[1]);//调用setter方法设置内容
22 }catch (Exception e){
23 e.printStackTrace();
24 }
25
26 }
27 }
28 }
③ClassInstanceFactroy负责实例化对象并且调用BeanUtils类实现属性内容的设置
1 package cn.demo13.demo;
2
3 class ClassInstanceFactory{
4 private ClassInstanceFactory(){}
5 public static <T> T create(Class<?> clazz,String value){
6 try{//如果想要采用反射进行简单Java类对象属性的设置,类中必须要有无参构造
7 Object obj=clazz.getDeclaredConstructor().newInstance();
8 BeanUtils.setValue(obj,value);//通过反射设置属性
9 return (T) obj;
10 }catch (Exception e){
11 e.printStackTrace();//即便出现错误也不影响后续代码的执行
12 return null;
13 }
14 }
15 }
4,设置多种数据类型
现在已经成功的实现了单级的属性配置,但是这里面依然需要考虑一个实际的情况,我们当前所给定的数据类型只是String,但是在实际的开发之中面对简单Java类中的属性类型一般的可选方案为:long(Long)、int(Integer)、double(Double)、String、Date(日期或者日期时间),所以对于当前的程序代码而言就必须做出修改,可以实现各种数据的类型的配置。
既然要求可以实现不同类型的内容的设置,并且BeanUtils类主要是完成属性赋值处理的,那么就可以在这个类之中追加有一些列的处理方法。
package cn.demo13.demo; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date; public class BeanUtils {//进行Bean处理类
private BeanUtils(){}
/**
* 实现指定对象的属性设置
* @param obj 要进行反射操作的实例化对象
* @param value 包含有指定内容的字符串,格式【属性:内容|属性:内容】
*/
public static void setValue(Object obj,String value) {
String[] results=value.split("\\|");//字符串拆分
for(int x=0;x<results.length;x++){
//attval[0]保存的是属性的名称、attval[1]保存的是属性内容
String[] attval=results[x].split(":");//获取【属性名称】与【内容】 try{
Field field=obj.getClass().getDeclaredField(attval[0]);//获取属性成员
Method setMethod=obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]),field.getType());
Object convertVal=BeanUtils.convertAttributeValue(field.getType().getName(),attval[1]);
setMethod.invoke(obj,convertVal);//调用setter方法设置内容
}catch (Exception e){
e.printStackTrace();
} }
} /**
* 实现属性类型转换处理
* @param type 属性类型,通过Field获取
* @param value 属性的内容,传入的都是字符串,需要将其变为指定类型
* @return 转换后的数据
*/
private static Object convertAttributeValue(String type,String value){
// System.out.println("type="+type+",value="+value);
if("long".equals(type)||"java.lang.Long".equals(type)){//长整型
return Long.parseLong(value);
}else if("int".equals(type)||"java.lang.int".equals(type)){
return Integer.parseInt(value);
}else if("double".equals(type)||"java.lang.double".equals(type)){
return Double.parseDouble(value);
}else if("java.util.Date".equals(type)){ SimpleDateFormat sdf=null;
if(value.matches("\\d{4}-\\d{2}-\\d{2}")){//日期类型
sdf=new SimpleDateFormat("yyyy-MM-dd");
}else if(value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")){//有日期
sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}else {
return new Date();
}
try {
return sdf.parse(value);
} catch (ParseException e) {
return new Date();
}
}else {
return value;
}
}
}
此时只是列举出了几种常见的数据类型,如果想要将其作为一个产品推广,那么就必须要考虑所有可能出现的类型,同时所有可能的日期格式也需要考虑。
5,级联对象实例化
如果说给定的类对象之中存在其他的引用的级联关系的情况下,称为多级设置。例如:一个雇员属于一个部门,一个部门属于一个公司,所以这个时候对于简单Java类的基本关系定义如下:
初始化3个类:Emp、Company、Dept。
public class Emp {
private String ename;
private String job;
private long empno;
private double salary;
private Date hiredate;
private Dept dept;//setter、getter略
}
public class Company {
private String name;
private Date createDate;//setter、getter略
}
public class Dept {
private String dname;
private String loc;
private Company company;//setter、getter略
}
如果要通过Emp进行操作,则应该使用【.】作为级联关系的处理:
dept.dname:财务部——>Emp的实例化对象.getDept().setDname("财务部");
dept.company.name:Mufasa——>Emp的实例化对象.getDpet().getCompany().setName("Mufasa");
考虑到代码的简洁性,所以应该考虑可以通过级联的配置自动实现类中属性的实例化。
String value="ename:万雨|empno:7369|job:Java开发工程师|salary:750.00|hiredate:1989-10-10|"
+"dept.dname:财务部|dept.company.name:Mufasa";
现在的属性存在多级关系,那么多级的关系就必须与单级的配置区分开。
package com.company.mufasa; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date; public class BeanUtils {//进行Bean处理类
private BeanUtils(){}
/**
* 实现指定对象的属性设置
* @param obj 要进行反射操作的实例化对象
* @param value 包含有指定内容的字符串,格式【属性:内容|属性:内容】
*/
public static void setValue(Object obj,String value) {
String[] results=value.split("\\|");//字符串拆分
for(int x=0;x<results.length;x++){
//attval[0]保存的是属性的名称、attval[1]保存的是属性内容
String[] attval=results[x].split(":");//获取【属性名称】与【内容】 try{
if(attval[0].contains(".")){//多级配置
String[] temp=attval[0].split("\\.");
Object currentObject=obj;
//最后一位肯定是类中的属性名称,所以不在本次实例化处理的范畴之内
for (int y=0;y<temp.length-1;y++){//实例化
//调用相应的getter方法,如果getter方法返回了null表示该对象为实例化
Method getMethod=currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y]));
Object tempObject=getMethod.invoke(currentObject);
if(tempObject==null){//该对象没有实例化
Field field=currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
Method method=currentObject.getClass().getDeclaredMethod("set"+StringUtils.initcap(temp[y]),field.getType());
Object newObject=field.getType().getDeclaredConstructor().newInstance();
method.invoke(currentObject,newObject);
currentObject=newObject;
}else {
currentObject=tempObject;
}
// System.out.println(temp[y]+"----"+currentObject);
} }else {//单级配置
Field field=obj.getClass().getDeclaredField(attval[0]);//获取属性成员
Method setMethod=obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]),field.getType());
Object convertVal=BeanUtils.convertAttributeValue(field.getType().getName(),attval[1]);
setMethod.invoke(obj,convertVal);//调用setter方法设置内容
} }catch (Exception e){
e.printStackTrace();
} }
} /**
* 实现属性类型转换处理
* @param type 属性类型,通过Field获取
* @param value 属性的内容,传入的都是字符串,需要将其变为指定类型
* @return 转换后的数据
*/
private static Object convertAttributeValue(String type,String value){
// System.out.println("type="+type+",value="+value);
if("long".equals(type)||"java.lang.Long".equals(type)){//长整型
return Long.parseLong(value);
}else if("int".equals(type)||"java.lang.int".equals(type)){
return Integer.parseInt(value);
}else if("double".equals(type)||"java.lang.double".equals(type)){
return Double.parseDouble(value);
}else if("java.util.Date".equals(type)){ SimpleDateFormat sdf=null;
if(value.matches("\\d{4}-\\d{2}-\\d{2}")){//日期类型
sdf=new SimpleDateFormat("yyyy-MM-dd");
}else if(value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")){//有日期
sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}else {
return new Date();
}
try {
return sdf.parse(value);
} catch (ParseException e) {
return new Date();
}
}else {
return value;
}
}
}
这些自动的级联配置的实例化处理操作,在以后进行项目的编写之中一定会使用到。
6,级联属性赋值
现在已经实现级联的实例化处理,随后要解决级联的属性设置问题。在进行级联实例化处理的时候循环都是少了一位的。
for (int y=0;y<temp.length-1;y++){//实例化
//调用相应的getter方法,如果getter方法返回了null表示该对象为实例化
Method getMethod=currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y]));
Object tempObject=getMethod.invoke(currentObject);
if(tempObject==null){//该对象没有实例化
Field field=currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
Method method=currentObject.getClass().getDeclaredMethod("set"+StringUtils.initcap(temp[y]),field.getType());
Object newObject=field.getType().getDeclaredConstructor().newInstance();
method.invoke(currentObject,newObject);
currentObject=newObject;
}else {
currentObject=tempObject;
}
}
}
当此时代码循环处理完成之后,currentObject表示的就是可以进行setter方法调用的对象了,并且理论上该对象一定不可能为null,随后就可以按照之前的方式利用对象进行setter调用。
·范例:实现对象的级联属性设置
package com.company.mufasa; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date; public class BeanUtils {//进行Bean处理类
private BeanUtils(){}
/**
* 实现指定对象的属性设置
* @param obj 要进行反射操作的实例化对象
* @param value 包含有指定内容的字符串,格式【属性:内容|属性:内容】
*/
public static void setValue(Object obj,String value) {
String[] results=value.split("\\|");//字符串拆分
for(int x=0;x<results.length;x++){
//attval[0]保存的是属性的名称、attval[1]保存的是属性内容
String[] attval=results[x].split(":");//获取【属性名称】与【内容】 try{
if(attval[0].contains(".")){//多级配置
String[] temp=attval[0].split("\\.");
Object currentObject=obj;
//最后一位肯定是类中的属性名称,所以不在本次实例化处理的范畴之内
for (int y=0;y<temp.length-1;y++){//实例化
//调用相应的getter方法,如果getter方法返回了null表示该对象为实例化
Method getMethod=currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y]));
Object tempObject=getMethod.invoke(currentObject);
if(tempObject==null){//该对象没有实例化
Field field=currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
Method method=currentObject.getClass().getDeclaredMethod("set"+StringUtils.initcap(temp[y]),field.getType());
Object newObject=field.getType().getDeclaredConstructor().newInstance();
method.invoke(currentObject,newObject);
currentObject=newObject;
}else {
currentObject=tempObject;
} }
Field field=currentObject.getClass().getDeclaredField(temp[temp.length-1]);//获取成员
Method setMethod=currentObject.getClass().getDeclaredMethod("set"+StringUtils.initcap(temp[temp.length-1]),field.getType());
Object convertVal=BeanUtils.convertAttributeValue(field.getType().getName(),attval[1]);
setMethod.invoke(currentObject,convertVal);//调用setter方法设置内容
}else {//单级配置
Field field=obj.getClass().getDeclaredField(attval[0]);//获取属性成员
Method setMethod=obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]),field.getType());
Object convertVal=BeanUtils.convertAttributeValue(field.getType().getName(),attval[1]);
setMethod.invoke(obj,convertVal);//调用setter方法设置内容
} }catch (Exception e){
e.printStackTrace();
} }
} /**
* 实现属性类型转换处理
* @param type 属性类型,通过Field获取
* @param value 属性的内容,传入的都是字符串,需要将其变为指定类型
* @return 转换后的数据
*/
private static Object convertAttributeValue(String type,String value){
// System.out.println("type="+type+",value="+value);
if("long".equals(type)||"java.lang.Long".equals(type)){//长整型
return Long.parseLong(value);
}else if("int".equals(type)||"java.lang.int".equals(type)){
return Integer.parseInt(value);
}else if("double".equals(type)||"java.lang.double".equals(type)){
return Double.parseDouble(value);
}else if("java.util.Date".equals(type)){ SimpleDateFormat sdf=null;
if(value.matches("\\d{4}-\\d{2}-\\d{2}")){//日期类型
sdf=new SimpleDateFormat("yyyy-MM-dd");
}else if(value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")){//有日期
sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}else {
return new Date();
}
try {
return sdf.parse(value);
} catch (ParseException e) {
return new Date();
}
}else {
return value;
}
}
}
在以后的简单Java类之中简单Java类的幅值将不再重复调用setter方法操作完成,而这种处理形式是在正轨开发中普遍采用的方式。
进阶Java编程(10)反射与简单Java类的更多相关文章
- java反射(四)--反射与简单java类
一.传统简单java类 简单的java类主要是由属性所组成,并且提供有相应的setter以及getter的处理方法,同时简单java类最大的特征就是通过对象保存相应的类的属性内容,但是如果使用传统的简 ...
- Java编程思想重点笔记(Java开发必看)
Java编程思想重点笔记(Java开发必看) Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而 ...
- 进阶Java编程(13)反射与Annotation
1,反射取得Annotation信息 从JDK1.5之后Java提供了Annotation技术支持,这种技术为项目的编写带来了新的模型,而后经过了十年的发展,Annotation的技术得到了非常广泛的 ...
- 进阶Java编程(9)反射与类操作
1,反射获取类结构信息 在反射机制的处理过程之中不仅仅只是一个实例化对象的处理操作,更多的情况下还有类的组成结构操作,任何一个类的基本组成结构:父类(父接口).包.属性.方法(构造方法与普通方法). ...
- Java编程之反射中的注解详解
"注解"这个词,可谓是在Java编程中出镜率比较高,而且也是一个老生常谈的话题.我们之前在聊Spring相关的东西时,注解是无处不在,之前我们简单的聊过一些"注解&quo ...
- 【Java编程】建立一个简单的JDBC连接-Drivers, Connection, Statement and PreparedStatement
本blog提供了一个简单的通过JDBC驱动建立JDBC连接例程.并分别通过Statement和PreparedStatement实现对数据库的查询. 在下一篇blog中将重点比較Statement与P ...
- 黑马程序员:Java编程_反射技术
=========== ASP.Net+Android+IOS开发..Net培训.期待与您交流!=========== Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性 ...
- Java编程基础-反射
一.java反射 1.反射:动态获取类的信息,以及动态调用对象的方法的功能.可以理解为动态看透类的能力. 2.主要功能:在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对象:在运行时判断任意 ...
- java 编程基础 反射方式获取泛型的类型Fileld.getGenericType() 或Method.getGenericParameterTypes(); (ParameterizedType) ;getActualTypeArguments()
引言 自从JDK5以后,Java Class类增加了泛型功能,从而允许使用泛型来限制Class类,例如,String.class的类型实际上是 Class 如果 Class 对应的类暂时未知,则使 C ...
随机推荐
- go 两个数组取并集
实际生产中,对不同数组取交集.并集.差集等场景很常用,下面来说下两个数组取差集 直接上代码: //两个集合取并集 package main import "fmt" //思想: / ...
- HearthBuddy中_settings.txt的更详细参数解释
https://tieba.baidu.com/p/5275382967 默认的配置不是很合理,花了点时间读了下silverfish(也就是兄弟用的AI)的代码后也尝试修改了些参数,有没有效果仁者见仁 ...
- PCB Layout初学者必会知识总结(转)
PCB是印刷电路板(即Printed Circuit Board)的简称.印刷电路板是组装电子零件用的基板,是在通用基材上按预定设计形成点间连接及印制元件的印制板.该产品的主要功能是使各种电子零组件形 ...
- 使用redis防止重复提交
使用redis防止重复提交 其实主要思路是他的https://blog.csdn.net/u013378306/article/details/52944780 主要目前我的情况是,前后端分离的, ...
- selenium 常见事件操作
1.文本框输入内容 from selenium import webdriverdriver = webdriver.Chrome(r"C:\Users\Administrator\Desk ...
- SSM框架—Spring AOP之基于注解的声明式AspectJ(Demo)
项目结构 XML <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http ...
- Java日志体系(三)commons-logging
1.1 简介 Apache Commons Logging,又名JakartaCommons Logging (JCL),它是Apache提供的一个通用的日志接口,它的出现避免了和具体的日志方案直接耦 ...
- Python 的内置函数__import__
我们知道import语句是用来导入外部模块的,当然还有from...import...也可以,但是其实import实际上是使用builtin函数__import__来工作的. 在一些程序中,我 ...
- Cell中实现多图展示
实现的效果如下: 主要实现代码如下: // // DetailCell.m // Floral // // Created by 思 彭 on 16/9/21. // Copyright © 2016 ...
- Spring Cloud health节点通过注册中心扫描状态的简单实现
package com.zjs.web; import com.netflix.appinfo.InstanceInfo; import com.zjs.FallbackApiApplication; ...