反射
反射
反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(属性,构造器,方法),并能操作的属性和方法,反射在设计模式和框架都会用到。
反射机制可以完成:
- 判断任意一个对象所属的类
- 在运行时构造任意一个对象
- 在运行时得到任意一个对象的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
反射有关的类:
- java.lang.Class,代表一个类,Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method 代表类的方法
- java.lang.reflect.Field 代表类的成员属性
- java.lang.reflect.Constructor 代表类的构造方法
public class Cat {
private String name;
public int age = 10;
public Cat(){
}
public Cat(String name,int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//反射的简单使用
Class clazz = Class.forName("reflect.Cat");
//获取类的方法
Method method = clazz.getMethod("getAge");
//获取类的属性
Field age = clazz.getField("age");
//获取类的构造器
Constructor constructor = clazz.getConstructor();
//构建一个对象
Object o = constructor.newInstance();
System.out.println(o.getClass());
System.out.println(clazz + " " + method + " " + age);
//运行方法
System.out.println(method.invoke(o));
反射机制的优点和缺点
优点:可以动态的创建和使用对象,使用灵活,没有反射机制,框架就失去了底层支持
缺点:使用反射机制,基本上是解释执行,对执行速度有影响
优化
关闭访问检查,Method,Field,Constructor都有setAccessible()方法,主要用于访问安全检查的开关,设置为true可以关闭检查。
Class
-
Class也是类,因此也继承Object类
-
Class对象不是new出来的,而是由系统创建出来的,是由类加载创建在堆中
Class clazz = Class.forName("reflect.Cat");
-
对于每个Class对象在堆内存中只会有一份,因为类只会加载一次
-
每个类的实例都会记住自己是由哪个Class实例生成的
-
通过一个Class可以得到一个类的完整结构,通过一系列的API
-
Class对象存放在堆中
-
类的字节码二进制数据,是放在方法区,有的地方称为类的元数据
Class常用方法
Class clazz = Class.forName("reflect.Car");
//显示该类是哪个类的对象
System.out.println(clazz);
//显示该类的名字,全类名
System.out.println(clazz.getName());
//显示类的包名
System.out.println(clazz.getPackage().getName());
//显示该类的运行类型
System.out.println(clazz.getClass());
//创建该类对象
Object o = clazz.newInstance();
System.out.println(o);
//获取对象属性
Field brand = clazz.getField("brand");
System.out.println(brand.get(o));//输出属性的值
//重新给属性设置值
brand.set(o,"奔驰");
System.out.println(brand.get(o));
//获取多个属性
Field[] fields = clazz.getFields();
for(Field e : fields){
//获取每个属性的名字
System.out.println(e.getName());
}
/*
class reflect.Car
reflect.Car
reflect
class java.lang.Class
Car{brand='宝马', price=500000, color='白色'}
宝马
奔驰
brand
price
color
*/
获取Class对象方法
//第一种通过Class.forName,主要在编译阶段
Class clazz1 = Class.forName("reflect.Car");
System.out.println(clazz1);
//第二种通过类。class获取
Class clazz2 = Car.class;
System.out.println(clazz2);
//第三种通过对象实例.getClass()获取
Car car = new Car();
Class clazz3 = car.getClass();
System.out.println(clazz3);
//通过类加载器获取
ClassLoader classLoader = car.getClass().getClassLoader();
Class clazz4 = classLoader.loadClass("reflect.Car");
System.out.println(clazz4);
//基本数据类型通过.class获取
Class clazz5 = int.class;
System.out.println(clazz5);
//基本类型的包装类通过类名.TYPE获取
Class clazz6 = Integer.TYPE;
System.out.println(clazz6);
类加载
反射机制是Java实现动态语言的关键,也就是通过反射实现类的动态加载
静态加载:编译的时候加载相关的类,如果没有则报错,依赖性很强
动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不会报错
类的加载时机:
- 使用new创建对象的时候
- 创建子类对象,父类也会被加载
- 使用类的静态属性
- 通过反射
Class常用方法
//Class类中常用方法
Class clazz = Class.forName("reflect.Person");
//获取类的全类名
System.out.println(clazz.getName());
//获取类的名字
System.out.println(clazz.getSimpleName());
//返回包名
System.out.println(clazz.getPackage());
//返回父类类信息
Class superClass = clazz.getSuperclass();
System.out.println(superClass);
//返回所有public属性包括父类的
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
//返回所有本类所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
}
//返回所有public方法,包括父类的
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
//返回本类所有的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
//返回所有public构造器
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName());
}
//返回所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor.getName());
}
//返回所有接口
Class[] interfaces = clazz.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println(anInterface);
}
//返回所有注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//返回所有本类所有属性
Class clazz = Class.forName("reflect.Person");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("该类的属性:" + declaredField.getName() +
"该属性的属性权限: " + declaredField.getModifiers() + "该属性的类型: " +
declaredField.getType());
}
//返回本类所有的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("该方法的名字:" + declaredMethod.getName() + "该方法的修饰符:" +
declaredMethod.getModifiers() + "该方法的返回值类型: " + declaredMethod.getReturnType());
Class[] parameterTypes = declaredMethod.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println("该方法的参数类型: " + parameterType.getTypeName());
}
}
创建对象
Class clazz = Class.forName("reflect.User");
//通过默认无参构造函数构建对象
Object o = clazz.newInstance();
System.out.println(o);
//通过公共有参构造函数构造对象
Constructor constructor = clazz.getConstructor(String.class);
Object o1 = constructor.newInstance("张三");
System.out.println(o1);
//通过公共有参构造函数构造对象
Constructor constructor1 = clazz.getConstructor(String.class, int.class);
Object o2 = constructor1.newInstance("李四", 20);
System.out.println(o2);
//通过私有构造函数构造对象
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class, String.class);
declaredConstructor.setAccessible(true);
Object o3 = declaredConstructor.newInstance("王五", 30, "男");
System.out.println(o3);
访问属性
Class clazz = Class.forName("reflect.User");
Object o = clazz.newInstance();
//访问公有属性
Field name = clazz.getField("name");
name.set(o,"张三");
System.out.println(o);
//访问私有属性
Field salary = clazz.getDeclaredField("salary");
salary.setAccessible(true);
salary.set(o,2345.67);
System.out.println(o);
//访问静态属性
Field test = clazz.getDeclaredField("test");
test.setAccessible(true);
test.set(null,"获取");
System.out.println(test.get(null));
访问方法
Class clazz = Class.forName("reflect.User");
Object o = clazz.newInstance();
//访问公共方法
Method m1 = clazz.getMethod("m1");
m1.invoke(o);
//有参数的方法
Method m2 = clazz.getMethod("m2", String.class);
m2.invoke(o,"张三");
//私有有返回值的方法
Method m3 = clazz.getDeclaredMethod("m3");
m3.setAccessible(true);
Object invoke = m3.invoke(o);
System.out.println("返回值: " + invoke);