java 反射机制
来源:互联网 发布:js 数组存在值 编辑:程序博客网 时间:2024/06/05 20:55
0、前言及思路
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
–摘自:百度百科-JAVA反射机制
java的反射机制是java SE的内容,但是却在许多框架中出现使用,java反射机制可以接触到一些程序不允许你接触的地方,对于java反射机制的这一特性是存在一些争议的,有人支持,有人反对。
对于java的反射机制,核心是Class类,这个Class类也在java虚拟机JVM很始终要的,因为一个类的信息会包装成一个Class类,同时这个Class类也是java反射机制的入口,从我的学习中,我发现,许多操作都是围绕着Class展开的。
从Class类中我们可以获得一些信息,从一个类的上到下,可列出信息如下:
Class ↓
- 1、包信息
- 2、类修饰符、类名、父类、多接口
- 3、成员变量 -> 获取(get)和设置(set)成员变量
- 4、构造方法 -> 执行构造方法
- 5、成员方法 -> 调用方法
其中可以发现一些规律:
- 这些信息都是在Class类中获得的,那么写java反射的时候第一时间应该是拿到需要的Class类实例
- 接着获取一些如上1、2、3、4、5的信息
- 获得完信息就完毕的,比如1、2的信息,我们已经不能再干什么了
- 获取完还是一个信息类,而这个类可以执行方法,完成一些功能的,比如3、4、5
下面开始实践。注意Constructor、Field、Method类。
如果获取Constructor、Field、Method这些类的是私有信息,记得用setAccessible方法设置Accessible为true,再去使用方法这些是有属性或者方法。
1、构造一个被反射的类
先构建如下一个提供调用的类:
public class Reflection extends Thread implements Serializable { // 静态常量属性 private static final long serialVersionUID = 1L; // 静态属性 private static Reflection instance; // 普通私有属性 private String threadName; // 这个属性是是了验证get方法的,ide自动生成的形式 private boolean isRunning; // 私有构造方法 private Reflection() { this.threadName = currentThread().getName(); } // 这个构造方法仅代码需要 public Reflection(final String threadName, boolean isRunning) { super(); this.threadName = threadName; this.isRunning = isRunning; } // 类方法 public static Reflection getInstance() { if (instance == null) { synchronized (Reflection.class) { if (instance == null) { instance = new Reflection(); } } } return instance; } // 普通方法 @Override public void run() { // TODO Auto-generated method stub System.out.println("run"); } // 下面是自动生成的getter和setter方法,用于属性的取值和赋值 public boolean isRunning() { return isRunning; } public void setRunning(boolean isRunning) { this.isRunning = isRunning; } public String getThreadName() { return threadName; } public void setThreadName(String threadName) { this.threadName = threadName; } public static long getSerialversionuid() { return serialVersionUID; } // toString方法在在调用构造方法的时候容易看到属性值 @Override public String toString() { return "Reflection [threadName=" + threadName + ", isRunning=" + isRunning + "]"; } //私有方法 private String printMSG(String who){ return who+" print Reflection [threadName=" + threadName + ", isRunning=" + isRunning + "]"; }}
2、构造Class类
构造Class类的方法有三个:
- Class.forName(“包名.类名”) -> Class.forName(“space.xxhui.Reflection”);
- 类名.class -> Reflection.class
- 对象名.getClass() -> Reflection.getInstance().getClass();
下面是举例子,代码如下:
Class cForName = null; Class cForClass = Reflection.class; Reflection r = Reflection.getInstance(); Class cForRuntime = r.getClass(); try { cForName = Class.forName("space.xxhui.Reflection"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); }
3、获取包信息
其实很简单就getPackage().getName(),即可
// 1、先获得Package类,再获得包名 System.out.println("***** start print packageName *****"); String p1 = cForName.getPackage().getName(); String p2 = cForClass.getPackage().getName(); String p3 = cForRuntime.getPackage().getName(); System.out.println(p1); System.out.println(p2); System.out.println(p3); System.out.println("***** stop print packageName *****");
结果:
4、获取类修饰符、类名、父类、多接口
4.1、类修饰符和类名
System.out.println("***** start print classModify and class name ****"); // 2.1、返回这个类或接口的Java语言修饰符返回整数编码 int modifyCode = cForClass.getModifiers(); // 2.2、使用Modifier类的方法进行解码。 String modifyType = Modifier.toString(modifyCode); // 3、获取当前类名 String name = cForName.getName(); System.out.println("\n"+modifyType +" - class - "+ name +"\n"); System.out.println("***** stop print classModify and class name ****");
结果:
4.2、获取父类和多接口
System.out.println("***** start print super class and interfaces ****"); // 4、获得当前父类名字(java是单继承,所以方法只返回单值) String super1 = cForName.getSuperclass().getName(); System.out.print("\n extends - "+super1+" - implements - "); // 5、获得所有接口,并打印它们的名字(java可以实现多个接口,所以返回值是数组) for (Class cInterface : cForName.getInterfaces()) { System.out.print(cInterface.getName()+" - "); } System.out.println("\n"); System.out.println("****** stop print super class and interfaces *****");
结果:
4、获取成员变量
System.out.println("****** 打印成员变量 *****"); System.out.println(">>>>>> 打印全部声明的成员变量"); // 6.1、获得属性的声明信息 // 注意:用的是cForRunTime // 获取属性类型的方法用的是:cField.getGenericType().getTypeName() for (Field cField : cForRuntime.getDeclaredFields()) { System.out.print(Modifier.toString(cField.getModifiers()) + " - " + cField.getGenericType().getTypeName() + " _ " + cField.getName()); // 对于 Field、Method 或 Constructor 对象,取消默认 Java 语言访问控制检查的能力 cField.setAccessible(true); try { System.out.print(" = " + cField.get(r)+"\n"); } catch (IllegalArgumentException | IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(); // 6.2获取(get)和设置(set)特定的属性信息 try { // instance为static属性 System.out.println(">>>>>> 打印static成员变量"); Field cField = cForName.getDeclaredField("instance"); if (cField != null) { System.out.println(Modifier.toString(cField.getModifiers()) + " _ " + cField.getType().getName() + " - " + " _ " + cField.getName()); } // threadName为普通属性 System.out.println(">>>>>> 打印要get和set的成员变量"); cField = cForRuntime.getDeclaredField("threadName"); if (cField != null) { System.out.println(Modifier.toString(cField.getModifiers()) + " _ " + cField.getType().getName() + " _ " + " _ " + cField.getName()); cField.setAccessible(true); System.out.println("查看设置前的值:threaName :"+cField.get(r));//获取属性 cField.set(r, "sub thread");//设置属性 System.out.println("查看设置后的值:threadName :"+cField.get(r));//查看是否设置成功 } } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("****** 结束打印成员变量 *****");
结果:
5、获取构造方法
System.out.println("****** 打印构造方法 *****"); System.out.println("获取公共构造方法:"); // 7.1获取构造方法(public的 // getConstructors方法返回所有pulic声明的构造方法 for (Constructor cConstructor : cForName.getConstructors()) { System.out.print(Modifier.toString(cConstructor.getModifiers()) + " - " + cConstructor.getName()); System.out.print(" ( "); for (Parameter cParameter : cConstructor.getParameters()) { System.out.print(Modifier.toString(cParameter.getModifiers()) + " - " + cParameter.getType().getName() + " - " + cParameter.getName()+" _ "); } System.out.print(" ) \n"); } System.out.println("打印所有声明的构造方法"); // 7.2获取构造方法(所有的 // getDeclaredConstructors方法返回类中声明的全部方法 for (Constructor cConstructor : cForName.getDeclaredConstructors()) { System.out.print(Modifier.toString(cConstructor.getModifiers()) + " - " + cConstructor.getName()); System.out.print(" ( "); for (Parameter cParameter : cConstructor.getParameters()) { System.out.print(Modifier.toString(cParameter.getModifiers()) + " - " + cParameter.getParameterizedType().getTypeName() + " - " + cParameter.getName()+" _ "); } System.out.print(" ) \n"); } System.out.println(); // 7.3获取单个构造方法,并调用构造函数 try { // 获取声明的无参构造函数 Constructor cConstructor = cForName.getDeclaredConstructor(); System.out.print(Modifier.toString(cConstructor.getModifiers()) + " - " + cConstructor.getName()); System.out.print(" ( "); for (Parameter cParameter : cConstructor.getParameters()) { System.out.print(Modifier.toString(cParameter.getModifiers()) + " - " + cParameter.getParameterizedType().getTypeName() + " - " + cParameter.getName()); } System.out.print(" ) \n"); // 无参的构造方法是私有的,先取消访问控制的能力 // 对于 Field、Method 或 Constructor 对象,取消默认 Java 语言访问控制检查的能力 cConstructor.setAccessible(true); System.out.println("调用私有构造方法:"+cConstructor.newInstance().toString()); // 获取声明的有两个参数的构造函数 cConstructor = cForName.getDeclaredConstructor(new Class[] { String.class, boolean.class }); System.out.print(Modifier.toString(cConstructor.getModifiers()) + " - " + cConstructor.getName()); System.out.print(" ( "); for (Parameter cParameter : cConstructor.getParameters()) { System.out.print(Modifier.toString(cParameter.getModifiers()) + " - " + cParameter.getParameterizedType().getTypeName() + " - " + cParameter.getName()); } System.out.print(" ) \n"); System.out.println("调用公有构造方法:"+cConstructor.newInstance("sub Thread", false).toString()); } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("****** 构造方法打印结束 *****");
结果:
6、获取成员方法
System.out.println("****** 打印成员方法 *****"); System.out.println("打印所有公有方法: 太长了不打印,知道即可"); // 8.1获取方法(public的,并且包括接口、父类本类的,打印出来好长啊// for (Method cMethod : cForName.getMethods()) {// System.out.print(Modifier.toString(cMethod.getModifiers()) + " - " + cMethod.getReturnType().getName()// + " - " + cMethod.getName());// System.out.print(" ( ");// for (Parameter cParameter : cMethod.getParameters()) {// System.out.print(Modifier.toString(cParameter.getModifiers()) + " - "// + cParameter.getParameterizedType().getTypeName() + " - " + cParameter.getName());// }// System.out.print(" ) \n");// } System.out.println("打印所有声明的方法"); //8.2获取方法(所有声明的方法,包括private for (Method cMethod : cForName.getDeclaredMethods()) { System.out.println(Modifier.toString(cMethod.getModifiers()) + " - " + cMethod.getReturnType().getName() + " - " + cMethod.getName()); for (Parameter cParameter : cMethod.getParameters()) { System.out.println(Modifier.toString(cParameter.getModifiers()) + " - " + cParameter.getParameterizedType().getTypeName() + " - " + cParameter.getName()); } } System.out.println("打印单个方法,并调用:"); //8.3获取单个方法,并调用方法 try { //获取一个public类型的无参方法 Method cMethod = cForName.getMethod("run", new Class[]{}); System.out.println(Modifier.toString(cMethod.getModifiers()) + " - " + cMethod.getReturnType().getName() + " - " + cMethod.getName()+" ( ) "); //调用方法 Reflection reflection =(Reflection) cForName.getConstructor(new Class[] { String.class, boolean.class }).newInstance("sub Thread",false); System.out.println("普通方法调用:"); cMethod.invoke(reflection, null);//这里参数为null代表无参数 System.out.println("//--------------------------------------------------"); //获取一个private类型的有参方法 cMethod = cForName.getDeclaredMethod("printMSG", new Class[]{String.class}); System.out.print(Modifier.toString(cMethod.getModifiers()) + " - " + cMethod.getReturnType().getName() + " - " + cMethod.getName()); System.out.print(" ( "); for (Parameter cParameter : cMethod.getParameters()) { System.out.print(Modifier.toString(cParameter.getModifiers()) + " - " + cParameter.getParameterizedType().getTypeName() + " - " + cParameter.getName()); } System.out.print(" ) \n"); // 由于是私有的,取消访问控制的能力 // 对于 Field、Method 或 Constructor 对象,取消默认 Java 语言访问控制检查的能力 cMethod.setAccessible(true); System.out.println("普通方法调用:"); String result = (String) cMethod.invoke(reflection, "Hitvz"); System.out.println(result); System.out.println("//--------------------------------------------------"); //调用一个类方法(注意:反射调用方法是区分大小写的,因为我用getinstance报错了,呵呵呵 cMethod = cForName.getMethod("getInstance", new Class[]{}); System.out.println(Modifier.toString(cMethod.getModifiers()) + " - " + cMethod.getReturnType().getName() + " - " + cMethod.getName()); for (Parameter cParameter : cMethod.getParameters()) { System.out.println(Modifier.toString(cParameter.getModifiers()) + " - " + cParameter.getParameterizedType().getTypeName() + " - " + cParameter.getName()); } //调用静态方法,与普通方法的区别就是:invoke方法的第一个参数,普通方法是要一个具体的实例对象,而静态方法的话直接置null即可 System.out.println("静态方法调用:"); Reflection reflection2 = (Reflection) cMethod.invoke(null,null); System.out.println(reflection2.toString()); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("****** 成员方法结束打印 *****");
7、通过方法来设置成员变量
我自己写的方法:
public static void buildSetter(Object target, String name,Class[] clazzs ,Object[] objects){ if(clazzs[0].getName().equals("boolean")||clazzs[0].getName().equals("java.lang.Boolean")){ char letter = name.substring(2, 3).toCharArray()[0]; if(letter<'Z'&&letter>'A'){ name = name.substring(2); } name ="set"+ name.substring(0, 1).toUpperCase() + name.substring(1); }else{ name ="set"+ name.substring(0, 1).toUpperCase() + name.substring(1); //System.out.println(name); } //System.out.println(name); Method m = null; try { m = target.getClass().getDeclaredMethod(name, clazzs); m.invoke(target, objects); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // boolean修饰的属性,getter方法有is开头,不添加is,没有的话,添加is // setter方法却是有is开头,去掉is,没有is,如常不增删 public static Object buildGetter(Object target ,String name){//由于不能获取返回类型,所以只能在方法中找了 String temp =name; List<Method> list = new ArrayList<Method>(); for (Method method : target.getClass().getMethods()) {//找出每个方法 if(method.getParameterCount()==0){//找出方法中参数为0的方法 if(method.getReturnType().getName().equals("void")){//排除返回值为void的方法 continue; } if(method.getName().startsWith("get")||method.getName().startsWith("is")){//选择出get和is开头的方法 temp = name; if(method.getReturnType().getName().equals("boolean")||method.getReturnType().getName().equals("java.lang.Boolean")){//找出返回值为布尔类型的方法,再判断 char letter = temp.substring(2, 3).toCharArray()[0]; if(letter<'Z'&&letter>'A'){//第三个字母是大写 if(method.getName().length()==temp.length()){ temp = temp.substring(2); if(method.getName().contains(temp)){ list.add(method); } } }else{//不是大写 temp = temp.substring(0, 1).toUpperCase() + temp.substring(1); if(method.getName().contains(temp)){ list.add(method); } } }else {//找出返回值为非布尔类型的方法,再处理 temp ="get"+ temp.substring(0, 1).toUpperCase() + temp.substring(1); if(method.getName().contains(temp)){ if(method.getName().length()==temp.length()){ list.add(method); } } } } } } if(list.size()==0){ System.out.println("no such getter!"); return null; } //System.out.println(list.size()); Method m = null; Object o = null; try { m = target.getClass().getDeclaredMethod(list.get(0).getName(), new Class[]{}); o = m.invoke(target); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return o; }
调用:
System.out.println("修改threadName"); try { Reflection reflection =(Reflection) cForName.getConstructor(new Class[] { String.class, boolean.class }).newInstance("sub Thread",false); buildSetter(reflection, "threadName", new Class[]{String.class}, new Object[]{"sub Thread"}); System.out.println("更改后的信息:"+reflection.toString()); Object o= buildGetter(reflection, "threadName"); System.out.println("获取threadName信息:"+o); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); }
- 【反射】JAVA反射机制
- 【Java】JAVA反射机制
- Java 反射机制[Field反射]
- Java 反射机制[Method反射]
- Java反射机制笔记-反射机制
- java的反射机制
- Java的反射机制
- java反射机制详解!
- Java反射机制
- Java的反射机制
- java 反射机制--侯捷
- java反射机制
- java反射机制
- [候捷]Java反射机制
- java 反射机制
- java 反射机制初探
- 关于Java反射机制
- java反射机制
- 0725-jQuery
- 0034_Search for a Range
- Git(6)——远程仓库
- 子承父类
- bzoj3236 作业 莫队+树状数组
- java 反射机制
- 链表翻转【比如链表1→2→3→4→5→6,k=2, 翻转后2→1→4→3→6→】
- ssm+bootstrap验证练习01注册验证(方法二)--代码实现
- 【学习笔记】天嵌2440第三季下学期——linux多线程同步
- HDU1896 Stones【模拟+优先队列】
- python语法基础入门
- 09 在ZStack里的定时器应用
- 17 多校
- NOI2017游记