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

认识反射:使用反射实现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;
	}
	@Override
	public 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.User
		String name = c.getName();//com.gos.java.standard.User
		String simpleName = c.getSimpleName();//User
		System.out.println(Modifier.toString(c.getModifiers()));//public final    也就是对应的类的声明中class关键字之前的关键字
		System.out.println(c.getPackage());//package com.gos.java.standard
		System.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



你可能感兴趣的:(庖丁解牛——Java反射解析一个类)