Java反射原理

    说到反射,第一次用是在收费系统中使用抽象工厂+反射+配置文件中,对这段代码记忆犹新:

Imports System.Reflection
Public Class DFactory
    Dim strDB As String = System.Configuration.ConfigurationSettings.AppSettings("DBString")
    Function CreateUserInfo() As IUserInfo
        Return CType(Assembly.Load("DAL").CreateInstance("DAL.DalUserInfo" & strDB), IUserInfo)
    End Function
End Class
    用到的核心内容就是上面:Assembly.Load("DAL").CreateInstance("DAL.DalUserInfo" & strDB),当时仅限于使用,并没有深入学习,学JAVA的过程中,再次遇到索性就再学习一下,先来说说什么是反射。

反射

    反射技术出现在.NET和JAVA之前,是指程序可以访问、检测和修改它本身状态或行为的一种能力,对应到JAVA和,也就是指的JAVA程序对自身进行检查,并能直接操作程序的内部属性和方法。

    再说直白一点,就是JAVA提供了一系列API,可以在程序运行期间,得到class中内部信息,如包名、父类信息、接口信息、函数、属性等,根据这一特性,可以实现在执行期根据class文件动态生成实例等功能。

    根据class生成instance,需要class名,这个通过.NET和JAVA中的使用即可得知:

    JAVA中:Class.forName("com.tgb.person").newInstance();

    .NET中:Assembly.Load("DAL").CreateInstance("DAL.DalUserInfo" & strDB);

    他们的作用是相同的:根据包名+类名,生成类的实例,省略了new的过程,从而实现动态、延迟加载的效果。它允许程序在运行时加载、探知、使用编译期间完全未知的classes。

JAVA中的反射

    上面笼统的说了一下反射的作用,现在以JAVA为例,说明一下实现反射的APIs::Field、Constructor、Method、Class、Object:

  • Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。
  • Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。
  • Method类:提供关于类或接口上单独某个方法的信息。
  • Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
  • Object类:每个类都使用 Object 作为父类。

简单实例

    我们以Person为例。

package reflection;

public class Person {

	private String name;
	private String sex;
	private int age;
	
	private void grow()
	{
		System.out.println("im growing");
	}
	
	public void eat()
	{
		System.out.println("im eating");
	}
	public void sleep()
	{
		System.out.println("im sleeping");
	}
}

    测试类

package reflection;

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

public class Test {
	public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException {
		
/*		也可以使用:
		person one=(Person)Class.forName("reflction.Person").newInstance();
		生成类的实例*/
		Person one=new Person();
		//得到对象的类信息
		Class <?> classes=one.getClass();
		
		//获取Person类的所有方法
		Method m[] = classes.getDeclaredMethods();
		System.out.println("reflection.Person的方法:");
		for (int i = 0; i < m.length; i++)
		{
			System.out.println(m[i].toString());
		}
		System.out.println("<==================>");
		
		
		//获取Person类的所有方法
		Field f[] = classes.getDeclaredFields();
		System.out.println("reflection.Person的属性:");
		for (int i = 0; i < f.length; i++)
		{
			System.out.println(f[i].toString());
		}
		System.out.println("<==================>");

		//获取Person类的构造函数
		Constructor<?> c[] = classes.getConstructors();
		System.out.println("reflection.Person的构造函数:");
		for (int i = 0; i < c.length; i++)
		{
			System.out.println(c[i].toString());
		}
		System.out.println("<==================>");
		
		//获取Person类的接口
		Class<?> in[] = classes.getInterfaces();
		System.out.println("reflection.Person的接口:");
		for (int i = 0; i < c.length; i++)
		{
			System.out.println(in[i].toString());
		}
		System.out.println("<==================>");
	}

}

    测试结果

reflection.Person的方法:
public void reflection.Person.sleep()
private void reflection.Person.grow()
public void reflection.Person.eat()
<==================>
reflection.Person的属性:
private java.lang.String reflection.Person.name
private java.lang.String reflection.Person.sex
private int reflection.Person.age
<==================>
reflection.Person的构造函数:
public reflection.Person()
<==================>
reflection.Person的接口:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
	at reflection.Test.main(Test.java:48)

    分析

    demo比较简单,查找到一个类后,生成实例,再进一步使用反射获取到类的信息。

    以上有两点需要注意:即使是类的私有属性,也反射出来了;因为Person类并没有实现任何接口,故抛出异常。

原理解释

    理解有限,下面的图算是抛砖引玉:

    

    上图是从加载到实例化出对象的过程概览,我们说的反射,实际上是方法区的Person.class和堆中person对象之间的关系。

    正是因为这种相互的引用关系,使得class和对象之间可以相互得到,从而实现灵活、延迟、动态的效果,也给了开发人员更多的操作方式和想象空间。

总结

    反射说到这里先到此为止,如果有兴趣可以深入学习一下classloader相关内容,再学习反射就容易许多。那么,反射具体有哪些应用的场景,详见下篇博客。


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值