什么是动态加载?静态呢?
new创建对象的方式称作为静态加载,而使用Class.forName("XXX")称作为动态加载,它们俩本质的区别在于静态加载的类的源程序在编译时期加载(必须存在),而动态加载的类在编译时期可以缺席(源程序不必存在)。
哪些语言是静态的?哪些是动态的?
程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。
从这个观点看,Perl,Python,Ruby是动态语言,而C++,Java,C#不是动态语言。
但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。
什么是反射?
Reflection 是 Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时 通过 Reflection APIs 取得任何一个已知名称的 class 的内部信息,包括其 modifiers(诸如 public, static 等等)、superclass(例如 Object)、实现的 interfaces,也包括 fields 和 methods 的所有 信息,并可于运行时改变 fields内容或调用 Constructor,methods。
简而言之,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
原来的加载用的好好的,为什么要使用反射?
动态加载最大限度体现了程序的灵活性,降低了类之间的耦合性。方便了框架和其他的使用。或者游戏更新的时候,不可能将游戏删除重新下载,只是下载更新包,然后由游戏程序运行时动态加载代码文件,得到更新的代码编译,这就用到了反射。反射的目的就是为了扩展未知的应用。
反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
话不多说。进入ctrl + v 贴代码模式测试。
为了更好的使用反射,这里写了两个类用来熟悉动态加载。
被加载类
准备了公有的属性、构造方法、无参方法以及有参数的方法,还有私有的属性、构造方法、无参方法以及有参数的方法。
package com.example.反射;
public class One {
public int a = 1;
private int b = 2;
public One() {}
private One(int a) {
System.out.println("私有构造方法");
}
public void demo1() {
System.out.println("调用公有方法demo1");
}
private void demo2() {
System.out.println("调用私有方法demo2");
}
public void demo3(int a) {
System.out.println("调用有参数的公有方法demo3,参数为"+a);
}
private void demo4(int b) {
System.out.println("调用有参数的私有方法demo4,参数为"+b);
}
}
测试
1 首先是对文件class文件进行加载,获得Class文件对象,获取Class文件对象的方法有三种:
1.Object ——> getClass();
2.任何数据类型(包括基本数据类型)都有一个“静态”的class属性
3.通过Class类的静态方法:forName(String className)(常用),className是'包名.类名'。
Class cl = Class.forName("com.example.反射.One");
2 获取Class对象的构造方法,通过class对象 cl 调用方法获取构造方法
* 这里需要用到Constructor类,Constructor 提供关于类的单个构造方法的信息以及对它的访问权限
* setAccessible(true)方法表示取消java语言访问检查,在访问私有属性、方法之类时需要使用
//获得公有的构造方法
Constructor con1 = cl.getConstructor();
System.out.println("调用公有"+con1);
//获得私有的构造方法
Constructor con2 = cl.getDeclaredConstructor(int.class);
con2.setAccessible(true);
System.out.println("调用私有"+con2);
3 创建 Class类对象,也可以说是上面创建的Class文件对象的对象
* 创建Class类的对象时,可以通过构造方法创建,也可以通过Class文件对象创建。
// 创建类的对象,这里通过Class文件对象创建
Object obj = cl.newInstance();
* 通过构造方法创建,自定义的构造方法创建对象时可以传入参数。
Object obj1 = con1.newInstance();
Object obj2 = con2.newInstance(5);
4 获得Class类的属性,通过Class类的对象 cl 获得属性
* getField()是获得public修饰的属性,getDeclaredField()是获得已经声明的属性(包括public,private,default,protected)
* getFields(),getDeclaredFields()返回一个属性集
//公有属性
Field field1 = cl.getField("a");
System.out.println(field1.get(obj));//得到变量的值
//私有属性
Field field2 = cl.getDeclaredField("b");
field2.setAccessible(true);//该方法表示取消java语言访问检查
//field2.set(obj, 5);//这里可以给变量重新赋值
System.out.println(field2.get(obj));
5 获取Class类的无参方法以及调用
* getMethod()是获得public修饰的方法,getDeclaredMethod()是获得已经声明的方法(包括public,private,default,protected)
* getMethods(),getDeclaredMethods()返回一个方法集
* 调用方法时通过方法对象找到Class类的对象
// 获取类对象的无参公有方法
Method m1 = cl.getMethod("demo1");
//无参私有方法
Method m2 = cl.getDeclaredMethod("demo2");
m2.setAccessible(true);//该方法表示取消java语言访问检查
// 调用方法
m1.invoke(obj);
m2.invoke(obj);
6 获取Class类的有参方法以及调用
//有参公有方法
Method m3 = cl.getMethod("demo3",int.class);
//有参私有方法
Method m4 = cl.getDeclaredMethod("demo4", int.class);
m4.setAccessible(true);
//调用方法
m3.invoke(obj,2);
m4.invoke(obj, 10);
Java的反射是框架的基础,也用于程序的更新,这些都归功于Java可以实现动态创建对象和编译。但并不是Java反射是完美的,相反,有利就有弊。反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。