虽然以前(貌似是很久以前)用.net实现反射了,但当时也是只是在对数据连接的时候使用了抽象工厂方法时用的一点,当时也没深究怎么就加载上了呀,怎么个原理呀,记得当时能实现也就不错了。
而这个视频讲的java反射就比较详细了。视频可以从这里下载:
http://www.51px.asia/px/jiangtang.aspx
下面是我的理解,看完视频之后的。
什么是反射?
根据类的信息来加载这个类,然后构造这个对象,然后再调用这个类中的属性和方法。(这句话是那个老师说的)
我个人理解就是,反射就是让你可以随便调用你没有实例化的东西,因为类在实例化之后就固定了,而反射就打破了这种固定模式,即使你的类没有被实例化加载到内存中,你一样可以在你要使用的时候找到它。
张孝祥说:“反射就是把Java类中的各种成分映射成相应的java类”,其细节方面就是你通过自己编写代码来将类加载到java虚拟机中,也有人称“反射”为“类的自解析”。
通过反射可以让程序变得更加灵活。
反射的应用?
就像是我开头说的,在.net中连接数据库时为了让程序可以灵活的连接不通的数据库,操作不同的数据库我们使用了抽象工厂+反射+配置文件来实现。
这意味着反射可以用在对“松耦合”要求很高的场合。
还有一个很常见的例子,视频中也有提到,就是无论你用微软的“死丢丢”也就是vs了,还是java的IDE——eclipse,你编写好一个类之后你调用时,你只需将类实例化,然后实例化对象后面点一下就能出来看访问的属性和方法的列表,这个也是通过反射来实现的。
我冒昧的猜测一下其中的原理,首先你写好一个类之后,编译器一边都会直接进行检查的,也就是进行编译,如果存在编译时期错误就会提示。当你实例化这个类的时候它会进行编译,但这里不是执行,不会加载到内存中。这时你再使用你已经实例化好的类时,它会根据你你提供的类的信息,也就是你类的类型,通过反射找到里面的方法和属性,然后生成列表实现出来。(这段文字还待我探讨,大家踊跃拍砖)
反射的实现?
通过视频中介绍java中主要是通过四种方式来进行class的加载的:
1.classLoader
2.类名.class.
3.对象名.getClass()
4.Class.forName();
我个人觉得1、4是比较常用的,因为这两个可以通过类的信息找到类,进而将类加载的JVM中。你只需传递给他们字符串就ok。
下面是两个小练习可以练习一下:
1. classLoader
import java.lang.reflect.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
Class c1;
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
try {
//加载student类
c1 = classLoader.loadClass("demo1.Student");
System.out.println(c1);
//获得加载类的所有方法
Field[] fields = c1.getFields();
//遍历输出
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i].getName());
System.out.println(fields[i].getType());
System.out.println(fields[i].getModifiers());
}
Field stuName = c1.getField("name");
//获得c1中的方法
Class[] parameterTypes = {};
Method method = c1.getMethod("say", parameterTypes);
//实例化c1对象
Object obj = c1.newInstance();
//通过实例化后的对象调用c1中方法
method.invoke(obj,null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Student {
public String name;
public int age;
protected String nicai;
private int hh;
public void say() {
System.out.println("I‘m student");
}
}
2. forName方式
只需要把上面的
c1 = classLoader.loadClass("demo1.Student");
改成c1 = Class.forName("demo1.Student");即可。
通过这两段代码可以看出使用反射,我只需要知道我要调用的类的名字,就可以加载并使用它,并且这样可以更加灵活。你可以把字符串”demo1.Student”这个信息放到一个文件中,或者是放到数据库中,这样程序就不会那么死板了。
因为个人能力有限,还没有透彻的领悟到java反射的真谛,所以就说这么多吧。
- from the5fire.com
----EOF-----
微信公众号:Python程序员杂谈
微信公众号:Python程序员杂谈