承接着第一篇 , 这一节将继续谈到如何获取class对象的信息。class对象信息大致可分为两类:(1)class对象的信息;(2)class对象的成员信息。class对象的信息主要修饰修饰符,泛型参数,所实现的接口,继承的路径与及注解信息。class对象的成员信息主要有成员变量field,函数方法与构造器。在进入正文之前,如果对类的信息了解的不多,可以参考.
一、获取class对象信息
获取class对象信息,主要是使用了一系列对应的函数的方法,在这里先做一个简单的介绍:
方法 | 描述 |
getCanonicalName() | 获取class的类名 |
getModifiers() | 获取class的修饰符 |
getTypeParameters() | 获取class的泛型参数 |
getGenericInterfaces() | 获取class实现的接口 |
getSuperclass() | 获取class的父类,多次调用即可获得继承的路径 |
getAnnotations() | 获取class的注解 |
附:1、以上方法都是class对象的函数方法。方法名后带有“s“的,表示获取一个或多个的意思,都是以数组的形式返回。如”getTypeParameters()可能返回Type[]数组,其他的类似。注意的是”getmodifiers()“返回的是一个int。2、getAnnotations()并不能获取类的所有注解,只有实现了java.lang.reflect.AnnotatedElement的注解才可以被获得。如在预订的三个注解里@Override,@Deprecate,@SuppressWarning,只有@Deprecate可被获得。
下面给一个Demo,演示如何遍历class对象的信息:
public class ClassDeclarationSpy { public static void main(String[] args) { try { Class c = Class.forName("java.util.Date"); out.println("类名:" + c.getCanonicalName()); out.println("修饰符:" + Modifier.toString(c.getModifiers())); out.print("泛型参数: "); TypeVariable [] tv = c.getTypeParameters(); if (tv.length != 0) { for (TypeVariable t : tv) out.print(t.getName() + " "); out.println(); } else { out.println("无泛型参数"); } out.print("实现的接口:"); Type[] intfs = c.getGenericInterfaces(); if (intfs.length != 0) { for (Type intf : intfs) out.println(" " + intf.toString()); } else { out.println("无实现的接口"); } out.print("继承路径:"); List> l = new ArrayList<>(); assembleAncestor(c, l); if (l.size() != 0) { for (Class cl : l) out.println(cl.getCanonicalName()); } else { out.println("无超类"); } out.print("注解:"); Annotation[] ann = c.getAnnotations(); if (ann.length != 0) { for (Annotation a : ann) out.print(a.toString() + " "); out.format("%n"); out.println(); } else { out.println("无注解"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } private static void assembleAncestor(Class c, List > l) { Class ancestor = c.getSuperclass(); if (ancestor != null) { l.add(ancestor); assembleAncestor(ancestor, l); } }}
类似的,可以获取java.util.List的信息,其输出如下:
尝试去获取一个已经过时的class,如java.io.StringBufferInputStream
二、获取class对象的成员信息
class对象的成员信息主要有成员变量,函数方法与构造器。与获取class对象信息类似,java提供了各种方法来获取成员信息——这些方法大概可以分两类,一类是直接获取所有的成员(变量,函数或者构造器)的方法,另外一类是搜索指定成员的方法。下面给出这些方法的概览:
1、获得与Class对象对应类的字段
Class API | 继承的?? | 私有的?? |
no | yes | |
yes | no | |
no | yes | |
yes | no |
解释如下,“继承的?”代表了此方法是否可以获取从超类继承过来的filed值,“私有的”代表了此方法是否可以获取私有的field;如果方法含有“Declared”表示获取class对象自身含有的field值,如果没有,表示可以获取超类的field;如果方法名尾部含有“s”字样,表示此方法获取的是所有可以获取的field值返回一个Field<?>[]数组,反之,则是获取指定的field值,返回Field<T>。如“getDeclaredField()”表示获取当前class对象自身含有的field,此方法可以获取private修饰的field值,”getfields()”表示获取class对象所有public的field(包含从超累继承过来的),不可以获取private修饰的field。
2、获得与Class对象对应类的方法
Class API | 继承的方法? | 私有方法? |
no | yes | |
yes | no | |
no | yes | |
yes | no |
3、获得与Class对象对应类的构造方法
API | 继承的? | 私有的? |
—— | yes | |
—— | no | |
—— | yes | |
—— | no |
因为构造器不能从超类继承过来,因此继承对构造器来说没有任何意义,其他的用法与获取field值得方法类似。
Demo:建立两个类Student,Bachelor,如下
package com.other;public class Student { private int id; private String sex; public String name; public Student() { } public Student(int id, String sex, String name) { super(); this.id = id; this.sex = sex; this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
package com.other;public class Bachelor extends Student{ private String major; public Bachelor() { } public Bachelor(String major) { super(); this.major = major; }}
public class ClassHelp { public static void main(String[] args) throws Exception { Student stu = new Bachelor("computer"); Class clazz = stu.getClass(); //输出class的类名 System.out.println("class类名:" + clazz.getName()); //输出class所在的包 System.out.println("class包:"+ clazz.getPackage()); //获取指定的field System.out.println(clazz.getField("name"));// printMembers(clazz.getFields(), "Fields");// printMembers(clazz.getDeclaredConstructors(), "Constructors");// printMembers(clazz.getMethods(), "methods"); } public static void printMembers(Member[] mbrs, String s) { //Field,Mehtod,constructor都是Member的实现 out.println(s); for (Member mbr : mbrs) { if (mbr instanceof Field) out.println(((Field) mbr).toGenericString()); else if (mbr instanceof Constructor) out.println( ((Constructor ) mbr).toGenericString()); else if (mbr instanceof Method) out.println( ((Method) mbr).toGenericString()); } if (mbrs.length == 0) out.println("不存在" + s); out.println(); }}
另外三行注释代码的输出如下:
对于Field、Constructors的输出应该没有什么问题,可Method的输出就多了很多“意外”的信息,其实这些都继承过来的方法——在java里,任意一个对象都是java,lang.Object的直接或间接的子类,所以getMethods()也相对应的输出里java。lang.Object的九种方法。
方法toGenericString()返回描述此成员(Filed。Method,Constructor)的泛型描述,如果不存在,则调用toString()返回成员(Filed。Method,Constructor)字符串。