Java 反射 分析类和对象
Java 反射 分析类和对象
@author ixenos
摘要:优化程序启动策略、在运行时使用反射分析类的结构和对象
优化程序启动策略
在启动时,包含main方法的类被加载。它会加载所有它需要的类。这些被加载的类又要加载它们需要的类,以此类推,这是JVM的动态加载机制。
对于一个大型的应用程序,这将消耗很多时间,用户体验不好。此时可以通过反射来优化程序启动策略,要确保包含main方法的类没有显示地引用其他的类。
首先,显式一个启动动画,然后通过调用Class.forName手动加载其他的类,预加载。
在运行时使用反射分析类的结构
在java.lang.reflect包中有三个类Field、Method和Constructor,分别用于描述类的域、方法和构造器。
这三个类都有getName方法返回项目的名称
Field类的getType方法可返回描述域所属类型的Class对象
Method和Constructor类都有报告参数的方法,Method类还有报告返回类型的方法
这三个类还有getModifiers方法返回整数数值,用不同的位开关描述public和static这样的修饰符的使用状况。还可以使用java.lang.reflect.Modifier类的静态方法分析getModifiers返回的整数数值,如isPublic、isFinal、isPrivate
Class类中的getFields、getMethods和getConstructors方法返回类提供的public域、方法和构造器数组,其中包括超类的公有成员
Class类中的getDeclareFields、getDeclareMethods和getDeclaredConstructors方法将返回类中声明的所有域、方法和构造器,不包括超类的成员
在运行时使用反射分析对象
从上一节知道如何查看任意对象的数据域名称和类型:获得对应的Class对象,通过Class对象调用getDeclareFields
本节进一步查看数据域的实际内容(对对象进行分析)
1.查看数据域的关键方法是Field类中的get方法
如果f是一个Field类型的对象,obj是某个包含f域的类的对象,f.get(obj)将返回一个对象,其值为obj域的当前值
Employee harry = new Employee("Harry Hacker", 35000, 10, 1, 1989);
//反射分析类
Class c1 = harry..getClass();
Field f = c1.getDeclaredField("name");
//反射分析对象
Object v = f.get(harry);
*反射机制的默认行为受限于Java的访问控,然而,如果一个Java程序没有收到安全管理器的控制,就可以覆盖访问控制
*这需要调用Field、Method和Constructor对象的setAccessible方法,如f.setAccessible(true);
*setAccessible是AccessibleObject类中的一个方法,是Field、Method和Constructor类的公共超类
//以下是一个利用反射实现的对任意类型对象的toString方法
1 Class ObjectAnalyzer
2 {
3 public String toString(Object obj)
4 {
5 Class c1 = obj.getClass();
6 ...
7 String r = c1.getName();
8 //检查这个类及其所有超类的域
9 do
10 {
11 r += "[";
12 Fields[] fields = c1.getDeclaredFields();
13 //AccessibleObject.setAccessible也有静态方法哟
14 //使所有的域可以访问
15 AccessibleObject.setAccessible(fields, true);
16 //获得所有域的变量名和值
17 for(Field f : fields)
18 {
19 //静态域在运行时不变,没有分析的必要
20 if(!Modifier.isStatic(f.getModifiers()))
21 {
22 //表明当前类是上一次分析的类
23 if(!r.endsWith("[")) { r +=" ,"; }
24 //变量名 = ...
25 r += f.getName() + "=";
26 try
27 {
28 //get当前obj对象的f域的值
29 Object val = f.get(obj);
30 r += toString(val);
31 }
32 catch(Exception e) { e.printStackTrace(); }
33 }
34 }
35 //完成当前类,前进到基类
36 r += "]";
37 c1 = c1.getSuperClass();
38 }
39 //当没有基类时结束循环
40 while (c1 != null);
41 return r;
42 }
43 ...
44 }
//使用该toSting方法示例:
public String toString(){ return new ObjectAnalyzer().toString(this); } //使用this指向当前对象
1 import java.util.ArrayList;
2
3 /**
4 *这个程序使用反射的toString方法来查看任意对象的内部信息
5 */
6
7 public class ObjectAnalyzerTest
8 {
9 public class void main(String[] args)
10 {
11 ArrayList<Integer> squares = new ArrayList<>();
12 for(int i = 1; i <= 5; i++)
13 {
14 square.add(i * i);
15 }
16 System.out.println(new ObjectAnalyzer().toString(squares));
17 }
18 }
***This和super都不能在main()方法中使用,main()方法是静态的,this是本类对象的引用,静态先于对象,所以是不能使用的。
为什么?因为静态方法是在类加载的时候执行.类刚加载可能还没有创建对象,所以就不能用this
动态加载请看另一篇文章http://www.cnblogs.com/ixenos/p/5682088.html
//对toString改进使其能查看数组内部,以及记录被访问过的对象来阻止循环引用
1 package objectAnalyzer;
2
3 import java.lang.reflect.AccessibleObject;
4 import java.lang.reflect.Array;
5 import java.lang.reflect.Field;
6 import java.lang.reflect.Modifier;
7 import java.util.ArrayList;
8
9 public class ObjectAnalyzer
10 {
11 private ArrayList<Object> visited = new ArrayList<>();
12
13 /**
14 * Converts an object to a string representation that lists all fields.
15 * @param obj an object
16 * @return a string with the object's class name and all field names and
17 * values
18 */
19 public String toString(Object obj)
20 {
21 if (obj == null) return "null";
22 if (visited.contains(obj)) return "...";
23 visited.add(obj);
24 Class cl = obj.getClass();
25 if (cl == String.class) return (String) obj;
26 if (cl.isArray())
27 {
28 String r = cl.getComponentType() + "[]{";
29 for (int i = 0; i < Array.getLength(obj); i++)
30 {
31 if (i > 0) r += ",";
32 Object val = Array.get(obj, i);
33 if (cl.getComponentType().isPrimitive()) r += val;
34 else r += toString(val);
35 }
36 return r + "}";
37 }
38
39 String r = cl.getName();
40 // inspect the fields of this class and all superclasses
41 do
42 {
43 r += "[";
44 Field[] fields = cl.getDeclaredFields();
45 AccessibleObject.setAccessible(fields, true);
46 // get the names and values of all fields
47 for (Field f : fields)
48 {
49 if (!Modifier.isStatic(f.getModifiers()))
50 {
51 if (!r.endsWith("[")) r += ",";
52 r += f.getName() + "=";
53 try
54 {
55 Class t = f.getType();
56 Object val = f.get(obj);
57 if (t.isPrimitive()) r += val;
58 else r += toString(val);
59 }
60 catch (Exception e)
61 {
62 e.printStackTrace();
63 }
64 }
65 }
66 r += "]";
67 cl = cl.getSuperclass();
68 }
69 while (cl != null);
70
71 return r;
72 }
73 }
虚拟机为每个类型管理一个Class对象,因此可以用==实现两个Class对象的比较:if(e.getClass()==Employee.class)
2.设置数据域的关键方法是Field类中的set方法
调用f.set(obj, value)可以将obj对象的f域设置成新值
Java 反射 分析类和对象的更多相关文章
- Java反射获取类和对象信息全解析
反射可以解决在编译时无法预知对象和类是属于那个类的,要根据程序运行时的信息才能知道该对象和类的信息的问题. 在两个人协作开发时,你只要知道对方的类名就可以进行初步的开发了. 获取类对象 Class.f ...
- java 反射提取类信息, 动态代理 和过滤某些方法演示
java 反射提取类信息, 动态代理 和过滤某些方法演示 package org.rui.classts.reflects; import java.lang.reflect.Constructor; ...
- Java 反射 Class类
Java 反射 Class类 @author ixenos 摘要:Class类在反射中的地位.构造Class对象的三种方式.Class对象构造对应类型对象的三种方式 Class类在反射中的地位 位于j ...
- 利用Java反射根据类的名称获取属性信息和父类的属性信息
代码: import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java ...
- 利用java反射调用类的的私有方法--转
原文:http://blog.csdn.net/woshinia/article/details/11766567 1,今天和一位朋友谈到父类私有方法的调用问题,本来以为利用反射很轻松就可以实现,因为 ...
- 【JAVA零基础入门系列】Day11 Java中的类和对象
今天要说的是Java中两个非常重要的概念--类和对象. 什么是类,什么又是对象呢?类是对特定集合的概括描述,比如,人,这个类,外观特征上,有名字,有年龄,能说话,能吃饭等等,这是我们作为人类的相同特征 ...
- Java学习笔记十三:Java中的类和对象
Java中的类和对象 一:什么是对象: 总的来说就是"万物皆对象",客观存在的事物皆为对象.是计算机所关注的具体信息. 对象(object)是一件事.一个物体.一个名词,或可以获得 ...
- 【java】java反射 Field类的研究使用
java反射 Field类的研究使用 user.getClass().getFields() 和 user.getClass().getDeclaredFields(); 的区别是什么?
- Java自学-面向对象 类和对象
Java中的类和对象 引入面向对象的基本概念 假设,我们要设计一个LOL这样的游戏,使用面向对象的思想来设计,应该怎么做? 步骤 1 : 设计英雄这个类 LOL有很多英雄,比如盲僧,团战可以输,提莫必 ...
随机推荐
- JavaEE XML DOM解析
DOM解析XML @author ixenos XML解析方式(原理) a) DOM 解析树 b) SAX 流事件 DOM解析对应主流工具 i. DOM(官方) i ...
- Winform_devexpress开发框架主界面设计
做了好多年的C#开发,从.Net.Winform及第三方的DevExpress.无论什么样的系统,主界面的设计及风格无疑非常重要.从客户的角度考虑,要求功能区清晰,整体美观大方,这样才会有可能从第一视 ...
- 必须掌握的Linux命令
章节简述: 本章节讲述系统内核.Bash解释器的关系与作用,教给读者如何正确的执行Linux命令以及常见排错方法. 经验丰富的运维人员可以恰当的组合命令与参数,使Linux字符命令更加的灵活且相对减少 ...
- cout 格式化的一些方法
cout格式化的方式有很多,和C中的printf相比较,在实现方式上更加容易理解. 1.计数进制. 1.十六进制:hex 2.八进制:oct 3.十进制:dec(默认) 在控制进制的时候,可以使用两种 ...
- python从初识到精通1
Python3 基本数据类型 Python 中的变量不需要声明.每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建. 在 Python 中,变量就是变量,它没有类型,我们所说的"类型& ...
- POJ 2104:K-th Number(整体二分)
http://poj.org/problem?id=2104 题意:给出n个数和m个询问求区间第K小. 思路:以前用主席树做过,这次学整体二分来做.整体二分在yr大佬的指点下,终于大概懂了点了.对于二 ...
- QLibraryInfo
读取 qt.conf 文件, 获取 Qt Library 的信息. 通常会在以下三个路径查找conf文件: :/qt/etc/qt.conf(使用资源系统时) ...
- Mysql开机启动,CentOS6.5
使用chkconfig命令,步骤如下: 将服务文件拷贝到init.d下,并重命名为mysql cp /usr/local/mysql/support-files/mysql.server /etc/i ...
- 原生JavaScript+CSS3实现移动端滑块效果
在做web页面时,无论PC端还是移动端,我们会遇到滑块这样的效果,可能我们往往会想着去网上找插件,其实这个效果非常的简单,插件代码的的代码往往过于臃肿,不如自己动手,自给自足.首先看一下效果图: 分析 ...
- python 基础学习4-with语句
why use With? 有些事情需要事先进行设置,事后进行处理,with语句提供了一个很好的处理方式,例如文件读写处理,有时候可能忘记关闭文件,with可以很好地处理这种现象. with语句用来简 ...