您的位置:首页 > 运维架构

基于反射的动态调用-不止是code和oop,还有类加载方案

2016-02-27 22:16 330 查看
先给出基础类资源的代码,很容易理解,不做过多介绍:

package oop;
interface t {
public static final String name="zhangph";
}
public class Father implements t{
private static int mem;
static {
System.out.println("这是父类");//因为你不曾常用反射,所以加上这段代码显示区别
}
public Father() {
this.mem=258;
}
public String toString() {
return "there is the Object named father and the mem="+this.mem;
}
public void outPut() {
System.out.println("father function"+mem);
}
public void setMem(int m) {
this.mem=m;
}
public void test(int x) {
System.out.println("参数为"+x);
}
}


package oop;
import java.lang.reflect.Field;
public class Child extends Father{
private static int mem;
static {
System.out.println("class is here");
Static();
System.out.println(mem);
}
public Child() {
System.out.println("子类版本构造函数");
System.out.println("子类的mem初始值"+mem);
this.mem=2;
System.out.println("子类的mem最终值"+mem);
}
public void Cg() throws Exception {
this.mem=6;
System.out.println("子类的Cg方法"+mem);
}
public  String toString() {
return "child"+super.toString();
}
public static void Static () {
System.out.println("this is a static function");
}
}


然后再介绍主函数:

package oop;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Random;
public class oop {
private static void Print( Object s) {
System.out.println(s.toString());
}
public static void main(String []args) {
Class<?> cl1 = null,cl2=null,cl3=null;
try {
Print("1");
cl1=Class.forName("oop.Father");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Print("2");
cl2=Father.class;
Print("3");
cl3=new Father().getClass();
Print("ls");
Print(cl1.getName());
Print(cl2.getName());
Print(cl3.getName());
Print("***********************");
try {
Father f=(Father)cl1.newInstance();
Field field=cl1.getDeclaredField("mem");
field.setAccessible(true);
field.set(f,1234);
f.outPut();
Method method1=cl1.getMethod("test",int.class);
method1.invoke(cl1.newInstance(),5);
Method method2=cl1.getMethod("outPut" );
method2.invoke(cl1.newInstance());
Method method3=cl1.getMethod("toString");
String ss=(String) method3.invoke(cl1.newInstance());
Print(ss);
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (NoSuchFieldException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (Exception e) {
System.out.println("error");
}

}

}



执行效果:

1
这是父类
2
3
ls
oop.Father
oop.Father
oop.Father
***********************
father function1234
参数为5
father function258

there is the Object named father and the mem=258



下面着重分析第三个程序:

在第15、21、23行,你分别看到三种加载Class对象引用的方法。

forName()方法在编译时不会被检查,是完全的运行时调用,所以需要异常检查。对于Class对象引用,你可能之前接触很少(也许只是使用Mysql包的时候接触过),但是它本身不难理解,类是程序的一部分,java中一切皆对象,所以自然而然每个类都对应着一个Class对象(泛型的),如你所知,每编译一个类,都会产生对应的.class文件。

我们知道,java程序在它开始运行之前并非完全被加载。

JVM的类加载系统会首先检查是否加载了.class文件的字节码,而JVM加载一个类的开始,一定是创建了对这个类的静态引用。

基于上面这句话,我们可以推断,构造方法也是静态方法

我们回到15、21、23行,此时可以很明白的理解15和23行,23行是调用构造方法导入class类,forName方法直接加载.class对象。在forName方法中,我们也可以看到类体的静态语句被执行。

然后介绍21行,21行是使用一种叫做类字面常量的方法来生成的对Class对象的引用。这样做和使用forName的区别是它是在编译时检查的,所以不需要放在try块里面。同时,类字面常量的加载实现了足够的惰性,你可以看出,类字面常量并未加载类中的静态语句。

在25、26、27行中,我们可以看到Class对象引用的使用方法。实际上,Class对象引用有各种各样的get方法,例如

//getFields() 获取所有数据域
//getInterfaces() 获取实现的接口名
//getMethods() 获取所有的非构造函数
//getConstructors()获取构造函数
//getSuperclass()获取直接超类

下面介绍反射的调用规则。

在上面代码的30-41行,形象介绍了反射的使用方法。通过newInstance()生成对应类的对象引用,实际上这个方法的作用就类似于构造方法。同样,也通过getDeclaredField()方法修改静态域等。

在35到41行中,介绍了反射的普通方法调用,我分别举例了一个传参的和无参以及带返回值的方法,你可以类比其它。

以上是反射的核心部分内容,除了java编程思想,/article/4657750.html这个博客对我理解以上内容有很大帮助。

关于反射的意义,反射的效率是低于普通构造方法的,但是它作为一种理念,即动态加载和自控制,是很值得学习的,同时,反射机制也是在处理大型程序编码中可能用到的,因为那个时候你对整个项目也许就不会了解的面面俱到了。

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