反射相关
类的加载机制
classLoader(双亲委派)加载部分.class->类信息放入元空间->生成唯一Class对象放进堆内存
反射
目的:代码执行时,能够获取类的方法名、属性,以及给属性赋值
原理:Class对象相当于元空间的类信息的镜像,new直接通过元空间的类对象(有指针指向元空间类信息),反射是通过镜像生成对象。
实现:
public class Animal {
//default 子类不可跨包, protect可以子类可跨包, private子类可以继承
public float run(float distance){
return distance;
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Animal animal1 = new Animal();
animal1.run(2);
//类的反射对象
Class clz = Class.forName("Animal");
//方法的反射对象
Method method = clz.getMethod("run", float.class);
//构造方法的反射对象
Constructor constructor = clz.getConstructor();
//通过反射实例化对象
Object object = constructor.newInstance();
//通过放射调用方法
Object distance = method.invoke(object, 3);
}
}
三种获取Class的方式
- 类全限定名获取:Class class = Class.forName(“com.xxxx.xx”);
- 具体类获取:Class class = 类.Class;
- 对象获取:Class class=object.getClass();
参考:https://www.bilibili.com/video/BV13q4y1s7U8?spm_id_from=333.337.search-card.all.click&vd_source=ccd2ca4db2c7f66c6f0ab6dd058b6208
动态代理
目的:想在所有被代理的方法前加一个方法,动态代理可以方便实现
原理:所有实现被代理对象的方法,都会转为执行invoke中的方法
实现:类似aop
注解
原理:注解只是一个标志,反射查看类信息时发现注解就进行相应操作。
实现:
1.使用Spring中定义好的注解
定义类,使用注解注册以及赋值
@Component
@Data
public class Student {
@Value("小明")
private String name;
@Value("18")
private int age;
}
定义配置,扫描包范围
@Configuration
@ComponentScan("com.test.bean")
public class MainConfiguration {
}
打印类信息
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfiguration.class);
System.out.println(context.getBean(Student.class));
}
}
结果
Student(name=小明, age=18)
2.自定义注解实现@Component(spring工厂)以及@Value(spring依赖注入)
注解定义-》注解使用-》@MyComponent表示通过反射生成对象@MyValue表示通过反射赋值(更改属性权限)
注解定义
@Retention(RetentionPolicy.RUNTIME) //运行时使用
@Target(ElementType.TYPE) //作用于类上
public @interface MyComponent {
}
@Retention(RetentionPolicy.RUNTIME) //运行时使用
@Target(ElementType.FIELD) //作用于属性上
public @interface MyValue {
String value(); //放置给的属性值
}
类更改为自己的注解
@MyComponent
public class Student {
@MyValue("小明")
private String name;
@MyValue("18")
private int age;
}
寻找@MyComponet
Class<Student> studentClass = Student.class;
MyComponent myComponent = studentClass.getAnnotation(MyComponent.class);//这里开始只有类,只能找类注解,属性注解需要获取属性后,再获取属性上的注解
实现@MyComponent的方法
if(myComponent!=null){
Constructor<Student> constructor = studentClass.getConstructor(null);
Student student = constructor.newInstance();
}
寻找@MyValue
Field[] declareFields = studentClass.getDeclaredFields();// getFields()只能获取公有属性,getDeclaredFields()获取所有属性
for(Field field : declareFields){
MyValue myValue = studentClass.getAnnotation(MyValue.class);
}
实现@MyValue的方法
if(myValue != null){
declareField.setAccessible(true); // 变量为private,需要修改属性权限
// 如果注解中的值为int需要进行转换
if(declareField.getType().getName().equals("int")){
declareField.set(student, Integer.parseInt(myValue.value()));//将注解中的值,赋值给创建出的目标对象
}
else{
declareField.set(student, myValue.value());//将注解中的值,赋值给创建出的目标对象
}
}
完整的测试类
public class Test {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<Student> studentClass = Student.class;
MyComponent myComponent = studentClass.getAnnotation(MyComponent.class);
if(myComponent!=null){
Constructor<Student> constructor = studentClass.getConstructor(null);
Student student = constructor.newInstance();
Field[] declareFields = studentClass.getDeclaredFields();// getFields()只能获取公有属性,getDeclaredFields()获取所有属性
for(Field declareField : declareFields){
MyValue myValue = declareField.getAnnotation(MyValue.class);//属性注解,就要在属性上去寻找
if(myValue != null){
declareField.setAccessible(true); // 变量为private,需要修改属性权限
// 如果注解中的值为int需要进行转换
if(declareField.getType().getName().equals("int")){
declareField.set(student, Integer.parseInt(myValue.value()));//将注解中的值,赋值给创建出的目标对象
}
else{
declareField.set(student, myValue.value());//将注解中的值,赋值给创建