您的位置:首页 > 编程语言 > Java开发

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

2016-03-01 19:16 573 查看

认识反射:使用反射实现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包中有三个类Field、Method、Constructor和接口Annotation分别用于描述类的域、方法、构造器和类注解。Annotation可被用于
packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。所以在Field、Method、Constructor三个类中都有getAnnotation方法。
检查类的结构主要使用的Field、Method和Constructor这三个类,三者都有一个叫做getName的方法,用来返回对应的名称。Field类有一个getType方法,用来返回一个整型数值,用不同的位开关描述public和static这样的修饰符使用情况。另外还可以利用java.lang.reflect包中的Modifier类的静态方法分析getModifiers返回的整型数值。
Class类中的getFields、getMethods、getConstructors方法分别返回类提供的public域、方法和构造器,其中包括超类的公有成员。Class类的getDeclareFields、getDeclareMethods、getDeclareConstructors方法分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护成员,但不包括超类的成员

四、测试代码

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


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: