深入学习Java反射之道-class
来源:互联网 发布:程序员教程 pdf 编辑:程序博客网 时间:2024/04/30 07:32
深入学习Java反射之道-Class
反射常被用于在程序运行时检查或修改其执行行为。
为什么要使用反射
反射可以在下面几点帮助我们
- 扩展功能,扩展已有类的功能
- 类浏览器和可视化开发,类浏览器需要枚举类的成员,广泛应用于可视化开发环境
- 调试和测试工具,调试器需要能够检查类的私有成员,测试工具会使用反射调用API。
反射的弊端
反射很强大,但是不要滥用,如果可以避免使用,尽量避免。当使用反射时,下面的问题需要注意。
- 性能开销,反射会动态地处理对象,导致JVM的优化不能进行,因此,要避免在性能敏感地地方使用反射。
- 安全限制,反射可能会与安全管理相互冲突。
- 内部资源暴露,反射可以访问private方法,这可能会带来意料之外的副作用。
反射与类
java中的对象不是基本值类型就是引用类型,而所有的引用类型都继承自
java.lang.Object
。
Java虚拟机为每个类生成一个不可变的java.lang.Class
的类实例,该类实例提供了对象属性的运行期检查,包括了对象的成员和类型信息。java.lang.Class
是所有反射操作的入口。
如何获取类实例
java.lang.Class
是所有反射操作的入口。需要调用java.lang.Class
的对应方法,以获取类实例。
Object.getClass()
如果可以获取到一个对象的实例,最简单的获取类实例的方法是调用该对象的getClass()
方法。注意,这只是用于引用类型(getClass()
方法继承自Object
)。下面是几个例子:
- 获取
String
的类实例
Class c = "foo".getClass();
- 获取
Enum
的类实例
enum E{A,B}Class c= A.getClass();
- 获取集合的类实例
Set<String> s = new HashSet<String>();Class c = s.getClass();
- 获取数组的类实例
byte[] bytes = new byte[1024];Class c = bytes.getClass();
.class
语法
如果我们可以获得类型但是无法获取对应的对象,那么可以使用.class
语法来获得类实例。这同时解决了基本值类型的类实例获取方法。
- 获取基本值类型的类实例
boolean b;Class c = boolean.class; // correct
- 获取引用类型的类实例
Class c = java.io.PrintStream.class;
- 获取数组类型的类实例
Class c = int[][][].class;
Class.forName()
如果可以获得一个类的fully-qualified name(包名+类名),那么可以通过static方法Class.forName()
来获得对应的类实例。注意,基本值类型不能使用这个方法。
- String
Class c = Class.forName("java.lang.String");
数组类型的Class.forName()
- double一维数组
Class cDoubleArray = Class.forName("[D");
对应
double[].class.getName()
- String 二维数组
Class cStringArray = Class.forName("[[Ljava.lang.String;");
对应
String[][].class.getName()
基本值类型通过包装类获取类实例
每个基本值类型和void都有自己对应的包装类(java.lang包中),因此可以通过包装类的TYPE
属性来获取对应的封装类的类实例。
Class c = Double.TYPE;Class c = Void.TYPE;
Class
的其它方法
Class.getSuperclass()
返回当前类实例的父类。
Class.getClasses()
返回Class<?>[]
,包含了当前类实例的所有public成员类,接口,枚举(包括继承的成员)的类实例。
Class<?>[] c = Character.class.getDeclaredClasses();/*** 数组c中会包含Character类中的3个public成员类* static class Character.Subset* static class Character.UnicodeBlock* static class Character.UnicodeScript*/
Class.getDeclaredClasses()
返回Class<?>[]
,包含了当前类实例的所有(public, protected, friendlly, private )成员类,接口,枚举(包括继承的成员)的类实例。
Class<?>[] c = Character.class.getDeclaredClasses();/*** 数组c中会包含Character类中的3个public成员类和一个私有类* Character.Subset* Character.UnicodeBlock* Character.UnicodeScript* (private)Character.CharacterCache.*/
getDeclaringClass()
java.lang.Class.getDeclaringClass()
java.lang.reflect.Field.getDeclaringClass()
java.lang.reflect.Method.getDeclaringClass()
java.lang.reflect.Constructor.getDeclaringClass()
获取Class,Field,Method,Constructor声明所在类,注意,匿名内部类没有声明所在类。
Field f = System.class.getField("out");Class c = f.getDeclaringClass();// c -> System.public class MyClass { static Object o = new Object() { public void m() {} }; static Class<c> = o.getClass().getEnclosingClass();}// o -> null.
Class.getEnclosingClass()
返回匿名内部类的封装类。
public class MyClass { static Object o = new Object() { public void m() {} }; static Class<c> = o.getClass().getEnclosingClass(); // o -> MyClass}
类的标识符和类型检查
一个类有一个或多个修饰符,这些修饰符会影响运行期行为。
- 访问权限修饰符
- public
- protected
- friendly(默认包权限,也被称作default)
- private
- 重载修饰符
- abstract
- 静态修饰符
- static
- 不可修改修饰符
- final
- 强制严格浮点操作修饰符
- strictfp
- 注解
java.lang.reflect.Modifer
包含了所有可能的修饰符的声明,也包含了解析Class.getModifiers()
返回值的方法。
获取修饰符的例子
import java.lang.annotation.Annotation;import java.lang.reflect.Modifier;import java.lang.reflect.Type;import java.lang.reflect.TypeVariable;import java.util.ArrayList;import java.util.List;import static java.lang.System.out;/** * 引用自 * http://docs.oracle.com/javase/tutorial/reflect/class/classModifiers.html */public class ClassDeclarator { public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); out.format("Class:%n %s%n%n", c.getCanonicalName()); out.format("Modifiers:%n %s%n%n",Modifier.toString(c.getModifiers())); out.format("Type Parameters:%n"); TypeVariable[] tv = c.getTypeParameters(); if (tv.length != 0) { out.format(" "); for (TypeVariable t : tv) out.format("%s ", t.getName()); out.format("%n%n"); } else { out.format(" -- No Type Parameters --%n%n"); } out.format("Implemented Interfaces:%n"); Type[] intfs = c.getGenericInterfaces(); if (intfs.length != 0) { for (Type intf : intfs) out.format(" %s%n", intf.toString()); out.format("%n"); } else { out.format(" -- No Implemented Interfaces --%n%n"); } out.format("Inheritance Path:%n"); List<Class> l = new ArrayList<Class>(); printAncestor(c, l); if (l.size() != 0) { for (Class<?> cl : l) out.format(" %s%n", cl.getCanonicalName()); out.format("%n"); } else { out.format(" -- No Super Classes --%n%n"); } out.format("Annotations:%n"); Annotation[] ann = c.getAnnotations(); if (ann.length != 0) { for (Annotation a : ann) out.format(" %s%n", a.toString()); out.format("%n"); } else { out.format(" -- No Annotations --%n%n"); } } catch (ClassNotFoundException x) { x.printStackTrace(); } } private static void printAncestor(Class<?> c, List<Class> l) { Class<?> ancestor = c.getSuperclass(); if (ancestor != null) { l.add(ancestor); printAncestor(ancestor, l); } }}
探索类的成员
java.lang.Class
中获取fields,methods和constructors的方法分为两种,一种是获取全部成员,将结果放入List;一种是获取名称对应的成员。
另外,根据成员的声明位置,获取成员的方法也分为两种,一种是直接获取类中所有声明的成员,一种是获取类的public成员(包括继承的成员)。
field
& method
& constructor
field
getDeclaredField()
no no yes getField()
no yes no getDeclaredFields()
yes no yes getFields()
yes no nomethod
getDeclaredMethod()
no no yes getMethod()
no yes no getDeclaredMethods()
yes no yes getMethods()
yes no noconstructor
getDeclaredConstructor()
no yes getConstructor()
no no getDeclaredContructors()
yes yes getContructors()
yes no获取类的成员的代码示例
import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Member;import static java.lang.System.out;/** * 引用自 * http://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html */enum ClassMember { CONSTRUCTOR, FIELD, METHOD, CLASS, ALL }public class ClassSpy { public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); out.format("Class:%n %s%n%n", c.getCanonicalName()); Package p = c.getPackage(); out.format("Package:%n %s%n%n", (p != null ? p.getName() : "-- No Package --")); for (int i = 1; i < args.length; i++) { switch (ClassMember.valueOf(args[i])) { case CONSTRUCTOR: printMembers(c.getConstructors(), "Constructor"); break; case FIELD: printMembers(c.getFields(), "Fields"); break; case METHOD: printMembers(c.getMethods(), "Methods"); break; case CLASS: printClasses(c); break; case ALL: printMembers(c.getConstructors(), "Constuctors"); printMembers(c.getFields(), "Fields"); printMembers(c.getMethods(), "Methods"); printClasses(c); break; default: assert false; } } } catch (ClassNotFoundException x) { x.printStackTrace(); } } private static void printMembers(Member[] mbrs, String s) { out.format("%s:%n", s); for (Member mbr : mbrs) { if (mbr instanceof Field) out.format(" %s%n", ((Field)mbr).toGenericString()); else if (mbr instanceof Constructor) out.format(" %s%n", ((Constructor)mbr).toGenericString()); else if (mbr instanceof Method) out.format(" %s%n", ((Method)mbr).toGenericString()); } if (mbrs.length == 0) out.format(" -- No %s --%n", s); out.format("%n"); } private static void printClasses(Class<?> c) { out.format("Classes:%n"); Class<?>[] clss = c.getClasses(); for (Class<?> cls : clss) out.format(" %s%n", cls.getCanonicalName()); if (clss.length == 0) out.format(" -- No member interfaces, classes, or enums --%n"); out.format("%n"); }}
- 深入学习Java反射之道-class
- 深入学习Java反射之道-field
- Java反射之Class类
- Java 反射之Class用法
- java反射 之Class类
- java反射之Class类
- 【Java】反射之Class.forName()
- 深入理解 Java 反射:Class (反射的入口)
- 深入理解 Java 反射:Class (反射的入口)
- 深入理解 Java 反射:Class (反射的入口)
- 深入理解Java之反射
- 深入理解Java之反射
- JAVA反射学习之——深入研究(反射与泛型)
- Java反射机制总结学习--Class类
- java反射之获取Class对象
- JAVA之Class类与反射总结
- Java反射之Class,Constructor,Field
- java反射之获取Class对象
- 操作系统养成计划之篇二:死锁
- 数组中只出现一次的数字
- RPC
- Java并发编程 希尔排序
- Linux下的crond和crontab调研
- 深入学习Java反射之道-class
- 嵌入式Linux学习笔记(1)——linux系统搭建
- Unity_协程
- CentOS7安装Oracle 11gR2
- 《剑指offer》栈的压入、弹出序列
- Activity之startActivity&finishActivity
- JDBC批量操作
- MySQL+Python+Ubuntu
- CPU寻址能力,地址总线宽度,Byte,bit,怎么算?