(一)认识java.lang.Class类
1)Class类的实例不能通过new来创建。Class类只有一个私有的构造方法。
private Class(ClassLoader loader) {
classLoader = loader;
}
2)既然不能通过new来获取Class类的实例,那么我们如何获取Class类的实例呢?
有3种方式:
方式一:类名.class
方式二:对象.getClass()
方式三:调用Class类的静态方法,Class.forName(全类名)
String str=”abc”;
Class clazz1=String.class;
Class clazz2=str.getClass();//所有对象都有getClass()方法
Class clazz3=Class.forName("java.lang.String");
//clazz1,clazz2,clazz3是完全相等的,因为他们都指向同一份字节码
System.out.println(clazz1==clazz2);//输出true
System.out.println(clazz2==clazz3);//输出true
3)所有的类和接口都有对应的Class类的实例。8种基本数据类型、void以及数组也有对应的Class类的实例
①基本数据类型有对应的Class类的实例
Class clazz1=int.class;
Class clazz2=boolean.class;
System.out.println(clazz1);//输出int
System.out.println(clazz2);//输出boolean
②void有对应的Class类的实例
Class clazz1=void.class;
System.out.println(clazz1);//输出void
③数组有对应的Class类的实例
Class clazz4=int[].class;
Class clazz5=String[].class;
Class clazz6=int[][].class;
Class clazz7=String[][][].class;
System.out.println(clazz4);
System.out.println(clazz5);
System.out.println(clazz6);
System.out.println(clazz7);
输出结果:
class [I
class [Ljava.lang.String;
class [[I
class [[[Ljava.lang.String;
不难发现,数组的Class类的实例,取决于2个因素:数据类型和维度。
(二)认识java.lang.Class类的一些方法
1)getName():以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称
2)toString():重写了父类Object的toString()方法
public String toString() {
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
可见:接口的前缀是“interface”;基本类型的前缀是空字符串;其他(例如:数组)均是以“class”为前缀的。
3)newInstance():返回Object或者泛型类型。注意:会调用public的无参构造函数来创建实例对象。如果没有公有的无参构造器,则会抛出异常。
4)获取字段信息
public Field[] getFields();//获取所有的public的字段,包括从父类继承过来的
public Field getField(String name);//根据字段名获取public的字段
public Field[] getDeclaredFields();//获取所有声明的字段,可以是private字段,但是不包括从父类继承过来的字段
public Field getDeclaredField(String name);//根据字段名获取声明的字段
5)获取方法信息
public Method[] getMethods();
public Method getMethod(String name, Class<?>... parameterTypes);
public Method[] getDeclaredMethods();
public Method getDeclaredMethod(String name, Class<?>... parameterTypes);
6)获取构造方法信息
public Constructor<?>[] getConstructors();
public Constructor<T> getConstructor(Class<?>... parameterTypes);
public Constructor<?>[] getDeclaredConstructors();
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);
7)获取内部类信息
public Class<?>[] getClasses();//获取所有public的内部类
public Class<?>[] getDeclaredClasses();//获取所有声明的内部类
8)获取该类所在的外部类
public Class<?> getDeclaringClass();//获取声明该类的外部类
如果该类为外部类,则返回null。如果该类为内部类,则返回该内部类的外部类。
9)返回类型为boolean的一些简单方法
public native boolean isInstance(Object obj);//判断某个对象是否是它的实例
public native boolean isInterface();//是否是接口
public native boolean isArray();//是否是数组类型
public native boolean isPrimitive();//是否是基本数据类型
public boolean isAnnotation();//是否是注解
10)获取该类的父类和实现的接口
public native Class<? super T> getSuperclass();//获取该类的父类
public Class<?>[] getInterfaces();//获取该类实现的所有接口
public Type getGenericSuperclass();
public Type[] getGenericInterfaces();
11)获取修饰符
public native int getModifiers();//返回值是int类型,返回值代表的不是修饰符的个数
特定的int代表特定的某些修饰符。例如:17代表public final; 1代表public
(三)认识java.lang.reflect.Field类的一些方法
1)构造方法:
Field(Class<?> declaringClass,
String name,
Class<?> type,
int modifiers,
int slot,
String signature,
byte[] annotations)
{
this.clazz = declaringClass;
this.name = name;
this.type = type;
this.modifiers = modifiers;
this.slot = slot;
this.signature = signature;
this.annotations = annotations;
}
2)public String toString();//返回一个描述此 Field 的字符串
3)获取字段的值
①public Object get(Object obj);//返回指定对象上该字段的值
问题来了:字段有静态字段和实例字段之分,该如何获取这2种字段的值呢?
如果是实例字段,那么传过去的obj对象必须是declaringClass的实例。
如果是静态变量,那么没必要传具体的实例对象过去,只要把类对应的Class实例传过去就好了,即传的是declaringClass。示例如下:
/*
* 获取非静态字段的值
*/
public static Object getValue(Object obj,String fieldName) throws Exception{
Class clazz=obj.getClass();
//获取public的字段,如果fieldName对应的字段不是public,则找不到该字段
Field field = clazz.getField(fieldName);
//非静态属性,需要传具体的实例对象过去
return field.get(obj);
}
/*
* 获取静态字段的值
*/
public static Object getStaticValue(String className,String fieldName) throws Exception{
Class clazz=Class.forName(className);
//获取public的字段,如果fieldName对应的字段不是public,则找不到该字段
Field field = clazz.getField(fieldName);
//由于是静态属性,静态属性是类的,不是某个对象的,把对应的Class实例传过去即可
return field.get(clazz);
}
注意:获取字段的值不一定会成功,因为字段有访问权限。例如:对于private的字段,只有在类内部可以取到它的值。异常信息如下:java.lang.IllegalAccessException: Class com.Demo3 can not access a member of class com.Test with modifiers “private static”。
②public xxx getXxx(Object obj);// 涉及到8种数据类型。如果该字段是int类型,可以采用getInt(Object obj)方法获取指定对象上该字段的值。
4)设置字段的值
①public void set(Object obj, Object value);//为字段赋值。obj代表要操作的对象,value代表要赋的值
②public void setXxx(Object obj, xxx z);//涉及到8种数据类型
(四)认识java.lang.reflect.Field类的一些方法
1)构造函数
Method(Class<?> declaringClass,
String name,
Class<?>[] parameterTypes,
Class<?> returnType,
Class<?>[] checkedExceptions,
int modifiers,
int slot,
String signature,
byte[] annotations,
byte[] parameterAnnotations,
byte[] annotationDefault)
{
this.clazz = declaringClass;
this.name = name;
this.parameterTypes = parameterTypes;
this.returnType = returnType;
this.exceptionTypes = checkedExceptions;
this.modifiers = modifiers;
this.slot = slot;
this.signature = signature;
this.annotations = annotations;
this.parameterAnnotations = parameterAnnotations;
this.annotationDefault = annotationDefault;
}
2)最为重要的一个方法
public Object invoke(Object obj, Object… args); //调用指定对象的该方法,args是传递给该方法的参数。
注意点:
①如果是静态方法,那么传过去的obj对象为declaringClass(declaringClass是一个Class类的实例)。
②如果是非静态方法,那么传过去的obj对象必须是declaringClass的实例。如果不是实例,会抛出如下异常:java.lang.IllegalArgumentException: object is not an instance of declaring class
③该invoke方法的返回值就是该方法执行后的返回值。如果方法的返回值为void,那么该invoke方法的输出结果为null。如果方法的返回值类型为int,那么invoke方法的结果类型为Integer(因为会自动包装成Object对象)。
(五)认识java.lang.reflect.Constructor<T>
类的一些方法
1)构造器
Constructor(Class<T> declaringClass,
Class<?>[] parameterTypes,
Class<?>[] checkedExceptions,
int modifiers,
int slot,
String signature,
byte[] annotations,
byte[] parameterAnnotations) {
this.clazz = declaringClass;
this.parameterTypes = parameterTypes;
this.exceptionTypes = checkedExceptions;
this.modifiers = modifiers;
this.slot = slot;
this.signature = signature;
this.annotations = annotations;
this.parameterAnnotations = parameterAnnotations;
}
2)最为重要的一个方法
public T newInstance(Object ... initargs);//通过构造方法创建实例
最后一点:public Field[] getFields();和public Field[] getDeclaredFields();
public Method[] getMethods();和public Method[] getDeclaredMethods();
一般使用getFields();和getMethods();较多,获取公有的字段和方法才是有意义的,因为公有的字段和方法在任何地方都可以访问和调用。