java中的反射机制(一)
0. 概念
反射库:工具集合,能够用来编写动态操作Java代码的程序。
反射:能够分析类的能力的程序,可以用来
- 在运行的时候分析类的能力
- 在运行的时候检查对象
- 实现泛型数组操作代码
- 利用Method对象
1. class类
1.1概念
运行时类型标识:java运行时系统始终为所有对象维护一个运行时类型标识,这个信息会跟踪每个对象所属的类
Class: 使用一个特殊的java类可以访问这些信息(运行时类型标识),保存这些信息的类名为Class
1.2 获取Class类对象的三种方法
a. Object.getClass方法:该方法会返回一个Class类型的实例
Employee e;
Class c1 = e.getClass();
Class对象会描述一个特定类的属性 ,如上c1可以描述类Employee的属性,最常用的方法是getName(),这个方法将返回类的名字
e.getClass().getName()
b.静态方法forName: 获取类型对应的Class对象
String className = "java.util.Random";
Class c1 = Class.forName();
只有className是一个类名或者是接口名,该方法才能正常执行,而且无论何时使用,都需要提供一个异常处理器
c.如果T是任意的Java类型,T.class将代表匹配的类对象
例如:
Class cl1 = Random.class; Class cl2 = int.class; Class cl3 = Double[].class;
注意:一个Class对象实际上表示的是一个类型,这可能是类,也可能不是类,如int不是类,int.class是一个Class类型的对象
1.3 利用==运算实现两个类的对象的比较
虚拟机为每个类型管理一个唯一的Class对象
例如:
if (e.getClass == Employee.class)
1.4 构造描述类的实例
如果有一个Class类型的对像,可以用它构造类的实例
try { String className = "java.util.Random"; Class c1 = Class.forName(className); Object obj = c1.getConstructor().newInstance(); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); }
输出:
2.利用反射分析类的能力
可以检查类的结构。
java.lang.reflect中有三个类Filed、Method和Constructor分别用于描述类的字段、方法和构造器
这三个类共有一个getName()的方法,用来返回字段、方法、或者构造器的名称。
下面的代码就利用Class的api实现了打印一个类的全部信息
public class ReflectionTest { public static void main(String[] args) throws ClassNotFoundException { //从命令终端或者用户输入读取类名 String name; if (args.length>0) { name = args[0]; }else { Scanner in = new Scanner(System.in); System.out.println("Enter class name (e.g. java.util.Date):"); name = in.next(); } //打印该类名和父类名(不是Object的情况下) Class cl = Class.forName(name); Class superclass = cl.getSuperclass(); //getModifiers返回一个整数,描述所使用的修饰符,利用Modifier.toString方法将修饰符打印出来 String modifier = Modifier.toString(cl.getModifiers()); if (modifier.length()>0) { System.out.print(modifier+" "); } System.out.print("class "+name); if (superclass !=null && superclass != Object.class) { System.out.print(" extends "+superclass.getName()); } System.out.print("\n{\n"); //打印构造器 printConstructors(cl); System.out.println(""); printMethods(cl); System.out.println(""); printFiled(cl); System.out.println("}"); } //打印该类的所有构造器 public static void printConstructors(Class cl){ //getDeclaredConstructors:获取所有构造器 Constructor[] constructors = cl.getDeclaredConstructors(); for (Constructor c : constructors) { //获取构造器的名字 String name = c.getName(); System.out.print(" "); //获取构造器的修饰符 String modifier = Modifier.toString(c.getModifiers()); if (modifier.length()>0) { System.out.print(modifier+" "); } System.out.print(name+"("); //打印参数类型 Class[] parameterTypes = c.getParameterTypes(); for (int i = 0; i) { if (i>0) { System.out.print(", "); } System.out.print(parameterTypes[i].getName()); } System.out.println(");"); } } //打印所有方法 public static void printMethods(Class c1){ Method[] methods = c1.getMethods(); for (Method m : methods) { //返回类型 Class retType = m.getReturnType(); String name = m.getName(); System.out.print(" "); String modifier = Modifier.toString(m.getModifiers()); if (modifier.length()>0) { System.out.print(modifier+" "); } System.out.print(retType.getName()+" "+name+"("); //打印所有参数类型 Class[] parameterTypes = m.getParameterTypes(); for (int i = 0; i ) { if (i>0) { System.out.print(", "); } System.out.print(parameterTypes[i].getName()); } System.out.println(");"); } } public static void printFiled(Class cl){ Field[] fields = cl.getDeclaredFields(); for (Field f : fields) { Class type = f.getType(); String name = f.getName(); System.out.print(" "); String modifiers = Modifier.toString(f.getModifiers()); if (modifiers.length() > 0) { System.out.print(modifiers+" "); } System.out.println(type.getName()+" "+name+";"); } } }
3.使用反射在运行时分析对象
- 利用反射机制可以查看在编译期间还不知道的对象字段
- 对于字段的访问,受到Java安全控制的影响,反射机制的默认行为受限于Java的访问控制,但是可以调用Field等的setAccessible方法覆盖掉Java的访问控制,例如:
f.setAccessible(true);
4. 使用反射编写泛型数组代码
java.lang.reflect包中的Array类允许动态的创建数组
如CopyOf的实现:
public static Object goodCopyOf(Object a,int newlength){ //获取a数组的类对象 Class cl = a.getClass(); if(!cl.isArray()) return null; //确定数组的正确类型 Class componentType = cl.getComponentType(); int length = Array.getLength(a); Object newArray = Array.newInstance(componentType, newlength); System.arraycopy(a,0,newArray,0,Math.min(length,newlength)); return newArray; }
5.利用反射调用方法和构造器
反射机制中允许你调用任意的方法,Method类中有一个invoke方法,允许你调用当前Method对象的方法
Method m1 = Math.class.getMethod("sqrt", double.class); double d =(Double) m1.invoke(null, 4); System.out.println(d);
输出: