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<MayiktUserEntity> mayiktUserEntityClass = MayiktUserEntity.class;
// 2.new 对象 通过对象获取class springioc容器 根据class获取对象
MayiktUserEntity mayiktUserEntity = new MayiktUserEntity();
Class<? extends MayiktUserEntity> 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;
1、获得Class:主要有三种方法:
(1)Object–>getClass
(2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
(3)通过class类的静态方法:forName(String className)(最常用)
package com.mayikt;
import com.mayikt.entity.MayiktUserEntity;
/**
* @author 余胜军
* @ClassName Test01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName Test01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName UserEntity
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName Test03
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName Test04
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName Test05
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName Test05
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName UserEntity
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName UserEntity
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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;
/**
* @author 余胜军
* @ClassName Test07
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
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主题中;
结合上节课观察者模式
<dependencies>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
</dependencies>
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;
/**
* @author 余胜军
* @ClassName ReflexUtils
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class ReflexUtils {
public static Set<Class> getInterfaceImpls(Class c) {
Reflections reflections = new Reflections("com.mayikt");
//Filter是个接口,获取在指定包扫描的目录所有的实现类
Set<Class> 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<Class> interfaceImpls = ReflexUtils.getInterfaceImpls(MsgObServer.class);
// 2.在根据类名称从IOC容器中查找bean对象 存入到集合中
ArrayList<ObServer> 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);
}
}