本章涉及到框架开发中必用的反射以及常用方法 很重要 注重理解并实践
第17章 反射
17.1 一个需求引出反射
package com.fsl; public class Cat { private String name = "招财猫"; public int age = 10; //public的 public Cat() {} //无参构造器 public Cat(String name) { this.name = name; } public void hi() { //常用方法 //System.out.println("hi " + name); } public void cry() { //常用方法 System.out.println(name + " 喵喵叫.."); } }
package com.fsl; import com.fsl.Cat; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; /** * 反射问题的引入 */ @SuppressWarnings({"all"}) public class ReflectionQuestion { public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //根据配置文件 re.properties 指定信息, 创建Cat对象并调用方法hi //老韩回忆 //传统的方式 new 对象 -》 调用方法 // Cat cat = new Cat(); // cat.hi(); ===> cat.cry() 修改源码 //我们尝试做一做 -> 明白反射 //1. 使用Properties 类, 可以读写配置文件 Properties properties = new Properties(); properties.load(new FileInputStream("src\\main\\resources\\re.properties")); String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat" String methodName = properties.get("method").toString();//"hi" System.out.println("classfullpath=" + classfullpath); System.out.println("method=" + methodName); //2. 创建对象 , 传统的方法,行不通 =》 反射机制 //new classfullpath(); //3. 使用反射机制解决 //(1) 加载类, 返回Class类型的对象cls Class cls = Class.forName(classfullpath); //(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例 Object o = cls.newInstance(); System.out.println("o的运行类型=" + o.getClass()); //运行类型 //(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象 // 即:在反射中,可以把方法视为对象(万物皆对象) Method method1 = cls.getMethod(methodName); //(4) 通过method1 调用方法: 即通过方法对象来实现调用方法 System.out.println("============================="); method1.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象) } }
classfullpath=com.fsl.Cat method=cry
17.2 反射机制
- java reflection
反射机制允许程序执行期借助于Reflection API取得任何类的内部信息 比如成员变量 构造器 成员方等 并能操作对象的属性和方法 反射在设计模式和框架底层都会用到
加载完类之后 在堆中就产生了一个Class类型的对象 一个类只有一个Class对象 这个对象包含了类的完整结构信息 通过这个对象得到类的结构 这个对象就像一面镜子 通过这个镜子看到类的结构 所以形象地称之为 反射
- Java反射原理图
- 反射相关的主要类
package com.fsl; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Properties; class reflection{ public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { Properties properties=new Properties(); properties.load(new FileInputStream("src\\main\\resources\\re.properties")); String classFullPath=properties.get("classfullpath").toString(); String methodName=properties.get("method").toString(); System.out.println(classFullPath+" "+methodName); Class cls=Class.forName(classFullPath); System.out.println(cls); //获取method,field,constructor Method method=cls.getMethod(methodName); Field field=cls.getField("age");//注意只能获取非private属性 Constructor constructor1=cls.getConstructor(); Constructor constructor2=cls.getConstructor(String.class); System.out.println(method+" "+field+" "+constructor1+" "+constructor2); } }
- 反射优点缺点
个人理解:
首先 我们要了解编译时与运行时的本质区别
编译时:编译器在这个阶段处理源代码,将其转换为字节码(对于 Java 而言)。在编译时,编译器只能基于已有的源代码和静态的配置(如固定的代码逻辑、常量等)进行操作。它无法知道运行时的实际情况,例如用户在运行程序时可能更改的配置文件内容。
运行时:程序在运行时,JVM(Java 虚拟机)加载字节码并执行。在这个阶段,程序可以获取外部环境的信息,如配置文件的内容、用户输入等,并根据这些信息动态地调整行为。
编译时创建对象适合对性能要求较高且业务逻辑简单的场景,而运行时创建对象(尤其是通过反射等机制)更适合框架开发等需要高度灵活性和扩展性的场景。框架开发选择运行时创建对象主要是为了满足多样化的用户需求、支持插件扩展和实现松耦合设计。
而反射可以做什么事呢?
在框架开发中(如Spring),我们往往都是通过配置文件来确定创建哪些对象 因为框架通常需要处理各种各样的业务场景和用户需求 例如在 Spring 框架中,通过运行时创建对象,可以根据配置文件(如 XML 配置或 Java 配置类)动态地决定要创建哪些对象,并处理它们之间的依赖关系 不同的用户可能有不同的配置需求 运行时创建对象可以很好地适应这种变化 所以我们属于运行时创建对象 而运行时创建对象就是通过反射来做的
17.3 Class类
package com.fsl; class class1{ public static void main(String[] args) throws ClassNotFoundException { Class cls1=Class.forName("com.fsl.Cat"); Class cls2=Class.forName("com.fsl.Cat"); Class cls3=Class.forName("com.fsl.Cat"); System.out.println(cls1.hashCode()); System.out.println(cls2.hashCode()); System.out.println(cls3.hashCode()); } }//三个Class对象的hashcode()一样 说明对于存放在对立的Class类对象 内存中只有一份 因为类只加载一次
- class类常用方法
17.4 获取class类对象
package com.fsl; class getclass{ public static void main(String[] args) throws ClassNotFoundException { //获取class对象的六种方式 Class<?> cls1=Class.forName("com.fsl.Cat"); System.out.println(cls1); Class cls2=Cat.class; System.out.println(cls2); Cat cat = new Cat(); Class cls3=cat.getClass(); System.out.println(cls3); ClassLoader cl=cat.getClass().getClassLoader(); Class cls4=cl.loadClass("com.fsl.Cat"); System.out.println(cls4); Class cls5=int.class; System.out.println(cls5); Class cls6=Integer.TYPE; System.out.println(cls6); } }
17.5 哪些类型有Class对象
package com.fsl; import java.io.Serializable; /** * 演示哪些类型有Class对象 */ public class AllTypeClass { public static void main(String[] args) { Class<String> cls1 = String.class;//外部类 Class<Serializable> cls2 = Serializable.class;//接口 Class<Integer[]> cls3 = Integer[].class;//数组 Class<float[][]> cls4 = float[][].class;//二维数组 Class<Deprecated> cls5 = Deprecated.class;//注解 //枚举 Class<Thread.State> cls6 = Thread.State.class; Class<Long> cls7 = long.class;//基本数据类型 Class<Void> cls8 = void.class;//void数据类型 Class<Class> cls9 = Class.class;// System.out.println(cls1); System.out.println(cls2); System.out.println(cls3); System.out.println(cls4); System.out.println(cls5); System.out.println(cls6); System.out.println(cls7); System.out.println(cls8); System.out.println(cls9); } }
17.6 类加载
- 类加载时机
- 类加载过程图
- 类加载各阶段完成任务
- 加载阶段
- 连接阶段 -验证
- 连接阶段-准备
- 连接阶段-解析
- Initialzation初始化
17.7 通过反射获取类结构信息
package com.fsl; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 演示如何通过反射获取类的结构信息 */ public class ReflectionUtils { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { ReflectionUtils re=new ReflectionUtils(); re.api_01(); re.api_02(); } @Test public void api_02() throws ClassNotFoundException, NoSuchMethodException { //得到Class对象 Class<?> personCls = Class.forName("com.fsl.Cat"); //getDeclaredFields:获取本类中所有属性 //规定 说明: 默认修饰符 是0 , public 是1 ,private 是 2 ,protected 是 4 , static 是 8 ,final 是 16 Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有属性=" + declaredField.getName() + " 该属性的修饰符值=" + declaredField.getModifiers() + " 该属性的类型=" + declaredField.getType()); } //getDeclaredMethods:获取本类中所有方法 Method[] declaredMethods = personCls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中所有方法=" + declaredMethod.getName() + " 该方法的访问修饰符值=" + declaredMethod.getModifiers() + " 该方法返回类型" + declaredMethod.getReturnType()); //输出当前这个方法的形参数组情况 Class<?>[] parameterTypes = declaredMethod.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println("该方法的形参类型=" + parameterType); } } //getDeclaredConstructors:获取本类中所有构造器 Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println("===================="); System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名 Class<?>[] parameterTypes = declaredConstructor.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println("该构造器的形参类型=" + parameterType); } } } //第一组方法API @Test public void api_01() throws ClassNotFoundException, NoSuchMethodException { //得到Class对象 Class<?> personCls = Class.forName("com.fsl.Cat"); //getName:获取全类名 System.out.println(personCls.getName());//com.hspedu.reflection.Person //getSimpleName:获取简单类名 System.out.println(personCls.getSimpleName());//Person //getFields:获取所有public修饰的属性,包含本类以及父类的 Field[] fields = personCls.getFields(); for (Field field : fields) {//增强for System.out.println("本类以及父类的属性=" + field.getName()); } //getDeclaredFields:获取本类中所有属性 Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有属性=" + declaredField.getName()); } //getMethods:获取所有public修饰的方法,包含本类以及父类的 Method[] methods = personCls.getMethods(); for (Method method : methods) { System.out.println("本类以及父类的方法=" + method.getName()); } //getDeclaredMethods:获取本类中所有方法 Method[] declaredMethods = personCls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中所有方法=" + declaredMethod.getName()); } //getConstructors: 获取所有public修饰的构造器,包含本类 Constructor<?>[] constructors = personCls.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("本类的构造器=" + constructor.getName()); } //getDeclaredConstructors:获取本类中所有构造器 Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名 } //getPackage:以Package形式返回 包信息 System.out.println(personCls.getPackage());//com.hspedu.reflection //getSuperClass:以Class形式返回父类信息 Class<?> superclass = personCls.getSuperclass(); System.out.println("父类的class对象=" + superclass);// //getInterfaces:以Class[]形式返回接口信息 Class<?>[] interfaces = personCls.getInterfaces(); for (Class<?> anInterface : interfaces) { System.out.println("接口信息=" + anInterface); } //getAnnotations:以Annotation[] 形式返回注解信息 Annotation[] annotations = personCls.getAnnotations(); for (Annotation annotation : annotations) { System.out.println("注解信息=" + annotation);//注解 } } }
标签:Java,复习,17,System,class,public,println,Class,out From: https://blog.csdn.net/weixin_60566743/article/details/144153608