反射机制事理图

获取字节码文件工具的三种办法

Class clazz1 = Class.forName(“全限定类名”);//通过Class类中的静态方法forName,直接获取到一个类的字节码文件工具,此时该类还是源文件阶段,并没有变为字节码文件。
Class clazz2 = Person.class;//当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件工具,也便是获取自己, 该类处于字节码阶段。
Class clazz3 = p.getClass();//通过类的实例获取该类的字节码文件工具,该类处于创建工具阶段

有了字节码文件工具才能得到类中所有的信息,我们在利用反射获取信息时,也要考虑利用上面哪种办法获取字节码工具合理,视不同情形而定。

jsp反射Java反射机制 AJAX

反射的优缺陷:

优点:在运行时得到类的各种内容,进行反编译,对付Java这种先编译再运行的措辞,能够让我们很方便的创建灵巧的代码,这些代码可以在运行时装置,无需在组件之间进行源代码的链接,更加随意马虎实现面向工具。

缺陷:

1)反射会花费一定的系统资源,因此,如果不须要动态地创建一个工具,那么就不须要反射;2)反射调用方法时可以忽略权限检讨,因此可能会毁坏封装性而导致安全问题。

反射的用场:

反编译:.class-->.java通过反射机制访问java工具的属性,方法,布局方法等当我们在利用IDE,比如Ecplise时,当我们输入一个工具或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里便是用到反射。
反射最主要的用场便是开拓各种通用框架。
比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了担保框架的通用性,他们可能须要根据配置文件加载不同的类或者工具,调用不同的方法,这个时候就必须利用到反射了,运行时动态加载须要的加载的工具。
例如,在利用Strut2框架的开拓过程中,我们一样平常会在struts.xml里去配置Action

<action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute"> <result>/shop/shop-index.jsp</result> <result name="error">login.jsp</result> </action>

反射常用方法

反射常用方法

通过字节码工具创建实例工具

/ 类工具 Class的实例 JVM在加载一个类的class文件时,就会同时创建一个Class的实例,利用该实例记录加载的 类的统统信息(类名,有哪些属性,哪些方法,哪些布局器等)。
并且每个被JVM加载的类都有 且只有一个Class的实例与之对应。
反射的第一步便是获取要操作的类的类工具,以便程序在运行期间得知要操作的类的统统信息 然后对其进行相应的操作。
获取一个类的类工具的常见办法: 1:类名.class 例如: Class cls = String.class; Class cls = int.class; 把稳:基本类型获取类工具只有这一种办法。
2:Class.forName(String className) 例如: Class cls = Class.forName("java.lang.String"); 这里传入的类名必须是类的完备限定名,即:包名.类名 3:还可以通过类加载器形式完成 / //获取String的类工具// Class cls = String.class;// Class cls = ArrayList.class;// Class cls = Class.forName("java.lang.String"); Scanner scanner = new Scanner(System.in); System.out.println("请输入类名:"); String className = scanner.nextLine(); /全限定名称: java.util.ArrayList、java.util.HashMap、java.lang.String/ Class cls = Class.forName(className); //获取当前类工具所表示的类的完备限定名 String name = cls.getName(); System.out.println(name); //仅获取类名(不包含包名) name = cls.getSimpleName(); System.out.println(name); / Package getPackage() 获取当前类工具所表示的类的包,返回的Package实例表示该包信息 / Package pack = cls.getPackage(); String packName = pack.getName(); System.out.println("包名"+packName); / Method[] getMethods() 获取当前类工具所表示的类中定义的所有公创办法,包含从超类继续下来的方法 java.lang.reflect.Method类,方法工具 该类的每一个实例用于表示某个类中定义的一个方法,通过它可以获取其表示的方法中的 干系信息(方法名,参数个数,参数类型,返回值类型等等,并且还可以调用这个方法) / Method[] methods = cls.getMethods(); for(Method method : methods){ System.out.println(method.getName()+"()"); }

通过公开的无参布局器实例化的功能

//1获取要实例化的类的类工具// Class cls = Class.forName("reflect.Person");Scanner scanner = new Scanner(System.in);System.out.println("请输入要实例化的类名:");String className = scanner.nextLine();Class cls = Class.forName(className);//2类工具直接供应了可以通过公开的 无参布局器 实例化的功能Object obj = cls.newInstance();System.out.println(obj);

利用有参布局器进行实例化

Class cls = Class.forName("reflect.Person");//获取Person的布局器Person(String,int)// cls.getConstructor();//不穿任何参数时获取的仍旧是无参布局器Constructor c = cls.getConstructor(String.class,int.class);//new Person("王五",55);Object obj = c.newInstance("王五",55);//实例化时要传入布局器哀求的实际参数System.out.println(obj);

利用反射机制调用方法

//1实例化Class cls = Class.forName("reflect.Person");//Object obj = new Person();Object obj = cls.newInstance();//2调用方法//2.1通过类工具获取要调用的方法Method method = cls.getMethod("sayHello");//获取的是无参的sayHello方法//2.2通过获取的方法工具来调用该方法// obj.sayHello() 由于obj指向的是及一个Person工具,因此反射机制可以调用到它的sayHello()method.invoke(obj);

调用有参方法

Class cls = Class.forName("reflect.Person");Object obj = cls.newInstance();//doSomeThing(String)Method method = cls.getMethod("doSomeThing", String.class);method.invoke(obj,"玩游戏");//p.doSomeThing("玩游戏");//doSomeThing(String,int)Method method1 = cls.getMethod("doSomeThing", String.class,int.class);method1.invoke(obj,"作业",5);

得到Class所有方法(包括私有)

Class cls = Class.forName("reflect.Person");Object obj = cls.newInstance();/ getMethod(),getMethods() 它们都是获取Class所表示的类的所有公创办法,包含从超类继续的 getDeclaredMethod(),getDeclaredMethods() 这两个方法获取的都是Class所表示的类中当前类自身定义的方法。
包含私有方法 /// Method[] methods = cls.getDeclaredMethods();// for(Method method : methods){// System.out.println(method.getName());// }Method method = cls.getDeclaredMethod("dosome");method.setAccessible(true);//强行打开dosome方法的访问权限method.invoke(obj);//p.dosome()

int parameterCount() 返回方法参数个数

Class cls = Class.forName("reflect.Person");Object obj = cls.newInstance();//获取所有方法Method[] methods = cls.getMethods();for (Method method : methods){ //判断方法名称包含 say 并且 无方法参数 if(method.getName().contains("say") && method.getParameterCount()==0 ){ System.out.println("自动调用方法:"+method.getName()); method.invoke(obj); }}

自动调用本类自己定义的无参的公创办法Demo如下:

//1这里确当前目录表示的是当前ReflectDemo7这个类所在最外层包的上一级目录// File dir = new File(// ReflectDemo7.class.getClassLoader().getResource(".").toURI()// );//2这里确当前目录便是当前类所在的目录 【文件的目录】File dir = new File( ReflectDemo7.class.getResource(".").toURI());System.out.println(dir.getName());//通过当前类ReflectDemo7的类工具获取所在的包名String packageName = ReflectDemo7.class.getPackage().getName();System.out.println("ReflectDemo7类的包名是:"+packageName);//获取ReflectDemo7.class文件所在的目录中所有.class文件File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));for(File sub : subs){ //获取字节码文件的文件名 String fileName = sub.getName(); System.out.println(fileName); / 由于java命名哀求,文件名必须与类名同等,以是我们可以通过文件名得知该字节码 文件中保存的类的类名 / String className = fileName.substring(0,fileName.indexOf(".")); //加载该类的类工具 Class cls = Class.forName(packageName+"."+className); Object obj = cls.newInstance(); //通过类工具获取本类定义的所有方法 Method[] methods = cls.getDeclaredMethods(); //遍历每个方法,检讨哪个方法是无参的 for(Method method : methods){ //Modifier.PUBLIC 这是一个整数 代表类中Public的方法判断 if(method.getParameterCount()==0 && method.getModifiers() == Modifier.PUBLIC){ System.out.println("自动调用"+className+"的方法:"+method.getName()); method.invoke(obj); } }}

补充:JDK5之后推出了一个特性:变长参数

该特性用于适应那些传入参数的个数不固定的利用场景,使得利用一个方法就可以办理该问题,而无需穷尽。
所有参数个数组合的重载。

public static void main(String[] args) { dosome(1,"one"); dosome(2,"one","two"); dosome(1,"one","two","three"); } / 一个方法里只能有一个变长参数,且必须是末了一个参数 @param arg / public static void dosome(int a,String... arg){ System.out.println(arg.length); System.out.println(Arrays.toString(arg)); }

学习记录,如有侵权请联系删除。