\(^_^)/ Java 反射

http://blog.csdn.net/libo2006/article/details/1631961

http://www.cnblogs.com/octobershiner/archive/2012/03/18/2404751.html

http://www.ibm.com/developerworks/cn/java/j-dyn0603/

http://lavasoft.blog.51cto.com/62575/43218/

http://www.importnew.com/9078.html

 反射的实际用途:
1.springmvc、struts2等mvc框架的form提交时获取表单的值使用反射
2.动态代理、动态加载类
3.spring的aop、ioc使用反射,事务控制
4.运行过程中对未知的类进行初始化
5.数据库结果集、xml、json转换成Java Bean对象时
6.Java运行时监控、调试、测试等工具

扫描二维码关注公众号,回复: 831937 查看本文章

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

Java反射机制主要提供了以下功能: 

    在运行时判断任意一个对象所属的类;

    在运行时构造任意一个类的对象;

    在运行时判断任意一个类所具有的成员变量和方法;

    在运行时调用任意一个对象的方法;生成动态代理。

Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。如果您想借由“修改Java标准库源码”来观察Class 对象的实际生成时机(例如在Class的constructor内添加一个println()),这样是行不通的!因为Class并没有public constructor。

public final class Class<T> implements java.io.Serializable,

                              java.lang.reflect.GenericDeclaration,

                              java.lang.reflect.Type,

                              java.lang.reflect.AnnotatedElement {

  private Class() {}

  public String toString() {

        return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))  + getName();

  }

  @CallerSensitive

  public static Class<?> forName(String className) throws ClassNotFoundException {

      return forName0(className, true,ClassLoader.getClassLoader(Reflection.getCallerClass()));

  }

  ...

}

注意它的private Class() {},意指不允许任何人经由编程方式产生Class object。是的,其object 只能由JVM 产生。

“Class” object的取得途径

Java允许我们从多种管道为一个class生成对应的Class object。

Class object 诞生管道

示例

运用getClass()

注:每个class 都有此函数

String str = "abc";

Class c1 = str.getClass();

运用

Class.getSuperclass()2

Button b = new Button();

Class c1 = b.getClass();

Class c2 = c1.getSuperclass();

运用static method

Class.forName()

(最常被使用)

Class c1 = Class.forName ("java.lang.String");

Class c2 = Class.forName ("java.awt.Button");

Class c3 = Class.forName ("java.util.LinkedList$Entry");

Class c4 = Class.forName ("I");

Class c5 = Class.forName ("[I");

运用

.class 语法

Class c1 = String.class;

Class c2 = java.awt.Button.class;

Class c3 = Main.InnerClass.class;

Class c4 = int.class;

Class c5 = int[].class;

运用

primitive wrapper classes

的TYPE 语法

 

Class c1 = Boolean.TYPE;

Class c2 = Byte.TYPE;

Class c3 = Character.TYPE;

Class c4 = Short.TYPE;

Class c5 = Integer.TYPE;

Class c6 = Long.TYPE;

Class c7 = Float.TYPE;

Class c8 = Double.TYPE;

Class c9 = Void.TYPE;

Java classes 各成份所对应的Reflection APIs

Java class 内部模块

Java class 内部模块说明

相应之Reflection API,多半为Class methods。

返回值类型(return type)

(1) package

class隶属哪个package

getPackage()

Package

(2) import

class导入哪些classes

无直接对应之API。

 

(3) modifier

class(或methods, fields)的属性

 

int getModifiers()

Modifier.toString(int)

Modifier.isInterface(int)

int

String

bool

(4) class name or interface name

class/interface

名称getName()

String

(5) type parameters

参数化类型的名称

getTypeParameters()

TypeVariable <Class>[]

(6) base class

base class(只可能一个)

getSuperClass()

Class

(7) implemented interfaces

实现有哪些interfaces

getInterfaces()

Class[]

 

(8) inner classes

内部classes

getDeclaredClasses()

Class[]

(8') outer class

如果我们观察的class 本身是inner classes,那么相对它就会有个outer class。

getDeclaringClass()

Class

(9) constructors

构造函数getDeclaredConstructors()

不论 public 或private 或其它access level,皆可获得。另有功能近似之取得函数。

Constructor[]

(10) methods

操作函数getDeclaredMethods()

不论 public 或private 或其它access level,皆可获得。另有功能近似之取得函数。

Method[]

(11) fields

字段(成员变量)

getDeclaredFields()不论public 或private 或其它access level,皆可获得。另有功能近似之取得函数。

Field[]

 

Reflection的另三个动态性质

(1) 运行时生成instances,(2) 执行期唤起methods,(3) 运行时改动fields。

运行时生成instances

欲生成对象实体,在Reflection 动态机制中有两种作法:

一个针对“无自变量ctor”:调用Class的newInstance()

一个针对“带参数ctor”:不再调用Class的newInstance(),而是调用Constructor 的newInstance()。

运行时调用methods

首先准备一个Class[]做为ctor的参数类型,然后以此为自变量调用getMethod(),获得特定的Method object。接下来准备一个Object[]放置自变量,然后调用上述所得之特定Method object的invoke()。

运行时变更fields内容

首先调用Class的getField()并指定field名称。获得特定的Field object之后便可直接调用Field的get()和set()

使用java的反射机制,一般需要遵循三步:

1、获得你想操作类的Class对象

2、通过第一步获得的Class对象去取得操作类的方法或是属性名

3、操作第二步取得的方法或是属性

Java运行的时候,某个类无论生成多少个对象,他们都会对应同一个Class对象,它表示正在运行程序中的类和接口。

如何取得操作类的Class对象,常用的有三种方式

1、调用Class的静态方法forName,如上例;

2、使用类的.class语法,如:Class<?> cls = String.class;

3、调用对象的getClass方法,如:String str = "abc";Class<?> cls = str .getClass();

在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中

–Class类:代表一个类

–Field类:代表类的成员变量(成员变量也成为类属性)

–Method类:代表类的方法

–Constructor类:代表类的构造方法

–Array类:提供动态创建数组,以及访问数组的元素的静态方法

若想通过类的不带参数的构造方法来生成对象,我们有两种方式:

1)先获得Class对象,然后通过该Class对象的newInstance方法直接获得即可。如

Class<?> classType = String.class; 

Object o = classType.newInstance();

2)先获得Class对象,然后通过该Class对象获得所对应的Constructor对象,再通过该Constructor对象的newInstance方法生成。如

Class<?> classType = Customer.class;

Constructor constructor  =classType.getConstructor(new Class[]{});

Object o1 = constructor.newInstance(new Object[]{});

若想通过类的带参数的构造方法来生成对象,只能使用下面这种方式:

Class<?> classType = Customer.class;

Constructor constructor2  = classType.getConstructor(new Class[]{String.class,int.class});

Object o2 = constructor.newInstance(new Object[]{"张三",20});

安全性和反射:

在处理反射时安全性是一个较复杂的问题。反射经常由框架型代码使用,由于这一点,我们可能希望框架能够全面接入代码,无需考虑常规的接入限制。但是,在其它情况下,不受控制的接入会带来严重的安全性风险,例如当代码在不值得信任的代码共享的环境中运行时。

由于这些互相矛盾的需求,Java编程语言定义一种多级别方法来处理反射的安全性。基本模式是对反射实施与应用于源代码接入相同的限制:

从任意位置到类公共组件的接入 

类自身外部无任何到私有组件的接入 

受保护和打包(缺省接入)组件的有限接入 

不过至少有些时候,围绕这些限制还有一种简单的方法。我们可以在我们所写的类中,扩展一个普通的基本类java.lang.reflect.AccessibleObject 类。这个类定义了一种setAccessible方法,使我们能够启动或关闭对这些类中其中一个类的实例的接入检测。唯一的问题在于如果使用了安全性管理器,它将检测正在关闭接入检测的代码是否许可了这样做。如果未许可,安全性管理器抛出一个例外。

Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象(根据安全性限制),无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。例如,反射经常在持续存储对象为数据库、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。

但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。

许多应用中更严重的一个缺点是使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比相应的直接代码更复杂,正如性能比较的代码实例中看到的一样。解决这些问题的最佳方案是保守地使用反射——仅在它可以真正增加灵活性的地方——记录其在目标类中的使用。

Java反射的典型应用

Spring框架:IOC(控制反转)、白盒测试、Hibernate框架:关联映射等

“反射(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为。”这个概念常常会和内省(Introspection)混淆,以下是这两个术语在Wikipedia中的解释:

内省用于在运行时检测某个对象的类型和其包含的属性;

反射用于在运行时检测和修改某个对象的结构及其行为。

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTest {

	// 该方法实现对Customer的拷贝
	public static Object copy(Object object) throws Exception {
		Class<?> classType = object.getClass();

		Object objectCopy = classType.getConstructor(new Class[] {})
				.newInstance(new Object[] {});

		Field[] fields = classType.getDeclaredFields();

		for (Field field : fields) {
			String name = field.getName();
			String firstLetter = name.substring(0, 1).toUpperCase();// 将属性的首字母转换为大写

			String getMethodName = "get" + firstLetter + name.substring(1);
			String setMethodName = "set" + firstLetter + name.substring(1);

			Method getMethod = classType.getMethod(getMethodName,
					new Class[] {});
			Method setMethod = classType.getMethod(setMethodName,
					new Class[] { field.getType() });

			Object value = getMethod.invoke(object, new Object[] {});

			setMethod.invoke(objectCopy, new Object[] { value });
		}

		return objectCopy;
	}

	public static void main(String[] args) throws Exception {

		Customer c = new Customer("Tom", 20);
		c.setId(1L);
		Object o = copy(c);
		Customer customerCopy = (Customer) o;

		System.out.println(customerCopy.getId() + "," + customerCopy.getName()
				+ "," + customerCopy.getAge());

	}

}

class Customer {
	private long id;
	private String name;
	private int age;

	public Customer() {

	}

	public Customer(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}
import java.lang.reflect.Array;

// Java.lang.Array类提供了动态创建和访问数组元素的各种静态方法。
public class ArrayTester {
	
	public static void main(String[] args) {
		
		Class<?> classType = String.class;
		
		Object array = Array.newInstance(classType, 10);
		
		Array.set(array, 5, "hello");
		
		String s = (String) Array.get(array, 5);
		
		System.out.println(s);
	}
}
import java.lang.reflect.Array;

// Integer.TYPE 返回的是int所对应的Class对象
// Integer.class 返回的是Integer所对应的Class对象

public class ArrayTester2 {
	
	public static void main(String[] args) {
		
		int[] dims = new int[]{5,10,15};
		
		Object array = Array.newInstance(Integer.TYPE, dims);
		
		Object arrayObj = Array.get(array, 3);
		
//		Class<?> classType = arrayObj.getClass().getComponentType();
//		
//		System.out.println(classType);
		
		arrayObj = Array.get(arrayObj, 5);
		
		Array.set(arrayObj, 10, 37);
		
		int[][][] arrayCast = (int[][][]) array;
		
		System.out.println(arrayCast[3][5][10]);
		
	}
	
}
package cn.netjava.session;
 
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
 
import cn.netjava.factory.Connect2DBFactory;
import cn.netjava.pojo.UserInfo;
 
public class NetJavaSession {
    /**
     * 解析出保存对象的sql语句
     *
     * @param object
     *            :需要保存的对象
     * @return:保存对象的sql语句
     */
    public static String getSaveObjectSql(Object object) {
        // 定义一个sql字符串
        String sql = "insert into ";
        // 得到对象的类
        Class c = object.getClass();
        // 得到对象中所有的方法
        Method[] methods = c.getMethods();
        // 得到对象中所有的属性
        Field[] fields = c.getFields();
        // 得到对象类的名字
        String cName = c.getName();
        // 从类的名字中解析出表名
        String tableName = cName.substring(cName.lastIndexOf(".") + 1,
                cName.length());
        sql += tableName + "(";
        List<String> mList = new ArrayList<String>();
        List vList = new ArrayList();
        for (Method method : methods) {
            String mName = method.getName();
            if (mName.startsWith("get") && !mName.startsWith("getClass")) {
                String fieldName = mName.substring(3, mName.length());
                mList.add(fieldName);
                System.out.println("字段名字----->" + fieldName);
                try {
                    Object value = method.invoke(object, null);
                    System.out.println("执行方法返回的值:" + value);
                    if (value instanceof String) {
                        vList.add("\"" + value + "\"");
                        System.out.println("字段值------>" + value);
                    } else {
                        vList.add(value);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        for (int i = 0; i < mList.size(); i++) {
            if (i < mList.size() - 1) {
                sql += mList.get(i) + ",";
            } else {
                sql += mList.get(i) + ") values(";
            }
        }
        for (int i = 0; i < vList.size(); i++) {
            if (i < vList.size() - 1) {
                sql += vList.get(i) + ",";
            } else {
                sql += vList.get(i) + ")";
            }
        }
 
        return sql;
    }
 
    public static List getDatasFromDB(String tableName, int Id) {
 
        return null;
 
    }
 
    /**
     * 将对象保存到数据库中
     *
     * @param object
     *            :需要保存的对象
     * @return:方法执行的结果;1:表示成功,0:表示失败
     */
    public int saveObject(Object object) {
        Connection con = Connect2DBFactory.getDBConnection();
        String sql = getSaveObjectSql(object);
        try {
            // Statement statement=(Statement) con.createStatement();
            PreparedStatement psmt = con.prepareStatement(sql);
            psmt.executeUpdate();
            return 1;
        } catch (SQLException e) {
            e.printStackTrace();
            return 0;
        }
    }
 
    /**
     * 从数据库中取得对象
     *
     * @param arg0
     *            :对象所属的类
     * @param id
     *            :对象的id
     * @return:需要查找的对象
     */
    public Object getObject(String className, int Id) {
        // 得到表名字
        String tableName = className.substring(className.lastIndexOf(".") + 1,
                className.length());
        // 根据类名来创建Class对象
        Class c = null;
        try {
            c = Class.forName(className);
 
        } catch (ClassNotFoundException e1) {
 
            e1.printStackTrace();
        }
        // 拼凑查询sql语句
        String sql = "select * from " + tableName + " where Id=" + Id;
        System.out.println("查找sql语句:" + sql);
        // 获得数据库链接
        Connection con = Connect2DBFactory.getDBConnection();
        // 创建类的实例
        Object obj = null;
        try {
 
            Statement stm = con.createStatement();
            // 得到执行查寻语句返回的结果集
            ResultSet set = stm.executeQuery(sql);
            // 得到对象的方法数组
            Method[] methods = c.getMethods();
            // 遍历结果集
            while (set.next()) {
                obj = c.newInstance();
                // 遍历对象的方法
                for (Method method : methods) {
                    String methodName = method.getName();
                    // 如果对象的方法以set开头
                    if (methodName.startsWith("set")) {
                        // 根据方法名字得到数据表格中字段的名字
                        String columnName = methodName.substring(3,
                                methodName.length());
                        // 得到方法的参数类型
                        Class[] parmts = method.getParameterTypes();
                        if (parmts[0] == String.class) {
                            // 如果参数为String类型,则从结果集中按照列名取得对应的值,并且执行改set方法
                            method.invoke(obj, set.getString(columnName));
                        }
                        if (parmts[0] == int.class) {
                            method.invoke(obj, set.getInt(columnName));
                        }
                    }
 
                }
            }
 
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
}
public String outObjPropertyString(Object obj) 
    {
        StringBuffer sb = new StringBuffer();
        if(null != obj)
        {
            try {
                this.getPropertyString(obj, sb);
            }
            catch (Exception e) {
                logger.log("outObjPropertyString is error " + e.getMessage());
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
    
    public String getPropertyString(Object entityName, StringBuffer sb) throws Exception { 
        Class c = entityName.getClass(); 
        Field field [] = c.getDeclaredFields(); 
        Object obj = null;
        String classname = "";
        Object tempObj = null;
        sb.append("------ " + " begin ------\n"); 
        for(Field f : field){ 

            sb.append(f.getName()); 
            sb.append(" : "); 
            obj = invokeMethod(entityName,f.getName(),f.getType(),null);
            if(null != obj)
            {
                if(obj.getClass().isArray())
                {
                    for (int i=0;i<Array.getLength(obj);i++) 
                    {
                        tempObj = Array.get(obj, i);
                        if(tempObj.getClass().isPrimitive())
                        {
                            sb.append(tempObj.toString());
                        }
                        else if(tempObj instanceof String)
                        {
                            sb.append(tempObj.toString());
                        }
                        else if(tempObj instanceof Date)
                        {
                            sb.append(tempObj.toString());
                        }
                        else if(tempObj instanceof Number)
                        {
                            sb.append(tempObj.toString());
                        }
                        else
                        {
                            this.getPropertyString(tempObj , sb);
                        }
                    }
                }
                
                classname = obj.getClass().getName();
                if(classname.indexOf("com.cignacmb.core.model.") > -1)
                {
                    this.getPropertyString(obj , sb);
                }

            }
            
            /*if (f.getType() == Address.class) 
            {
                this.getPropertyString(obj , sb);
            }*/
            
            sb.append(obj); 
            sb.append("\n"); 
        } 
        sb.append("------ " + " end ------\n"); 
        return sb.toString(); 
    } 
    
    
    public Object invokeMethod(Object owner, String methodName, Class fieldType, Object[] args) throws Exception{
        Class ownerClass = owner.getClass();

        methodName = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
        Method method = null;
        try {
            if(fieldType == boolean.class)
            {
                method = ownerClass.getMethod("is" + methodName);
            }
            else
            {
                method = ownerClass.getMethod("get" + methodName);
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            //e.printStackTrace();

            return " can't find 'get" + methodName + "' method";
        }

        return method.invoke(owner);
        
    }

但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误

所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数

猜你喜欢

转载自yanguz123.iteye.com/blog/2211929