对于每一种类,Java虚拟机都会初始化一个Class类型的实例,当我们编译一个新的类就会产生一个Class对象,并且这个Class对象会被保存在同名的.class文件里。当我们new一个对象的时候,或者引用静态变量时,Java虚拟机的类加载器系统会将对应的Class对象加载到JVM中,然后JVM再根据这个Class相关的信息创建我们需要的实例对象或者提供静态变量的引用值。
获取class对象及部分信息的方法:
@Override
protected void initView() {
//获取class类的几种方式
Log.i(TAG,"1 通过对象实例获取class==============================");
Class stringClass = "abc".getClass();
Log.i(TAG,"普通对象的class:" + stringClass);
Log.i(TAG,"2 通过类的类型获取class==============================");
Class easyTypeClass = int.class;
Log.i(TAG,"基本类型的class:" + easyTypeClass);
Class enumClass = E.A.getClass();
Log.i(TAG,"enum类型的class:" + enumClass);
Log.i(TAG,"3 通过类的全局限定名获取class==============================");
try {
Class nameClass = Class.forName("java.lang.String");
Log.i(TAG,"通过全局限定名 java.lang.String 获取class: " + nameClass);
Class cDoubleArrayClass = Class.forName("[D");
Log.i(TAG,"通过全局限定名 [D 获取double[].class:" + cDoubleArrayClass);
Class cStringArrayClass = Class.forName("[[Ljava.lang.String;");
Log.i(TAG,"通过全局限定名 [[Ljava.lang.String; 获取String[][].class: " + cStringArrayClass);
Log.i(TAG,"4 通过包装类的TYPE字段获取class==============================");
Class doubleClass = Double.TYPE;
Log.i(TAG,"基本类型的包装类也可以通过 TYPE字段获取Class:" + doubleClass);
Log.i(TAG,"5 获取指定类的父类 class==============================");
Class baseFraClass = BaseFragment.class;
Log.i(TAG,"BaseFragment的Class对象: " + baseFraClass);
Class baseFraFatherClass = baseFraClass.getSuperclass();
Log.i(TAG,"BaseFragment的父类的Class对象: " + baseFraFatherClass);
Log.i(TAG,"获取类的详细信息, 修饰符,类名,泛型类型,父类, 以hashMap类为例====================");
Class hashMapClass = HashMap.class;
Log.i(TAG,"hashMap 的 name为:" + hashMapClass.getName());
Log.i(TAG,"hashMap 的 SimpleName为:" + hashMapClass.getSimpleName());
Log.i(TAG,"hashMap 的 类修饰符为:" + Modifier.toString(hashMapClass.getModifiers()));
TypeVariable[] tv = hashMapClass.getTypeParameters();
StringBuilder pas = new StringBuilder();
for (int i = 0; i < tv.length; i++) {
TypeVariable t = tv[i];
pas.append(t.getName() + " ");
}
Log.i(TAG,"hashMap 的 泛型为:" + pas);
Type[] ts = hashMapClass.getGenericInterfaces();
StringBuilder genericInterface = new StringBuilder();
for (int i = 0; i < ts.length; i++) {
genericInterface.append(ts[i].toString() + " ");
}
Log.i(TAG,"hashMap 的 实现接口, getGenericInterfaces :" + genericInterface);
Type[] tss = hashMapClass.getInterfaces();
StringBuilder interfaces = new StringBuilder();
for (int i = 0; i < tss.length; i++) {
interfaces.append(tss[i].toString() + " ");
}
Log.i(TAG,"hashMap 的 实现接口, getInterfaces :" + interfaces);
List<Class> fathers = new ArrayList<>();
addAncestor(ReflexDemoAct.class, fathers);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < fathers.size(); i++) {
Class c = fathers.get(i);
builder.append(c.getCanonicalName() + "\n");
}
Log.i(TAG, "ReflexDemoAct 的继承树为 : \n" + builder.toString());
Annotation[] annotations = ReflexDemoAct.class.getAnnotations();
StringBuilder annotationString = new StringBuilder();
if(null == annotations || annotations.length == 0){
Log.i(TAG, "ReflectDemoAct类没有注解");
} else {
for (int i = 0; i < annotations.length; i++) {
Annotation annotation = annotations[i];
annotationString.append(annotation.toString() + " ");
}
Log.i(TAG, "ReflectDemoAct类的Runtime类型的注解是: "+ annotationString.toString());
}
//以下是变量,方法,构造方法对应的类对应
Log.i(TAG, Field.class.getCanonicalName() + ", 对应类的变量");
Log.i(TAG, Method.class.getCanonicalName() + ", 对应类的方法");
Log.i(TAG, Constructor.class.getCanonicalName() + ", 对应类的构造方法");
Log.i(TAG, "但是,上面的方法正常情况下都不能获取private修饰的变量");
Log.i(TAG, AccessibleObject.class.getCanonicalName() + ", 通过它的setAccessible()方法来取消Java语言访问权限的检查");
Log.i(TAG, "很庆幸的是,Field, Method, Constructor方法均继承自AccessibleObject类,均可以设置这个入口,这样就可以访问private的内容了");
Class reflexActClass = ReflexDemoAct.class;
Field[] fields = reflexActClass.getFields();
StringBuilder fieldBuild = new StringBuilder();
for (int i = 0; i < fields.length; i++) {
fieldBuild.append(fields[i].toString() + "\n");
}
Log.i(TAG, "得到的成员变量为: " + fieldBuild.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void addAncestor(Class<?> cla, List<Class> claList){
Class<?> fatherCla = cla.getSuperclass();
if (null != fatherCla){
claList.add(fatherCla);
addAncestor(fatherCla, claList);
}
}
Field
通过Field可以访问给定对象的类变量,仅对于当前类,不包含其父类里面的变量,包括获取变量的类型,修饰符,注解,变量的名,变量的值,或者重新设置变量值。即使变量是private的。Class类有4种获取Field的方式。
- getDeclaredField(String name) 获取指定的变量(只要是声明的变量都能获得,即使是private的。)
- getField(String name), 获取指定的变量(但是只能是public的)
- deDeclaredFields(), 获取所有声明的变量,(包括private的)
- getFields(),获取所有的public变量。
package com.example.forev.mycodelibrary;
import android.util.Log;
public class Cat {
public static final String TAG = Cat.class.getSimpleName();
private String name;
@Deprecated
public int age;
public Cat(String name, int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public void eat(String food){
Log.d(TAG, "eat food " + food);
}
public void eat(String... foods){
StringBuilder s = new StringBuilder();
for(String food : foods){
s.append(food);
s.append(" ");
}
Log.d(TAG, "eat food " + s.toString());
}
public void sleep(){
Log.d(TAG, "sleep");
}
@Override
public String toString() {
return "name = " + name + " age = " + age;
}
}
private void logFieldUses() {
Class reflexActClass = Cat.class;
Field[] fields = reflexActClass.getDeclaredFields();
StringBuilder fieldBuild = new StringBuilder();
fieldBuild.append("\n");
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
fieldBuild.append("变量名:" + f.getName() + " ");
fieldBuild.append("类型:" + f.getType() + " ");
fieldBuild.append("修饰符:"+ Modifier.toString(f.getModifiers()) + " ");
Annotation[] as = f.getAnnotations();
if (null == as || as.length == 0){
fieldBuild.append("没有注解\n");
} else {
for (int k = 0; k < as.length; k++) {
Annotation an = as[k];
fieldBuild.append("注解" + k + ":" + an.toString() + " ");
}
}
fieldBuild.append("\n");
}
Log.i(TAG, "通过 getFields() 得到的public成员变量为: " + fieldBuild.toString());
try {
Cat cat = new Cat("yayali", 3);
Field name = reflexActClass.getDeclaredField("name");
//name是private类型的,所以要设置一下才可以访问。
name.setAccessible(true);
String nameValue = (String) name.get(cat);
Log.i(TAG, "name的值为:" + nameValue);
Field age = reflexActClass.getField("age");
int ageValue = (int) age.get(cat);
Log.i(TAG, "age的值为:" + ageValue);
Field tag = reflexActClass.getField("TAG");
String tagValue = (String) tag.get(cat);
Log.i(TAG, "TAG的值为:" + tagValue);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
打印结果为:
2019-03-06 15:32:26.001 7835-7835/com.example.forev.mycodelibrary I/ReflexDemoAct: 通过 getFields() 得到的public成员变量为:
变量名:age 类型:int 修饰符:public 注解0:@java.lang.Deprecated()
变量名:name 类型:class java.lang.String 修饰符:private 没有注解
变量名:TAG 类型:class java.lang.String 修饰符:public static final 没有注解
2019-03-06 15:32:26.001 7835-7835/com.example.forev.mycodelibrary I/ReflexDemoAct: name的值为:yayali
2019-03-06 15:32:26.001 7835-7835/com.example.forev.mycodelibrary I/ReflexDemoAct: age的值为:3
2019-03-06 15:32:26.001 7835-7835/com.example.forev.mycodelibrary I/ReflexDemoAct: TAG的值为:Cat
Method
代码如下:
private void logMethodUses(){
Class catClass = Cat.class;
Method[] methods = catClass.getDeclaredMethods();
StringBuilder builder = new StringBuilder();
builder.append("\n");
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
builder.append("方法名为:" + method.getName() + " ");
builder.append("修饰符为:" + Modifier.toString(method.getModifiers()) + " ");
builder.append("返回类型为:" + method.getGenericReturnType().toString() + " ");
//方法抛出的异常
Type[] exceptionTypes = method.getGenericExceptionTypes();
if (0 == exceptionTypes.length){
builder.append("没有异常! ");
} else {
builder.append("\"\\n 抛出的异常为:\\n\"");
for (int k = 0; k < exceptionTypes.length; k++) {
Type type = exceptionTypes[k];
builder.append(type.toString() + "\n");
}
}
//方法的参数,包括类型,名称,
Type[] ptypes = method.getGenericParameterTypes();
if (0 == ptypes.length){
builder.append("没有参数! ");
} else {
builder.append("参数类型为:\n");
for (int c = 0; c < ptypes.length; c++) {
Type type = ptypes[c];
builder.append(type.toString() + "\n");
}
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
Parameter[] params = method.getParameters();
if (0 == params.length) {
builder.append(" 没有参数");
} else {
for(int y = 0; y < params.length; y++) {
Parameter parameter = params[y];
String pName = parameter.getName();
String type = parameter.getType().toString();
builder.append(" 参数" + y + "的名字是:" + pName + " 类型是:" + type + "\n");
}
}
}
//判断是否是可变参数
builder.append(method.isSynthetic() ? "有可变参数! " : "没有可变参数! ");
builder.append("\n");
}
Log.i(TAG, "method相关的信息为: " + builder.toString());
Log.i(TAG, "\n 开始通过反射调用方法!");
Cat cat = new Cat("huahua", 6);
Method method = null;
try {
//重载机制的存在,我们得传入一个描述具体传什么类型的参数
method = Cat.class.getMethod("eat", String.class);
method.invoke(cat, "鱼干");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
打印日志:
2019-03-06 18:17:53.848 14929-14929/com.example.forev.mycodelibrary I/ReflexDemoAct: method相关的信息为:
方法名为:eat 修饰符为:public 返回类型为:void 没有异常! 参数类型为:
class java.lang.String
参数0的名字是:arg0 类型是:class java.lang.String
没有可变参数!
方法名为:eat 修饰符为:public transient 返回类型为:void 没有异常! 参数类型为:
class [Ljava.lang.String;
参数0的名字是:arg0 类型是:class [Ljava.lang.String;
没有可变参数!
方法名为:getName 修饰符为:public 返回类型为:class java.lang.String 没有异常! 没有参数! 没有参数没有可变参数!
方法名为:sleep 修饰符为:public 返回类型为:void 没有异常! 没有参数! 没有参数没有可变参数!
方法名为:toString 修饰符为:public 返回类型为:class java.lang.String 没有异常! 没有参数! 没有参数没有可变参数!
2019-03-06 18:17:53.848 14929-14929/com.example.forev.mycodelibrary I/ReflexDemoAct: 开始通过反射调用方法!
2019-03-06 18:17:53.848 14929-14929/com.example.forev.mycodelibrary D/Cat: eat food 鱼干
Constructor 构造器
private void logConstructorUses(){
Log.i(TAG, "测试构造方法!");
try {
Class catClass = Cat.class;
Constructor constructor = catClass.getConstructor(String.class, int.class);
Cat cat = (Cat) constructor.newInstance("黑猫警长", 12);
Method sleepMethod = catClass.getMethod("sleep");
sleepMethod.invoke(cat);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
打印日志为:
2019-03-06 18:27:43.162 15201-15201/com.example.forev.mycodelibrary I/ReflexDemoAct: 测试构造方法!
2019-03-06 18:27:43.162 15201-15201/com.example.forev.mycodelibrary D/Cat: sleep