1. 反射
反射库( reflection library) 是一个工具集, 用于动态的操作java代码的程序.
能够分析类能力的程序被称为反射(reflection)
- 在运行时分析类的能力
- 在运行时查看对象,
- 实现通用的数组操作代码
- 用Method对象
1.1 Class类
在程序运行期间,Java 运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。 虚拟机利用运行时类型信息选择相应的方法执行。然而, 可以通过专门的 Java 类访问这些信息,保存这些信息的类被称为 Class。
一个 Class 对象将表示一个特定类的属性, 获取的方式有三种
Student s=new Student("大肥羊","(*^▽^*)");
//getClass获取
Class class1=s.getClass();
//通过forName 类名获取
Class class2=Class.forName(s.getClass().getName());
//根据 类.class获取
Class class3=Student.class;
Class表示的是一个类型 并代表这个类型必须是类 int.Class 也是一个Class类型的对象
通过Class创建对象
通过newInstance()可以调用 某类的无参构造器 来创建一个实例
Class class1=s.getClass();
class1.newInstance();
2. 使用反射
使用反射检查类的结构, 在 java.lang.reflect 包中有三个类 Field、 Method 和 Constructor 分别用于描述类的域、 方法和构造器。
package bai.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ReflectionTest {
public static void main(String[] args) {
Class c1= Student.class;
//返回父类
Class supercl=c1.getSuperclass();
//类的修饰符
String modifiers= Modifier.toString(c1.getModifiers());
p("类的修饰符: "+modifiers);
//构造器
printConstructors(c1);
//方法
printMethods(c1);
//字段
printFields(c1);
}
private static void p(String str){
System.out.println(str);
}
private static void printFields(Class c1) {
//获取所有的属性
Field[] fields=c1.getDeclaredFields();
for (Field field:fields){
p("-----------");
p("字段名称:"+field.getName());
Class type=field.getType();
String name= type.getName();
p("字段类型:"+name);
String modifiers=Modifier.toString(field.getModifiers());
p("修饰符:"+modifiers);
}
}
private static void printMethods(Class c1) {
//获取所有方法
Method[] methods = c1.getDeclaredMethods();
for (Method m : methods) {
p("-----------");
//获取返回类型
Class returnType = m.getReturnType();
String name = m.getName();
p("方法名:"+name);
String modifiers = Modifier.toString(m.getModifiers());
p("方法值修饰符:"+modifiers);
Class[] paramTypes=m.getParameterTypes();
for (Class paramType : paramTypes) {
p("参数:"+paramType.getName());
}
p("返回值:"+returnType.getName());
}
}
private static void printConstructors(Class c1) {
Constructor[] constructors=c1.getDeclaredConstructors();
for (Constructor c : constructors) {
p("-----------");
//获取构造函数声明类的二进制名称
String name=c.getName();
p("构造函数的名称: "+name);
//获取修饰符
String modifiers = Modifier.toString(c.getModifiers());
p("构造函数的修饰符: "+modifiers);
//获取所有的参数类型
Class[] paramTypes = c.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++)
{
p("参数"+j+" : "+paramTypes[j].getName());
}
}
}
}
2.1 Class常用方法 获取 字段 方法 构造函数
2.2 field Method Constructor
2.3 Modifier 修饰符
2.4 使用反射查看对象内容
获取属性的当前值,需要使用 java.lang.reflect.Field 类 该类可以获取 属性对象(Field) ,Field提供了关于属性的多个方法.
package bai.reflect;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class RefleCtionTest2 {
public static void main(String[] args) throws Exception {
Class c = Student.class;
//根据参数...获取构造器 如果需要获取private的 加上getDeclaredConstructor(XXX)
Constructor constructor = c.getConstructor(String.class, String.class);
//根据方法名和参数...获取方法对象
Method method = c.getMethod("toString");
//创建对象
Student o = (Student) constructor.newInstance("哈哈", "1123");
//通过 Method 的 invoke 调用 o 的toString 方法
System.out.println("创建对象:"+method.invoke(o));
//获取private字段
Field field = c.getDeclaredField("name");
//System.out.println(field.get(o));//get时候异常
// java.lang.IllegalAccessException:Class bai.reflect.RefleCtionTest2
// can not access a member of class bai.reflect.Student with modifiers "private"
//修改访问权限
field.setAccessible(true);
field.set(o,"哦噢耶");
System.out.println(field.get(o));
System.out.println("修改后:"+method.invoke(o));
}
public static Object toArray(Object[] a,int newLength){
//获取对象的类型
Class c1=a.getClass();
if (!c1.isArray()) return null;
//获取数组的类型
Class componentType=c1.getComponentType();
int length= Array.getLength(a);
//创建一个新的数组 object[] 数组不能转成其他类型的数组 但是obj对象可以
Object newArray=Array.newInstance(componentType,newLength);
//拷贝数组
System.arraycopy(a,0,newArray,0,Math.min(length,newLength));
return newArray;
}
}
Class的getDeclaredFields( )可以获取Field[ ] 即所有的字段, 包括private,调用field.get()方法时,收到java访问控制的约束,会抛出异常
Field继承了AccessibleObject类(可访问对象) 通过类的方法 可以设置属性的访问权限, 就可以获取和修改私有属性.
2.5 使用 反射编写泛型数组
reflect 中操作数组的类 java.lang.reflect.Array, Object[]数组不能转换为Test[] 数组 会转换异常 但是Object对象可以转换成Test[]
public static Object toArray(Object[] a,int newLength){
//获取对象的类型
Class c1=a.getClass();
if (!c1.isArray()) return null;
//获取数组的类型
Class componentType=c1.getComponentType();
int length= Array.getLength(a);
//创建一个新的数组 object[] 数组不能转成其他类型的数组 但是obj对象可以
Object newArray=Array.newInstance(componentType,newLength);
//拷贝数组
System.arraycopy(a,0,newArray,0,Math.min(length,newLength));
return newArray;
}
2.6 任意调用方法
Class c = Student.class;
//根据参数...获取构造器 如果需要获取private的 加上getDeclaredConstructor(XXX) Constructor constructor = c.getConstructor(String.class, String.class);
//根据方法名和参数...获取方法对象
Method method = c.getMethod("toString");
//创建对象
Student o = (Student) constructor.newInstance("哈哈", "1123");
//通过 Method 的 invoke 调用 o 的toString 方法
System.out.println("创建对象:"+method.invoke(o));