栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

07.Java反射技术

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

07.Java反射技术

什么是反射技术

1.Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

2.Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

Java反射机制可以动态方式获取到 class相关信息 class中成员方法、属性 ,反射技术灵活调用方法 或者

给我们成员属性赋值,class.forName 初始化对象(创建我们的对象)

类加载器:第九期Java进阶课程中 类加载器

简单回顾双亲委派机制

1.启动(Bootstrap)类加载器:加载JVM自身工作需要的类,它由JVM自己实现。它会加载$JAVA_HOME/jre/lib下的文件 底层是C语言实现

2.扩展(Extension)类加载器:它是JVM的一部分,由sun.misc.LauncherExtClassLoader实现,他会加载ExtClassLoader实现,他会加载ExtClassLoader实现,他会加载JAVA_HOME/jre/lib/ext目录中的文件(或由System.getProperty(“java.ext.dirs”)所指定的文件)。 底层是Java实现

3.(应用)AppClassLoader 类加载器:应用类加载器,我们工作中接触最多的也是这个类加载器,它由sun.misc.Launcher$AppClassLoader实现。他加载我们工程目录classpath下的class及jar包 底层是java实现

4.自定义类加载器: 也就是用户自己定义的类加载器

反射技术的原理

Class对象的由来是将.class文件读入内存,并为之创建一个Class对象。

     // 1.获取class方式 直接类名称.
        Class mayiktUserEntityClass = MayiktUserEntity.class;
        // 2.new 对象 通过对象获取class  springioc容器 根据class获取对象
        MayiktUserEntity mayiktUserEntity = new MayiktUserEntity();
        Class aClass = mayiktUserEntity.getClass();
        //类的完整路径地址 包的名称+类名称组合  第三种 企业使用最多的
        Class aClass1 = Class.forName("com.mayikt.entity.MayiktUserEntity");
反射的优缺点

优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

缺点:

1.反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;

2.反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

反射机制应用场景

1.JDBC 中Class.forName(“com.mysql.jdbc.Driver”)-----反射技术加载 mysql驱动

2.Spring底层基于反射初始化对象

3.(写一套自己 )第三方框架扩展功能 代理设计模式 反射技术

反射机制核心类

Java.lang.Class;

Java.lang.reflect.Constructor;

Java.lang.reflect.Field;

Java.lang.reflect.Method;

Java.lang.reflect.Modifier;

反射机制API使用 获取Class

1、获得Class:主要有三种方法:

(1)Object–>getClass

(2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性

(3)通过class类的静态方法:forName(String className)(最常用)

package com.mayikt;

import com.mayikt.entity.MayiktUserEntity;



public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 1.方式1 通过对象名称.getClass();
        MayiktUserEntity user1 = new MayiktUserEntity();
        System.out.println(user1.getClass());
        System.out.println(user1.getClass().getName());
        // 2.方式2: 直接通过类名称.class;
        System.out.println(MayiktUserEntity.class);
        // 3.方式3 :class.forName("类的完整路径地址")
        Class aClass = Class.forName("com.mayikt.entity.MayiktUserEntity");
        System.out.println(aClass==user1.getClass());
    }
}

注意就是在运行期间,一个类只有一个Class对象产生,所以打印结果都是true

判断是否为某个类的示例

在之前我们使用instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断时候为某个类的实例,它是一个native方法。

    public native boolean isInstance(Object obj);
package com.mayikt;

import com.mayikt.entity.MayiktUserEntity;



public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 1.方式1 通过对象名称.getClass();
        MayiktUserEntity user1 = new MayiktUserEntity();
        System.out.println(user1.getClass());
        System.out.println(user1.getClass().getName());
        // 2.方式2: 直接通过类名称.class;
        System.out.println(MayiktUserEntity.class);
        // 3.方式3 :class.forName("类的完整路径地址")
        Class aClass = Class.forName("com.mayikt.entity.MayiktUserEntity");
        System.out.println(aClass == user1.getClass());
        boolean instance = aClass.isInstance(new Object());
        System.out.println(instance);
    }
}
通过反射创建对象 反射使用无参构造方法初始化对象

使用Class对象的newInstance()方法来创建Class对象对应类的实例。

package com.mayikt.entity;


public class MayiktUserEntity {
    private String userName;
    private Integer age;

    public MayiktUserEntity() {
        System.out.println("无参构造方法初始化....");
    }
}
反射使用有参构造方法初始化对象
// 2.1 获取到构造方法  调用有参构造方法初始化对象
Constructor constructor = aClass.getConstructor(String.class, Integer.class);
 MayiktUserEntity user2 = (MayiktUserEntity) constructor.newInstance("mayikt", 22);
System.out.println(user2);

  public MayiktUserEntity(String userName, Integer age) {
        this.userName = userName;
        this.age = age;
  }
反射获取构造方法
(1)批量获取的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
(2)单个获取的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
(3) 调用构造方法:
Constructor-->newInstance(Object... initargs)
newInstance是 Constructor类的方法(管理构造函数的类)
api的解释为:newInstance(Object... initargs) ,使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象,并为之调用。
package com.mayikt;

import java.lang.reflect.Constructor;
import java.util.Arrays;


public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class aClass = Class.forName("com.mayikt.entity.MayiktUserEntity");
        // 1.所有"公有的"构造方法
        Constructor[] constructors1 = aClass.getConstructors();
        for (int i = 0; i < constructors1.length; i++) {
            System.out.println(constructors1[i]);
        }
        System.out.println("--------------------------");
        //2.获取所有的构造方法(包括私有、受保护、默认、公有)
        Constructor[] constructors2 = aClass.getDeclaredConstructors();
        for (int i = 0; i < constructors2.length; i++) {
            System.out.println(constructors2[i]);
        }
        
    }
}
反射获取成员属性

获取成员变量并调用:

1.批量的

​ 1.1.Field[] getFields():获取所有的"公有字段"

​ 1.2.Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;

2.获取单个的:

2.1.public Field getField(String fieldName):获取某个"公有的"字段;

2.2.public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)

3.设置字段的值 需要注意权限问题:

3.1.Field --> public void set(Object obj,Object value):

3.2.参数说明:

3.3.obj:要设置的字段所在的对象;

相关代码:

package com.mayikt;

import java.lang.reflect.Field;


public class Test04 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.获取所有的"公有字段"
        Class aClass = Class.forName("com.mayikt.entity.MayiktUserEntity");
        Field[] fields = aClass.getFields();
        for (int i = 0; i < fields.length; i++) {
            System.out.println(fields[i]);
        }
        //2.获取所有字段,包括:私有、受保护、默认、公有;
        Field[] declaredFields = aClass.getDeclaredFields();
        for (int i = 0; i < declaredFields.length; i++) {
            System.out.println(declaredFields[i]);
        }

    }
}

使用反射给类中成员属性赋值

package com.mayikt;

import com.mayikt.entity.MayiktUserEntity;

import java.lang.reflect.Field;


public class Test05 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        Class aClass = Class.forName("com.mayikt.entity.MayiktUserEntity");
        //1.反射使用无参构造方法初始化对象
        MayiktUserEntity mayiktUserEntity = (MayiktUserEntity) aClass.newInstance();
        Field userNameField = aClass.getDeclaredField("userName");
        userNameField.set(mayiktUserEntity, "mayikt");
        //2.获取该对象的成员userName值
        System.out.println(mayiktUserEntity.getUserName());
    }
}

错误提示:
Exception in thread "main" java.lang.IllegalAccessException: Class com.mayikt.Test05 can not access a member of class com.mayikt.entity.MayiktUserEntity with modifiers "private"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
	at java.lang.reflect.Field.set(Field.java:761)
	at com.mayikt.Test05.main(Test05.java:20)
 反射在默认的情况下不允许给私有属性赋值 需要设置权限
 
 package com.mayikt;

import com.mayikt.entity.MayiktUserEntity;

import java.lang.reflect.Field;


public class Test05 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        Class aClass = Class.forName("com.mayikt.entity.MayiktUserEntity");
        //1.反射使用无参构造方法初始化对象
        MayiktUserEntity mayiktUserEntity = (MayiktUserEntity) aClass.newInstance();
        Field userNameField = aClass.getDeclaredField("userName");
        userNameField.setAccessible(true);
        userNameField.set(mayiktUserEntity, "mayikt");
        //2.获取该对象的成员userName值
        System.out.println(mayiktUserEntity.getUserName());
    }
}

 
反射获取成员方法

获取成员方法并调用:

1.所有的方法:

1.1.public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)

1.2.public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)

2.获取单个的方法:

​ 2.1.public Method getMethod(String name,Class… parameterTypes):

				参数:

					name : 方法名;

					Class ... : 形参的Class类型对象

	public Method getDeclaredMethod(String name,Class... parameterTypes)

​ 调用方法:

	Method --> public Object invoke(Object obj,Object... args):

				参数说明:

				obj : 要调用方法的对象;
package com.mayikt.entity;


public class MayiktUserEntity extends ParentEntity {
    private String userName;
    private Integer age;

    public MayiktUserEntity() {
        System.out.println("无参构造方法初始化....");
    }

    public MayiktUserEntity(String userName, Integer age) {
        this.userName = userName;
        this.age = age;
    }

    MayiktUserEntity(String userName) {
        this.userName = userName;
        this.age = age;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "MayiktUserEntity{" +
                "userName='" + userName + ''' +
                ", age=" + age +
                '}';
    }
    private void addUser(){
        System.out.println("addUser");
    }
}


package com.mayikt.entity;


public class MayiktUserEntity extends ParentEntity {
    private String userName;
    private Integer age;

    public MayiktUserEntity() {
        System.out.println("无参构造方法初始化....");
    }

    public MayiktUserEntity(String userName, Integer age) {
        this.userName = userName;
        this.age = age;
    }

    MayiktUserEntity(String userName) {
        this.userName = userName;
        this.age = age;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "MayiktUserEntity{" +
                "userName='" + userName + ''' +
                ", age=" + age +
                '}';
    }
    private void addUser(){
        System.out.println("addUser");
    }
}

使用反射调用类中成员方法

反射调用类中的方法
package com.mayikt;

import com.mayikt.entity.MayiktUserEntity;

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


public class Test07 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class aClass = Class.forName("com.mayikt.entity.MayiktUserEntity");
        MayiktUserEntity mayiktUserEntity = (MayiktUserEntity) aClass.newInstance();
        Method addUserMethod = aClass.getDeclaredMethod("addUser", Integer.class);
        addUserMethod.setAccessible(true);
        Object result = addUserMethod.invoke(mayiktUserEntity, 10);
        System.out.println(result);
    }
}
反射机制综合案例

思路:

1.当我们springboot项目启动完成之后,获取当前有哪些观察者? MsgObServer 所有实现class

2.在根据该class去ioc容器中查找到该bean对象 存入到 msg主题中;

结合上节课观察者模式

maven依赖
  
        
            org.reflections
            reflections
            0.9.10
        
    
反射工具类
package com.mayikt.utils;

import com.mayikt.observer.ObServer;
import com.mayikt.observer.impl.MsgObServer;
import org.reflections.Reflections;

import java.util.List;
import java.util.Set;


public class ReflexUtils {
    public static Set getInterfaceImpls(Class c) {
        Reflections reflections = new Reflections("com.mayikt");
        //Filter是个接口,获取在指定包扫描的目录所有的实现类
        Set classes = reflections.getSubTypesOf(c);
        return classes;
    }
    
    public static void main(String[] args) {
        //        ReflexUtils.getInterfaceImpls(MsgObServer.class)
        //        interfaceImpls.forEach((t) -> {
        //            System.out.println("name:" + t.getSimpleName());
        //        });
    }
}
package com.mayikt.init;

import com.mayikt.observer.ObServer;
import com.mayikt.observer.impl.MsgObServer;
import com.mayikt.observer.impl.MsgSubject;
import com.mayikt.utils.ReflexUtils;
import com.mayikt.utils.SpringUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Set;

@Component
public class SpringBootInitialization implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 1.使用java反射机制 获取我们自定义的 ObServer下 有哪些实现类
        Set interfaceImpls = ReflexUtils.getInterfaceImpls(MsgObServer.class);
        // 2.在根据类名称从IOC容器中查找bean对象 存入到集合中
        ArrayList obServers = new ArrayList<>();
        interfaceImpls.forEach((c) -> {
            ObServer obServer = (ObServer) SpringUtils.getBean(c);
            //存入到集合中
            obServers.add(obServer);
        });
        // 3.赋值给主题
        MsgSubject msgSubject = SpringUtils.getBean("msgSubject", MsgSubject.class);
        msgSubject.addObServerAll(obServers);
        
    }
    
    
}
相关代码

反射代码.rar

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/998829.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号