反射
反射是框架的灵魂
反射也是动态化代理的基础
在运行期间 动态的获取类的信息以及对类进行操作的机制(获取编译后类的class字节码文件)
把每一个class文件放大来看 那么其中的每个组成部分都是一个又一个的对象
一个类由 具有相同属性和行为的对象组成
一个class文件看成一个类,每个类里边都有成员变量 方法 构造方法可以被看成属性
1.获取class对象
public static void getClassMothods() {
//1.获取class对象
//1
Class<Car> carClass = Car.class;
//2
Car car = new Car();
final Class<? extends Car> aClass = car.getClass();
//3
try {
final Class<?> aClass1 = Class.forName("com.klay.sm.reflect.Car");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
2.获取成员变量信息
public static void getFieldsMothods(){
// 全路径
try {
Class<?> aClass = Class.forName("com.klay.sm.reflect.Car");
Object o = aClass.newInstance();
System.out.println(o);
//获取成员变量 getFields()只能获取public修饰的属性 包括从父类继承的属性
final Field[] fields = aClass.getFields();
System.out.println(fields.length);
for (Field field:fields){
System.out.println(field);
System.out.println("==========");
System.out.println(field.getName());
}
//getDeclaredFields()只获取本类声明的属性 public private修饰的都可以
aClass.getDeclaredFields();
System.out.println(fields.length);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
3.获取方法对象 并且调用
public static void getMethods() {
try {
//调用类的class文件
Class<?> aClass = Class.forName("com.qy30.sm.reflect.Car");
// aClass.getConstructor()
//实例化
Object obj = aClass.newInstance();
// 调用public方法(包括继承的)
Method[] methods = aClass.getMethods();
/* for (Method method : methods) {
System.out.println(method.getName());
}*/
// 调用本类的方法 public和private
Method[] declaredMethods = aClass.getDeclaredMethods();
/* for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}*/
//1,根据方法名和形参类型获取指定的方法对象
Method declaredMethod = aClass.getDeclaredMethod("run");
// 把方法改为可访问的public
declaredMethod.setAccessible(true);
// 通过反射调用方法 传对象以及实参 调用方法invoke
declaredMethod.invoke(obj);
// 2,拿到有参数的 方法对象
Method addOil = aClass.getDeclaredMethod("addOil", String.class, Integer.class);
addOil.invoke(obj, "abc", 10);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
4,练习题
public static void exercise() {
try {
//调用class文件
Class<?> stuClass = Class.forName("com.qy30.sm.reflect.Student");
//实例化
Object student = stuClass.newInstance();
//调用本类方法
Method setCar = stuClass.getDeclaredMethod("setCar", Car.class);
// 通过配置文件传入进来
Class<?> aClass = Class.forName("配置文件(args[]或者读取配置文件)");
//车的实例化
Object o = aClass.newInstance();
//invoke()调用方法 传入参数
setCar.invoke(student, o);
System.out.println(student);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
5,构造器的使用
public static void getConstructor() {
try {
Class<?> aClass = Class.forName("com.qy30.sm.reflect.BmwCar");
// 默认会调用无参构造 没有无参构造就不能用这种办法
// Object o = aClass.newInstance();
// 获取构造器 public
Constructor<?>[] constructors = aClass.getConstructors();
// 所有的构造器
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
//一个构造器
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Double.class);
//更改修饰符
declaredConstructor.setAccessible(true);
//创建构造器对象
Object o1 = declaredConstructor.newInstance(6.6);
System.out.println(o1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
6.类加载器
按需加载 使用到的时候才会加载
字节码文件只会被加载一次,不会重复加载
静态代码块在类加载到内存的那一刻执行 并且只能加载一次
java–>complier编译为.class文件–>由类加载器加载到内存–>字节码校验文件–>解释器解释 成机器指令–>操作系统
java中的加载器
-
启动类加载器 bootstrap class loader
核心类的加载器 核心类 不是java代码写的
-
扩展类加载器 extend class loader
\jre\lib\ext 加载内部的类
-
应用类加载器 application class loader
加载用户自定义类
-
其他类加载器
双亲委派机制
当一个类加载器收到了类加载的请求 他不会自己去尝试加载这个类 而是把这个请求委派给父类加载器去完成 每一个层次的类加载器都是如此 因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(他的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载,从而保证每个类只会被加载一次