seo优化网站推广开源cms建站
seo优化网站推广,开源cms建站,河北建设厅网站首页,眉山建网站【0】README
0.1#xff09; 本文描述源代码均 转自 core java volume 1#xff0c; 旨在理解 java反射机制 #xff1b;最后还顺带提出了 继承设计的技巧#xff1b; 【1】反射相关
1#xff09;反射定义#xff1a;能够分析类能力的程序称为反射#xff1b; 2…【0】README
0.1 本文描述源代码均 转自 core java volume 1 旨在理解 java反射机制 最后还顺带提出了 继承设计的技巧 【1】反射相关
1反射定义能够分析类能力的程序称为反射 2反射机制可以用来
在运行中分析类的能力在运行中查看对象 如编写一个 toString 方法供所有类使用实现通用的数组操作代码利用 Method对象这个对象很像 C 中的函数指针
【2】Class 类
2.1 Java 运行时系统始终为 所有对象维护一个称为运行时的类型标志虚拟机 利用运行时类型信息选择相应的方法执行干货——Java 运行时系统始终为 所有对象维护一个称为运行时的类型标志对象在虚拟机中的运行时类信息保存在Class对象中 2.2Class 可以通过专门的java类访问这些信息 保存这些信息的类被称为 ClassObject.getClass() 将 返回一个Class 类型的实例 2.3 如同用一个Employee 对象表示一个特定的雇员属性一样 一个 Class 对象将表示一个特定类的属性最常用的 Class 方法是 getName方法类名Class类的定义 的良好诠释
2.4还可以调用静态方法forName 获得类名对于的Class对象
String className java.util.Date;
Class c1 Class.forName(className)
Hint在启动时main方法需要加载所有的类 对于一个大型的应用程序来说 这将会消耗很多时间 用户会因此感到不耐烦我们可以通过 Class.forName 手动地加载其他的类 2.5获得Class 类对象的第3种方法 1第一种方法
Date d new Date();
Class c1 d.getClass();
String name c1.getName();
2第二种方法
String className java.util.Date;
Class c1 Class.forName(className)
3第三种方法 如果T是 java类型 T.class 将代表匹配的类对象 如
Class c1 Date.class;
Class c2 int.class;
Class c3 Double[].class;
Attention一个 Class 对象实际上表示的是一个类型 而这个类型未必一定是一种类例如 int 不是类 但 int.class 是一个Class类型的对象干货——一个 Class 对象实际上表示的是一个类型 而这个类型未必一定是一种类如int不是类型而int.class是一个Class类型的对象那我们就可以人为 obj.class 是obj在jvm中运行时相关信息的封装对象 Annotation从 Java SE 5.0 开始 Class类已经参数化了如 Class 的类型是 Employee.class Warning由于历史原因 getName 应用于数组类型的时候会返回一个 很奇怪的名字 Double[].class.getName() 返回 ”[Ljava.lang.Double“ int[].class.getName() 返回 ”[I“ 2.6虚拟机为每个类型管理一个 Class对象 因此可以用 运算符实现两个类对象的比较操作 2.7newInstance()方法 可以用来快速创建一个类的实例.getClass().getInstance(); 它将创建一个与 e 具有相同类型的实例 newInstance 调用默认构造器 初始化新创建的对象如果这个类没有默认的构造器就会抛出一个异常
Annotation
A1如果需要以以上这种方式向构造器提供参数的话 那么就不要使用上面那条语句而使用 构造器类中的newInstance 方法A2key通过反射创建新类示例的两种方式及比较 http://blog.csdn.net/fenglibing/article/details/4531033 我的荔枝博文 http://blog.csdn.net/PacosonSWJTU/article/details/49886429 【3】捕获异常未检查异常已检查异常
3.1当程序运行过程中发生错误时 就会抛出异常。抛出异常比终止程序要灵活得多 这是因为可以提供一个捕获异常的处理器handler对异常情况进行处理 3.2异常有两种类型注意区别未检查异常和已检查异常
3.2.1对于已检查异常 编译器将会检查是否提供了处理器try-cath or throws Exception3.2.2对于未检查异常 例如访问null引用都属于未检查异常编译器不会查看是否为这些错误提供了处理器
3.3最简单的异常处理器
try catch块3.4如果类名不存在 则将跳过try 块中的剩余代码 程序直接进入catch 子句 这里利用Throwable 类的 printStackTrace 方法打印出栈的轨迹 【4】利用反射分析类的能力
4.1反射机制最重要的内容——检查类的结构 4.2在java.lang.reflect 包中有3个类 Field、Method 和 Constructor 分别用于描述类的域、方法 和 构造器 4.3这3个类都有一个 getName的方法 用来返回项目名称
4.3.1Field类 Field类有一个 getType方法 用来返回描述域所属类型的 Class对象4.3.2Method 和 Constructor 类 Method 和 Constructor 类有能够报告参数类型的方法Method类还可以有一个报告返回类型的方法4.3.3 这3个类还有一个叫做 getModifiers的方法它将返回一个整型数值用不同的位开关描述public 和 static这样的修饰符使用状况4.3.4 而且还可以用 java.lang.reflect 包中的Modifier类的静态方法分析 getModifiers 返回的整型数值如 可以使用 Modifier 类中的 isPublic、isPrivate 或 isFinal 判断方法或构造器 是否是 public, private , final我们需要做的工作就是调用 Modifier 类的相应方法 并对返回的整型数值进行分析
4.4 Class类中的 getField、getMethod 和 getConstructor 方法将分别返回类提供的public 域、方法和构造器数值其中包括超类的公有成员 4.5 Class 类的 getDeclareFields、getDeclareMethods、getDeclaredConstructors 方法将分别返回类中声明的全部域、方法和构造器其中包括私有方法和受保护成员但不包括超类成员 【5】在运行时使用反射分析对象
5.1本节将进一步查看数据域的实际内容 5.2利用反射机制可以查看在编译时还不清楚的对象域 5.3查看对象域的关键方法是 Field类中的 get方法如果 f 是一个 Field 类型的 对象 obj 是某个包含 f 域的类对象 f.get(obj) 将返回一个对象其值为obj 域的当前值 5.4看个荔枝
对以上代码的分析Analysis
A1由于name 是一个 private 所以get方法会抛出一个异常A2只有利用get 方法才能得到可访问域的值除非拥有访问权限否则 java 安全机制只允许查看任意对象有哪些域 而不允许读取他们的值
5.5引入setAccessible 方法打印结果与5.4做比较这个很有必要 反射机制的默认行为受限于 Java的访问控制 然而如果一个 java 程序没有收到安全管理器的控制就可以覆盖访问控制。为了达到这个目的需要调用 Field、Method、Constructor对象 的 setAccessible 方法如f.setAccessible(true)
5.6get方法 所遇到的问题 解决方法
5.6.1get遇到的问题 name域是一个 String因此把它作为 Object 返回没有什么问题但是假定我们想要查看salary 域 它属于double 类型 而java中数值类型不是对象5.6.2解决方法可以使用 Field 类中的 getDouble 方法也可以调用get 方法 此时 反射机制将会自动地将这个域值打包到相应的对象包装器中 这里将打包成 Double5.6.3当然 可以获得就可以设置 调用 f.set(obj, value) 可以将 obj 对象的 f域设置成新值 5.6.4如何编写一个可供任意类使用的通用 toString方法P203非常重要 【6】使用反射编写泛型数组代码
6.1java.lang.reflect 包中的Array 类允许动态地创建数组。例如 Array类中的copyOf 方法用于扩充数组容量
int[] a new int[100];
a Arrays.copyOf(a, 2*a.length());
6.2如何编写这样一个通用的方法
6.2.1将Employee[] 数组转换为 Object[] 数组 这让人感觉很有希望
public static Object[] badCopyOf(Object[] a, int newLength)
{Object[] newArray new Object[newLength];System.arraycopy(a, 0, newArray, 0, Math.min(a.length, newLength));return newArray;
} 6.2.2使用以上代码遇到的问题一个对象数组不能转换为 雇员数组Employee[]
Attention
A1 Java 数组会记住每个元素的类型 即创建数组时 new 表达式中使用的元素类型。将一个 Employee[] 临时转换为 Object[] 数组 然后再把它转换回来是可以的 但一个从开始就是Object[] 的数组却永远不会转换成Employee[] 数组。所以 为了能够编写这类通用的数组代码 需要能够创建与 原数组类型相同的新数组A2所以我们需要java.lang.reflect 包中Array类的一些方法。 其中最关键的是 Array 类中的静态方法 newInstance 它能够构造新数组。在调用它时 必须提供两个参数 一个是数组的元素类型 一个是数组的长度
Object newArray Array.newInstance(componentType, newLength)
6.3为了能够实际运行 需要获得新数组的长度和元素类型 可以通过 调用 Array.getLength(a) 获得数组的长度 也可以通过 Array类的静态方法 getLength 方法的返回值得到任意数组 的长度。 而要获得新数组元素类型 就需要进行以下工作Work
W1首先获得a 数组的类对象W2确认它是一个数组W3使用 Class类只能定义表示数组的类对象的 getComponentType 方法确定数组对应的类型 【7】调用任意方法
7.1在Method类中有一个invoke 方法 它允许调用包装在当前 Method 对象中的方法 invoke方法的签名是 Object invoke(Object obj, Object… args) 如 String n (String)m1.invoke(harry); 7.2如何得到 Method 对象呢 7.2.1通过 getDeclaredMethods 方法 然后对返回的Method对象数组进行查找 直到发现想要的方法为止 7.2.2通过调用 Class 类中的getMethod 方法得到想要的方法它与 getField 方法类似 getField 方法根据表示域名的字符串 返回一个 Field对象然而有可能存在着若干个相同名字的方法 因此要格外小心 以确保准确地得到想要的方法所以 我们需要提供想要方法的参数类型 7.3getMethod的方法签名是 Method getMethod(String name, Class… parameterTypes) 7.4看个荔枝如何获得 Employee类的 getName 方法 和 raiseSalary 方法的方法指针
Method m1 Employee.class.getMethod(getName);
Method m2 Employee.class.getMethod(getSalary, double.class);
7.5再看个荔枝 这里 f是一个Method类型的对象由于正在调用的 方法是一个静态方法所以 invokle 的第一个参数是null 为了将 Math.sqrt 函数表格化 需要将f 设置为 Math.class.getMethod(“sqrt”, double.class)这是 Math类中的一个方法 通过参数向它提供了一个函数名 sqrt 和 一个double类型参数
对以上代码的分析Analysis
A1 invoke 的参数和返回值必须是 Object类型的 这就意味着必须进行多次的类型转换A2使用反射获得方法指针的代码要比仅仅直接调用方法明显 慢一些
Attention
A1 建议仅在必要的时候才使用 Method对象而最好使用接口和内部类A2特别重申 建议 Java 开发者不要使用 Method 对象的回调功能 使用接口进行回调会使得代码的执行速度更快 更易于维护 【8】继承设计的技巧
8.1将公共操作和域放在超类 8.2不要使用受保护的域
8.2.1第一子类集合是无限制的 任何一个人都能够由某个类派生一个子类并编写代码以直接访问 protected 的实例域 从而破坏了封装性8.2.2第二在java程序设计语言中在同一个包中的所有类都可以访问 protected域 而不管它是否为这个类的子类
8.3使用继承实现 “is-a” 关系 8.4除非所有继承的方法都有意义 否则不要使用继承 8.5在覆盖方法时 不要改变预期的行为 8.6使用多态而非类型信息无论什么时候 碰到这种代码都应该使用 多态性
if(x is of type1)action1(x);
else if(x is of type2 )action2(x);
8.7不要过多地使用反射
8.7.1反射机制使得人们可以通过在运行时查看与核方法让个人编写出更具有通用性的程序这种功能对于编写系统程序来说极为实用 但是通常不适用于编写应用程序8.7.2反射是很脆弱的 即编译器很难帮助人们发现程序中的错误因此只有在运行时才发现错误并导致异常
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/87804.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!