基于反射的动态调用-不止是code和oop,还有类加载方案
2016-02-27 22:16
330 查看
先给出基础类资源的代码,很容易理解,不做过多介绍:
然后再介绍主函数:
执行效果:
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这个博客对我理解以上内容有很大帮助。
关于反射的意义,反射的效率是低于普通构造方法的,但是它作为一种理念,即动态加载和自控制,是很值得学习的,同时,反射机制也是在处理大型程序编码中可能用到的,因为那个时候你对整个项目也许就不会了解的面面俱到了。
以上。
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这个博客对我理解以上内容有很大帮助。
关于反射的意义,反射的效率是低于普通构造方法的,但是它作为一种理念,即动态加载和自控制,是很值得学习的,同时,反射机制也是在处理大型程序编码中可能用到的,因为那个时候你对整个项目也许就不会了解的面面俱到了。
以上。
相关文章推荐
- Linux实用操作命令(不断更新)
- linux常用命令
- linux c 代码测试之内存越界及内存泄露
- 从源码看Handler和Looper
- OpenGL ES纹理映射坐标对应
- linux(ubuntu)hadoop系统迁移或使用新主机产生问题
- linux c 编程模板总结(一)
- python结合shell查询google关键词排名的实现代码
- linux内核分析 第一周
- Hadoop 6、第一个mapreduce程序 WordCount
- Linux Is Not Matrix——使用域名访问局域网网站
- linux(ubuntu)mysql自动安装
- 监控知识点概述
- Apache的工作模式prefork、worker、event
- Varnish配置文件详解(架构师之路)
- 如何分析业务问题
- Linux SSH安全策略限制IP登录方法(转)
- opencv保存avi视频
- shell编程练习002(20160227)
- 1044 Shopping in Mars