庖丁解牛——Java反射解析一个类

来源:互联网 发布:国际数据是什么 编辑:程序博客网 时间:2024/04/30 03:26

认识反射:使用反射实现toString的功能

1.main方法中的测试代码

Set<Fruit> s = new HashSet<Fruit>();s.add(new Peach());User user = (User) c.getDeclaredConstructor(Integer.class , String.class , boolean.class , Set.class , long.class , String.class , boolean.class , String.class , boolean.class).newInstance(11 , "XIAOMING" , false , s , 123456789 , "XM" , true , "很高-->像姚明一样高" , true);System.out.println(user.toString());//调用方法,在反射中实现toString方法功能Field[] fs = c.getDeclaredFields();StringBuilder sb = new StringBuilder();sb.append(c.getSimpleName()).append(" [");for(int i = 0 ; i < fs.length ; i++){Method m= getMethod(fs[i] , c);if(m != null){sb.append(fs[i].getName()).append("=");sb.append(m.invoke(user));sb = (i == fs.length -1 )?sb.append("]"):sb.append(", ");}}System.out.println(sb.toString().equals(user.toString()));//true


 2.生成get方法

public static Method getMethod(Field f , Class<?> c) throws NoSuchMethodException, SecurityException{String fName = f.getName();String methodName = "get";Type type = f.getGenericType();if(type == boolean.class || type == Boolean.class){fName = fName.startsWith("is")?fName.replaceFirst("is", ""):fName;fName = fName.length()==0?"is":fName;methodName = "is";}methodName += fName.substring(0, 1).toUpperCase() + fName.substring(1);System.out.println(methodName);Method m = null;try{m = c.getDeclaredMethod(methodName);}catch(Exception e){if((type == boolean.class || type == Boolean.class)){methodName = "get" + methodName.substring(2);m = c.getDeclaredMethod(methodName);}}return m;}

3.生成set方法

public static Method setMethod(Field f , Class<?> c) throws NoSuchMethodException, SecurityException{String fName = f.getName();String methodName = "set";methodName += fName.substring(0, 1).toUpperCase() + fName.substring(1);Method m = c.getDeclaredMethod(methodName);return m;}
从上面的小例子可以看出,利用反射,在程序的运行过程中,完成了对一个类的结构分析,通过获得类的域、调用类的方法等操作,模拟出了toString方法的功能。

一、什么是反射

    反射库(reflection library)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵Java代码的程序。能够分析类能力的程序称为反射(reflective)。

二、反射的作用

反射机制的功能极其强大,在下面可以看到,反射机制可以用来:

  • 在运行中查看对象

  • 在运行中分析类的能力

  • 实现通用的数组操作代码

  • 利用Method对象

反射是一种功能强大且复杂的机制。使用它的主要人员是工具构造者,而不是应用程序员。

三、利用用反射检查类的结构

java.lang.reflect包中有三个类FieldMethodConstructor和接口Annotation分别用于描述类的域、方法、构造器和类注解。Annotation可被用于 packagestypes(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。所以在FieldMethodConstructor三个类中都有getAnnotation方法。

检查类的结构主要使用的FieldMethodConstructor这三个类,三者都有一个叫做getName的方法,用来返回对应的名称。Field类有一个getType方法,用来返回一个整型数值,用不同的位开关描述publicstatic这样的修饰符使用情况。另外还可以利用java.lang.reflect包中的Modifier类的静态方法分析getModifiers返回的整型数值。

Class类中的getFieldsgetMethodsgetConstructors方法分别返回类提供的public域、方法和构造器,其中包括超类的公有成员Class类的getDeclareFieldsgetDeclareMethodsgetDeclareConstructors方法分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护成员,但不包括超类的成员

四、测试代码

1.User.java

package com.gos.java.standard;import java.io.Serializable;import java.util.Set;import javax.persistence.Entity;@Entity(name="user")public final class User extends Person implements Serializable{private static final long serialVersionUID = 1L;private Integer userId;private String cname;private boolean sex;private Set<Fruit> loveFruits;private long idNo;private String phoneticize;private boolean isMarr;private String isTall;private boolean is;public boolean getIs() {return is;}public void setIs(boolean is) {this.is = is;}public String getIsTall() {return isTall;}public void setIsTall(String isTall) {this.isTall = isTall;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public String getCname() {return cname;}public void setCname(String cname) {this.cname = cname;}public boolean isSex() {return sex;}public void setSex(boolean sex) {this.sex = sex;}public Set<Fruit> getLoveFruits() {return loveFruits;}public void setLoveFruits(Set<Fruit> loveFruits) {this.loveFruits = loveFruits;}public long getIdNo() {return idNo;}public void setIdNo(long idNo) {this.idNo = idNo;}public String getPhoneticize() {return phoneticize;}public void setPhoneticize(String phoneticize) {this.phoneticize = phoneticize;}@Overridepublic String toString() {return "User [userId=" + userId + ", cname=" + cname + ", sex=" + sex+ ", loveFruits=" + loveFruits + ", idNo=" + idNo+ ", phoneticize=" + phoneticize + ", isMarr=" + isMarr+ ", isTall=" + isTall + ", is=" + is + "]";}public User(Integer userId, String cname, boolean sex,Set<Fruit> loveFruits, long idNo, String phoneticize) {super();this.userId = userId;this.cname = cname;this.sex = sex;this.loveFruits = loveFruits;this.idNo = idNo;this.phoneticize = phoneticize;}public User() {super();}public User(Integer userId, String cname) {super();this.userId = userId;this.cname = cname;}public void run(){if(cname != null)System.out.println(this.cname + " is running!");}public boolean isMarr() {return isMarr;}public void setMarr(boolean isMarr) {this.isMarr = isMarr;}public User(Integer userId, String cname, boolean sex,Set<Fruit> loveFruits, long idNo, String phoneticize,boolean isMarr, String isTall, boolean is) {super();this.userId = userId;this.cname = cname;this.sex = sex;this.loveFruits = loveFruits;this.idNo = idNo;this.phoneticize = phoneticize;this.isMarr = isMarr;this.isTall = isTall;this.is = is;}}

2.Test.java#main

//Class常用方法及与常用类的方法/** * 1.获取名称、类信息 * 2.获取属性信息 * 3.获取方法信息 * 4.生成类实例 * 5.类型判断 * 6.调用方法 * 7.读取注释的信息 *///获取名称及类的相关信息Class c = User.class;String canonicalName = c.getCanonicalName();//com.gos.java.standard.UserString name = c.getName();//com.gos.java.standard.UserString simpleName = c.getSimpleName();//UserSystem.out.println(Modifier.toString(c.getModifiers()));//public final    也就是对应的类的声明中class关键字之前的关键字System.out.println(c.getPackage());//package com.gos.java.standardSystem.out.println(c.getSuperclass());//class com.gos.java.standard.Person//获取注解及信息Entity anno = (Entity) c.getAnnotation(Entity.class);System.out.println(anno.name());//user//获取属性信息Field[] fields = c.getDeclaredFields();for(Field f:fields){String fName = f.getName();//获得每个属性的名称Type type = f.getType();//获取每个属性的类型//……接下来的代码可能就是根据不同数据类型进行不同的处理流程}//获取具体的某个属性System.out.println(c.getDeclaredField("sex"));//private boolean com.gos.java.standard.User.sex//获取方法信息Method[] methods = c.getDeclaredMethods();for(Method m : methods){System.out.println(m.getName());//获得每个方法的名称}//获得某个具体的方法System.out.println(c.getDeclaredMethod("isSex"));//public void com.gos.java.standard.User.setSex(boolean)//生成实例//User user = (User)c.newInstance();//生成一个空的实例,在User中需要提供午餐构造器,或是不提供任何构造器(此时默认无参构造器)

五、各个类的在线中文文档

Class:http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/Class.html

Field:http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/reflect/Field.html

Method:http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/reflect/Method.html

Constructor:http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/reflect/Constructor.html

Annotation:http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/annotation/Annotation.html


0 0