1. 啥是反射

1.初识反射

刚开始学反射的时候,我是一脸懵逼的,这玩意真的是“抽象的妈妈给抽象开门-抽象到家了。”

为什么创建对象要先获取 Class 对象?这不多此一举吗?我直接 new 一下不是更简单吗?

什么是程序springboot运行时获取类的属性和方法?平成员变量和局部变量时都是程序编译出错了再修改代码,我为什么要考虑程序运行时的状态?

我平时开发也用不到,学这玩意有啥用变量的指针其含义是指该变量的

后来学了注解、spring、SpringMVC 等技术之后,发现反射无处不在。

2.JVM 加载类

我们写的 java 程序要放到 JVM 中运行,所以要学习变量与函数反射,首先需要了解 JVM 加载类的过程。

你真的了解反射吗?

1.数据库技术我们写的 .java 文件叫做源代码。

2.我们在一个类中写了一个 ma变量类型有哪些in 方法,然后点击 I变量DEA 的 run 按钮,JVM 运行时会触发 jdk 的 javac 指令将源代码编译成 .class 文件,这个文件又叫做字节码文件。

3.JVM 的类加载器(你可以理解成一个工具)通过一个类的全限定名来获取该类的二进制字节流,然变量的指针其含义是指该变量的后将该 class 文件加载到 JVM 的方法区中。

4.类加载器加载一个 .class 文件到方法区的同时会在堆中生成一个唯一的 Class 对象,这个 Class 包含这个类的成员变量、构造方法以及成员方法。

5.这个 Class 对象会创建与该类对应的对象实例。

所以表面上你 new 了一个对象,实际上当 JVM 运行程序的时候,真正帮变量类型有哪些你创建对象的是该类的 Class 对象。

也就是说反射其实jvm内存模型就是 JVM 在运行程序的时候将你创建的所有类都封装成唯一一个 Class 对象。这个 Class 对象包含属性、构造方法和成员方法。你拿到了 Class 对象,也springboot面试题就能获取这三个东西。

你拿到了反射之后(Class)的变量是什么意思属性,就能获取对象的属性名、属性类别、属性值,也能给属性设置值。

你拿到了反射之后(Class)的构造方法,就能创建对jvm调优象。

你拿到了反射之后(Class)的成员方法,就能执行该方法。

3.反射的概念

JAVA 反射机制是在程序运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调静态成员变量用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 java 语言的反射机制。

知道了 JVM 加载类的过程,变量与函数相信你应该更加深入的了解了反射的概念。

反射:JVM 运行程序 –> .java 文件 –> .clas数据库系统的核心是s 文件 –> Class数据库系统概论第五版课后答案 对象 –> 创建对象实例并操作该实例的属性和方法

接下来我就讲一下反射中的相关类以及常用方法。

2. Class 对变量4

获取 C数据库是什么lass 对象

先建一个 User 类:

public class User {
    private  String name = "知否君";
    public String sex = "男";
    public User() {
    }
    public User(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }
    public void eat(){
        System.out.println("人要吃饭!");
    }
    private void run(){
        System.out.println("人要跑步!");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}

获取 Class 对象的三种方式:

1. Class.forName(“全类名”)

全类名:包名+类名

Class userClass = Class.forName("com.xxl.model.User");

2. 类名.class

Class userClass = User.class;

3. 对象.getClass()

User user = new User();
Class userClass = user.getClass();

尽管有三种方式获取 Class 对象,但是我们一般采用上述第一种方式。

拿到 Class 对象之后,我们就可以操作与它相关的方法了。

3. 获取类名

1.获取完整类名:包名+类名

getName()

Class userClass = Class.forName("com.xxl.model.User");
String name = userClass.getName();
System.out.println(name);

打印结果:

你真的了解反射吗?

2.获取简单类名:不包括包名

getSimpleName()

Class userClass = Class.forName("com.xxl.model.User");
String simpleName = userClass.getSimpleName();
System.out.println(simpleName);

打印结果:

你真的了解反射吗?

4. 属jvm参数配置

4.1 获取属性

1.获取所有公有属性:public 修饰

getFields()

Class userClass = Class.forName("com.xxl.model.User");
Field[] fields = userClass.getFields();
for (Field field : fields) {
    System.out.println(field);
}

打印结果变量值

你真的了解反射吗?

2.获取单个公有属性

getField(“属性名”)

Class userClass = Class.forName("com.xxl.model.User");
Field field = userClass.getField("sex");
System.out.println(field);

打印结果:

你真的了解反射吗?

3.获取所有属性:公有+私有

getDeclaredFields()

Class userClass = Class.forName("com.xxl.model.User");
Field[] fields = userClass.getDeclaredFields();
for (Field field : fields) {
    System.out.println(field);
}

打印结果:

你真的了解反射吗?

4.获取单个属性:公有或者私有

getDeclaredField(“属性名”)

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
Field sexField = userClass.getDeclaredField("sex");
System.out.println(nameField);
System.out.println(sexField);

打印结果:

你真的了解反射吗?

4.2 操作属性

1.获取属性名称

getName()

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
System.out.println(nameField.getName());

打印结果:

你真的了解反射吗?

2.获取属性类型

getType()

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
System.out.println(nameField.getType());

打印结果:

你真的了解反射吗?

3.获取属性值

get(object)

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("sex");
User user = new User();
System.out.println(nameField.get(user));

打印结果:

你真的了解反射吗?

注: 通过反射不能直接获取私有属性的值,但是可以通过修改访问入口来获取私有属性的值。

设置允许访问私springboot有属性:

field.setAccessible(true);

例如:

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
nameField.setAccessible(true);
User user = new User();
System.out.println(nameField.get(user));

打印方法:

你真的了解反射吗?

4.设置属性值

set(object,”变量值属性值”)

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
nameField.setAccessible(true);
User user = new User();
nameField.set(user,"张无忌");
System.out.println(nameField.get(user));

打印jvm性能调优结果:

你真的了解反射吗?

5. 构造方法

1.获取所有公有构造方法

getConstructors()

Class userClass = Class.forName("com.xxl.model.User");
Constructor[] constructors = userClass.getConstructors();
for (Constructor constructor : constructors) {
    System.out.println(constructor);
}

打印结果:

你真的了解反射吗?

2.获取与参数类型匹配的构造方法

getConstructor(参数类型)

Class userClass = Class.forName("com.xxl.model.User");
Constructor constructor = userClass.getConstructor(String.class, String.class);
System.out.println(constructor);

打印结果:

你真的了解反射吗?

6. 成员方法

6.1获取成员方法

1.获取所有公共方法

getMethods()

Class userClass = Class.forName("com.xxl.model.User");
Method[] methods = userClass.getMethods();
for (Method method : methods) {
    System.out.println(method);
}

打印结果:

你真的了解反射吗?

我们发现,打印结果除了自定义数据库是什么的公共jvm参数配置方法,还有继承自 Object 类的公共方法。

2.获取某个公共方法

getMethod(“方法名”, 参数类型)

Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getMethod("setName", String.class);
System.out.println(method);

打印结果:

你真的了解反射吗?

3.获取所有方法:公有+私有

getDeclaredMethojvm调优ds()

Class userClass = Class.forName("com.xxl.model.User");
Method[] declaredMethods = userClass.getDeclaredMethods();
for (Method method : declaredMethods) {
    System.out.println(method);
}

打印结果:

你真的了解反射吗?

4.获取某个方法:公有或者私有

getDeclarspringcloud五大组件edMethod(“方法名”, 参数类型)

Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getDeclaredMethod("run");
System.out.println(method);

打印结果:

你真的了解反射吗?

6.变量的定义2 执行成员方法

invoke(objectjvm是什么,”方法参jvm调优面试题数”springboot面试题)

Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getDeclaredMethod("eat");
User user = new User();
method.invoke(user);

打印结果:

你真的了解反射吗?

注: 通过反射不能直接执行私有成员方法,但是可以设置允许成员变量有默认值吗访变量的定义问。

设置允许数据库系统概论第五版课后答案执行私有方法:

method.setAccessible(true);

7. 注解

1.判断类上或者方法上时候包含某个注解

isAnnotationPresent(注解名.class)

例如:

Class userClass = Class.forName("com.xxl.model.User");
if(userClass.isAnnotationPresent(Component.class)){
    Component annotation = (Component)userClass.getAnnotation(Component.class);
    String value = annotation.value();
    System.out.println(value);
};

2.获取注解

getAnnotation(注解名.class)

例如:

Class userClass = Class.forName("com.xxl.model.User");
// 获取类上的注解
Annotation annotation1 = userClass.getAnnotation(Component.class);
Method method = userClass.getMethod("eat");
// 获取方法上的某个注解
Annotation annotation2 = userClass.getAnnotation(Component.class);

8. 创建类的实例

1.通过 Class 实例化对象

Class数据库是什么.newInstance()

Class userClass = Class.forName("com.xxl.model.User");
User user = (User)userClass.newInstance();
System.out.println("姓名:"+user.getName()+" 性别:"+user.getSex());

打印结果:数据库原理及应用

你真的了解反射吗?

2.通过构造方法实例化对象

constructor.newspring框架Instance(参数值)

Class userClass = Class.forName("com.xxl.model.User");
Constructor constructor = userClass.getConstructor(String.class, String.class);
User user = (User)constructor.newInstance\("李诗情", "女"\);
System.out.println("姓名:"+user.getName()+" 性别:"+user.getSex());

打印结果:

你真的了解反射吗?

9数据库系统工程师. 反射案例

有一天技术总监对张三说:”张三spring翻译,听说你最近学反射了呀。那你设计一个对象的工厂类给我看看。”

张三心想:”哟,快过年了,领导这是要给我涨工资啊。这次我一定好好表现一次。”

5分钟过后,张三提交了代码:

public class ObjectFactory {
    public static User getUser() {
        User user = null;
        try {
            Class userClass = Class.forName("com.xxl.model.User");
            user = (User) userClass.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return user;
    }
    public static UserService getUserService() {
        UserService userService = null;
        try {
            Class userClass = Class.forName("com.xxl.service.impl.UserServiceImpl");
            userService = (UserService) userClass.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return userService;
    }
}

技术总监瞄了一眼代码,对张三说:”你这个工厂类存在两个问题。”

1.代码存在大量冗余。如果有一万个类,你是不是要写一万个静态方法?

2.代码耦合度太高。如果这些类存放的包路径发生改变,你再用 forName()获取 Class 对springcloud五大组件象是不是就会spring翻译有问题?你还要一个个手动改代码,然后再编译、打包、部署。。你不觉得麻烦吗?

“发散你的思维想一下,能不能只设计一个静态类,通过传参的方式用反射创建对象,传递的参数要降低和工厂类的耦合度。顺便提醒你一下,可以参考一下 JDBC 获取变量与函数数据库成员变量和实例变量的区别接参数的方式。”

张三一听:”不愧是总监啊,醍醐灌顶啊!等我 10 分钟变量泵。”

10 分钟后,张三再次提交了代码:

object.properties

user=com.xxl.model.User
userService=com.xxl.service.impl.UserServiceImpl

ObjectFactory

public class ObjectFactory {
    private static Properties objectProperty = new Properties();
    // 静态方法在类初始化时执行,且只执行一次
    static{
        try {
            InputStream inputStream = ObjectFactory.class.getResourceAsStream("/object.properties");
            objectProperty.load(inputStream);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static Object getObject(String key){
        Object object = null;
        try {
            Class objectClass = Class.forName(objectProperty.getProperty(key));
            object = objectClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return object;
    }
}

测试方法:

@Test
  void testObject() {
      User user = (User)ObjectFactory.getObject("user");
      UserService userService = (UserService)ObjectFactory.getObject("userService");
      System.out.println(user);
      System.out.println(userService);
  }

执行结果:

你真的了解反射吗?

总监看后连连点头,笑着对张三说:“用 prspringcloud五大组件ojvm性能调优perties 文件存放类的全限定名降低了代码的耦合度,通过传参的方式使用反射创建对象又降低了代码的冗余性成员变量和成员方法,这次改的可以。”成员变量和成员方法

“好啦,今晚项目要上线,先吃饭去吧,一会还要改 bug。”

张三:”.jvm是什么………好的总监。”

10. 反射的作用

我们或多或少都听说过设计框架的时候会用到反射,例如 Spring 的 IOC 就用到了工厂模式和反jvm参数配置射来创建对象,BeanUtils 的底层也是使用反射来拷贝属性。所以反射无处不在。

尽管我们日常开发几乎用不到反射,但是我们必须要搞懂反射的原理,因为它能帮我们理数据库系统的核心是解框架设计的原理。