Java反射机制

纸上学来终觉浅,在B站找了一个视频学习反射机制,跟着视频敲了一遍代码,理解反射机制的作用,视频质量很高,就是这个UP更新的有点慢。视频地址:Java中的反射 Reflection in Java_哔哩哔哩_bilibili     

直接上代码。

首先是Main方法,通过代码运行示例,学习反射机制的各种功能,最后是模拟容器读取配置文件,自动进行Bean生成、依赖注入的案例。

package com.wmj.test.reflectionInJava;

import com.sun.istack.internal.NotNull;
import org.springframework.context.annotation.Primary;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * java反射机制
 */
public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        //直接通过类对象进行操作
//        int filed = User.publicStaticField;
//        System.out.println(filed);
//        User.myPublicStaticMethod();
//        User user = new User("wmj", 20);
//        System.out.println(user.name);
//        user.myPublicMethod();

        //通过反射,在运行时确定调用的雷和方法
        //获取Class有3种主要方式
        // 1、是根据类的字面常量,如User.class;
        // 这种方式不会立即触发类的初始化,因此User类中的静态代码块不会执行
        //只有访问类的静态成员变量或创建类实例时才会被执行
//        Class<User> clazz = User.class;

        //2、通过getClass方法获取
//        User user = new User("wmj", 20);
        //因为Class对象是在运行时从user实例获取的,而User实例的具体类型只能在运行时创建和确定,
        // 在编译阶段无法准确地判断Class对象的确切类型,所以这里用通配符
//        Class<?> userClass = user.getClass();

        //3、使用Class.forName 方法
        //这种方式 User的静态代码块会被立即执行
//        Class<?> clazz = Class.forName("com.wmj.test.reflectionInJava.User");

        //4、下面 介绍Class的一些方法
//        Class<?> clazz = Class.forName("com.wmj.test.reflectionInJava.User");
        //getDeclaredFields  获取所有字段,无论是public  还是 private 的字段,但是不能获得其父类的字段
//        Field[] fields = clazz.getDeclaredFields();
//        for(Field field : fields){
//            System.out.println(field.getName());
//        }
//        System.out.println("     ");

        //getFields 只获取public字段。如果存在父类的话,包括父类的public字段
//        fields = clazz.getFields();
//        for(Field field : fields){
//            System.out.println(field.getName());
//        }

        //若想获取父类的字段信息,可以先通过getSuperclass,再获取字段信息
//        fields = clazz.getSuperclass().getDeclaredFields();
//        for(Field field : fields){
//            System.out.println(field.getName());
//        }

        //总结:对于其他方法  Declared 表示获取的是所有成员,不管方法是public还是private
        //而不带 Declared 仅代表获取public,包括继承自父类的公共成员

        //根据字段名获取单个字段的信息
//        Class<?> clazz = Class.forName("com.wmj.test.reflectionInJava.User");
//        Field field = clazz.getDeclaredField("comments");
//        //字段类型
//        System.out.println(field.getType());
//        //泛型类型
//        System.out.println(field.getGenericType());
//        //字段的注解类型
//        System.out.println(field.getAnnotationsByType(NotNull.class));

        //接下来是类层面的操作,包括查看和修改静态字段值,以及调用静态方法。
        //User中 有两个静态变量,publicStaticField 、privateStaticField
//        Class<?> clazz = Class.forName("com.wmj.test.reflectionInJava.User");
//        Field field = clazz.getDeclaredField("publicStaticField");
//        System.out.println(field.get(null));

//        Field field2 = clazz.getDeclaredField("privateStaticField");
//        //私有变量要赋权后才能查看
//        field2.setAccessible(true);
//        System.out.println(field2.get(null));
//
//        //给静态变量赋值
//        field2.set(null, 99);
//        System.out.println(field2.get(null));


        //获取类的方法信息
//        Class<?> clazz = Class.forName("com.wmj.test.reflectionInJava.User");
//        Method[] methods = clazz.getDeclaredMethods();
//        for(Method method : methods){
//            System.out.println(method.getName());
//        }
//        //根据方法名获取单个方法的信息
//        Method method = clazz.getDeclaredMethod("myPublicStaticMethod");
//        System.out.println(method.getName());
//        //方法调用
//        method.invoke(null);
//
//        Method method2 = clazz.getDeclaredMethod("myPrivateStaticMethod");
//        //私有方法,需要先赋权,否则报错
//        method2.setAccessible(true);
//        System.out.println(method2.getName());
//        //方法调用
//        method2.invoke(null);
//
//        //调用带参数的方法
//        Method method3 = clazz.getDeclaredMethod("myPrivateStaticMethod", String.class);
//        //私有方法,需要先赋权,否则报错
//        method3.setAccessible(true);
//        System.out.println(method3.getName());
//        //方法调用
//        method3.invoke(null, "PPPPPPPPPP");



        //下面是类实例的方法使用。对类实例进行访问和操作
//        Class<?> clazz = Class.forName("com.wmj.test.reflectionInJava.User");
//        //获取无参构造器
//        Constructor<?> constructor = clazz.getDeclaredConstructor();
//        //有参构造器
//        Constructor<?> constructor2 = clazz.getDeclaredConstructor(String.class, int.class);
//        Object object = constructor2.newInstance("wmj", 18);
//        //类型转换
//        if(object instanceof User){
//            User user = (User) object;
//        }
        //也可以使用cast 方法进行转换,但是因为该方法是通过泛型进行转换的,
        // 因此要求在编译阶段就确定要转换的类型,因此该方法仅对通过字面常量.class获取的Class对象有效
//        Class<User> clazz2 = User.class;
//        //有参构造器
//        Constructor<?> constructor3 = clazz2.getDeclaredConstructor(String.class, int.class);
//        Object object2 = constructor3.newInstance("wmj", 18);
//        User user2 = clazz2.cast(object2);
        //这里虽然介绍了类型的转换,但是这并不是反射的最佳实践。
        //建议使用反射直接调用和操作对象的方法和字段,而不是先进行类型转换,
        // 毕竟如果在编写阶段已经明确了要转换的类型,那么直接显示的使用更合适,而不必依赖反射
        //反射即真正价值在于在处理编译时未知的类型,从而编写更具有通用性的代码

//        Class<?> clazz = Class.forName("com.wmj.test.reflectionInJava.User");
//        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
//        Object object = constructor.newInstance("wmj", 18);
//        Field field = clazz.getDeclaredField("name");
//        //传入object实例,表示要获取的是这个实例对象的name字段,而不是类的静态变量值
//        System.out.println(field.get(object));
//
//        Field age = clazz.getDeclaredField("age");
//        age.setAccessible(true);
//        age.set(object, 30);
//        System.out.println(age.get(object));
        //上面我们将final 字段 age 的值进行了修改,这其实是破坏了封装性和设计原则,尽量避免使用
//        Method method = clazz.getDeclaredMethod("myPrivateMethod");
//        method.setAccessible(true);
//        method.invoke(object);
//
//        Method method2 = clazz.getDeclaredMethod("myPrivateMethod", String.class, String.class);
//        method2.setAccessible(true);
//        method2.invoke(object, "aaa", "bbb");

        //为深入理解反射的应用场景,模拟框架功能,实现通过配置实现服务的依赖注入
        //假设有一个需求,需要通过Order类获取客户信息和地址信息
        //首先是一般的实现方式。
//        Address address = new Address("爱橙街" , "123456");
//        Customer customer = new Customer("wmj", "qq.email.com");
//        Order order = new Order(customer, address);
//        order.getAddress().printPostCode();
//        order.getCustomer().printEmail();
        //这是通过反射的实现方法
        Container container = new Container();
        container.init();
        String className = "com.wmj.test.reflectionInJava.User";
        String fieldName = "message";
        Class<?> clazz = Class.forName(className);
        Object object = container.createInstance(clazz);
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        Object fieldValue = field.get(object);
        Method[] methods = fieldValue.getClass().getDeclaredMethods();
        for(Method method : methods){
            if(method.getDeclaredAnnotation(Primary.class) != null){
                method.invoke(fieldValue);
            }
        }
    }
}

接下来是其他各种类:

package com.wmj.test.reflectionInJava;

import org.springframework.context.annotation.Primary;

public class Address {

    private String street;

    private String postCode;

    public Address(String street, String postCode) {
        this.street = street;
        this.postCode = postCode;
    }

    @Primary
    public void printStreet(){
        System.out.println("printStreet : " + street);
    }

    @Primary
    public void printPostCode(){
        System.out.println("printPostCode : " + postCode);
    }
}
package com.wmj.test.reflectionInJava;


import org.springframework.context.annotation.Bean;

public class Config {

    @Bean
    public Customer customer(){
        return new Customer("wmj", "aaa.qq.com");
    }

    @Bean
    public Address address(){
        return new Address("大洋路", "123");
    }

    @Bean
    public Message message(){
        return new Message("这里有消息");
    }
}
package com.wmj.test.reflectionInJava;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class Container {
    private Map<Class<?>, Method> methods;

    private Object config;

    private Map<Class<?>, Object> services;

    /**
     * 读取配置文件的方法,通过Bean注解来过滤不必要的方法,并存进 methods 中,这些方法用于生成 Bean
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws InstantiationException
     */
    public void init() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        this.methods = new HashMap<>();
        this.services = new HashMap<>();
        Class<?> clazz = Class.forName("com.wmj.test.reflectionInJava.Config");
        Method[] methods = clazz.getDeclaredMethods();
        for(Method method:methods){
            if(method.getDeclaredAnnotation(Bean.class) != null){
                this.methods.put(method.getReturnType(), method);
            }
        }
        this.config = clazz.getConstructor().newInstance();
    }

    /**
     * 在init方法保存了生成Bean的方法后,
     * 通过传入clazz获取类实例方法,并生成Bean返回
     * @param clazz
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public Object getServiceInstanceByClass(Class<?> clazz) throws InvocationTargetException, IllegalAccessException {
        if(this.services.containsKey(clazz)){
            return this.services.get(clazz);
        }else{
            if(this.methods.containsKey(clazz)){
                Method method = this.methods.get(clazz);
                Object obj = method.invoke(this.config);
                this.services.put(clazz, obj);
                return obj;
            }
        }
        return null;
    }

    /**
     * 该方法用于获取Bean,并且进行自动注入
     * @param clazz
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws NoSuchMethodException
     */
    public Object createInstance(Class<?> clazz) throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
        //先获取构造方法
        Constructor<?> [] constructors = clazz.getDeclaredConstructors();
        for(Constructor<?> constructor : constructors){
            //如果构造方法被Autowired注解标记
            if(constructor.getDeclaredAnnotation(Autowired.class) != null){
                //获取构造方法参数数组
                Class<?> [] parameterTypes = constructor.getParameterTypes();
                Object [] argements = new Object[parameterTypes.length];
                //参数装载
                for(int i = 0; i < parameterTypes.length; i ++){
                    argements[i] = getServiceInstanceByClass(parameterTypes[i]);
                }
                //调用构造方法生成Bean
                return constructor.newInstance(argements);
            }
        }
        return clazz.getConstructor().newInstance();
    }
}
package com.wmj.test.reflectionInJava;

import org.springframework.context.annotation.Primary;

public class Customer {

    private String name;

    private String email;

    public Customer(String name, String email) {
        this.name = name;
        this.email = email;
    }

    @Primary
    public void printName(){
        System.out.println("printName : " + name);
    }

    @Primary
    public void printEmail(){
        System.out.println("printEmail : " + email);
    }
}
package com.wmj.test.reflectionInJava;

import org.springframework.context.annotation.Primary;

public class Message {
    private String content;

    public Message(String content) {
        this.content = content;
    }

    public Message() {
    }

    @Primary
    public void printMessage(){
        System.out.println("printMessage: " + this.content);
    }
}
package com.wmj.test.reflectionInJava;

import org.springframework.beans.factory.annotation.Autowired;

public class Order {
    private Customer customer;

    private Address address;

    @Autowired
    public Order(Customer customer, Address address) {
        this.customer = customer;
        this.address = address;
    }

    public Order (){

    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}
package com.wmj.test.reflectionInJava;

public class Person {
    public String personPublic;

    private String personPrivate;
}
package com.wmj.test.reflectionInJava;

import com.sun.istack.internal.NotNull;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

public class User extends Person{

    @NotNull
    public String name;

    private final int age;

    private String email;

    private Message message;

    private List<String> comments;

    public static int publicStaticField = 1;

    private static int privateStaticField = 1;

    static {
        System.out.println("User class  is initialized");
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Autowired
    public User(Message message){
        this.message = message;
        this.age = 18;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }

    public void myPublicMethod(){
        System.out.println("this is a public method");
    }

    private void myPrivateMethod(){
        System.out.println("this is a private method");
    }

    private void myPrivateMethod(String content, String mark){
        System.out.println("this is a private method with parameters. " + content + "   " + mark);
    }

    public static void myPublicStaticMethod(){
        System.out.println("this is a public static Method");
    }

    private static void myPrivateStaticMethod(){
        System.out.println("this is a private static Method");
    }

    private static void myPrivateStaticMethod(String content){
        System.out.println("this is a private static method with parameters: " + content);
    }

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java反射机制是指在运行时动态地获取一个类的信息,并可以操作类的属性、方法和构造器等。Java反射机制可以使程序员在运行时动态地调用类的方法和属性,扩展类的功能,并可以实现注解、工厂模式以及框架开发等。 Java反射机制的原理如下:首先,Java编译器将Java源代码编译为字节码文件,字节码文件中包含着类的信息,这些信息包括类的名称、方法、属性和构造器等等。接着,Java虚拟机将字节码文件加载到内存中,然后通过类加载器将类加载到内存中形成一个类对象,这个类对象可以操作字节码文件中的信息。 使用Java反射机制的过程如下:首先获取类对象,通过类对象来获取类的构造器、属性、方法等信息,然后调用构造器来创建对象,通过属性获取和设置类的成员属性,通过方法调用类的方法等。 Java反射机制的优点是可以在运行时动态地得到类的信息,使得程序员在程序运行时能够对类进行更加灵活的操作,并可以使得程序更加通用化,同时也存在着一定的性能问题,因为Java反射机制需要Java虚拟机进行一定的额外处理,所以在程序运行时需要进行额外的时间和资源消耗。 总之,Java反射机制Java语言的一项重要特性,在Java开发中广泛应用,在代码编写、框架开发以及API开发中具有重要作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值