JAVA-反射

JAVA-反射(reflection)

01. 一个需求引出反射

1. 问题

  1. 根据配置文件 re.properties 指定信息,创建Cat对象并调用方法hi
    re.properties:
calssfullpath=com.yzjedu.Cat
method=hi
  1. 使用现有的技术,可以做到吗?
    cat类:
package com.yzjedu;public class Cat {private String name = "招财猫";public void hi() {System.out.println("你好,招财猫");}}

传统方法测试类

package com.yzjedu.reflection.question;import com.yzjedu.Cat;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;@SuppressWarnings("all")
public class ReflectionQuestion {public static void main(String[] args) throws IOException {//1. 根据配置文件 re.properties 指定信息,创建Cat对象并调用方法hi//1.1 传统方法 new 对象 —》调用方法
//        Cat cat = new Cat();
//        cat.hi();//2. 使用Properties类,可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();String method = (String) properties.get("method").toString();System.out.println("classfullpath= " + classfullpath);System.out.println("method= " + method);//3. 创建对象,传统方法已经不能够做到了}
}

由此可见我们传统的方式已经不能够完成要求由此引出反射

02. 反射快速入门

1. 我们是用反射来解决上面的问题

反射解决:

package com.yzjedu.reflection.question;import com.yzjedu.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 {//1. 根据配置文件 re.properties 指定信息,创建Cat对象并调用方法hi//1.1 传统方法 new 对象 —》调用方法
//        Cat cat = new Cat();
//        cat.hi();//2. 使用Properties类,可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();String methodName = (String) properties.get("method").toString();System.out.println("classfullpath= " + classfullpath);System.out.println("method= " + methodName);//3. 创建对象,传统方法已经不能够做到了//new classfullpath();//4. 使用反射机制解决//4.1 加载类, 返回Class类型的对象clsClass cls = Class.forName(classfullpath);//4.2 通过cls得到你加载的类 com.yzjedu.Cat 的对象实例Object o = cls.newInstance();System.out.println("o的运行类型=" + o.getClass());//4.3 通过cls得到 加载的类 com.yzjedu.Cat 的方法对象//即在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);//4.4 即通过method1 调用方法:即通过方法对象来实现调用方法method1.invoke(o);//传统方法 对象.方法(), 反射机制 方法.invoke(对象)}
}
  1. 这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码情况下,来控制程序,也符合设计模式的 ocp原则(开闭原则:不修改源码,扩容功能)

03. 反射机制

1. Java Reflection

  1. 反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
  2. 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射

2. Java反射机制原理示意图

在这里插入图片描述

3. Java反射机制可以完成

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时得到任意一个类所具有成员变量和方法
  4. 在运行时调用任意一个对象的成员变量和方法
  5. 生成动态代理

4. 反射相关的主要类

  1. Java.lang.Class: 代表一个类,Class对象表示某个类加载后在堆中的对象
  2. java.lang.reflection.Method: 代表类的方法,Method对象表示某个类的方法
  3. java.lang.reflect.Field: 代表类的成员变量,Field对象表示某个类的成员变量
  4. java.lang.reflect.Constructor: 代表类的构造方法,Constructor对象表示构造器
    这些类在java.lang.reflection中
1. 演示案例

Cat类:

package com.yzjedu;public class Cat {private String name = "招财猫";public int age = 2;public Cat(String name) {this.name = name;}public Cat() {}public void hi() {System.out.println("你好,招财猫");}}

反射

import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;@SuppressWarnings("all")
public class Reflection01 {public static void main(String[] args) throws Exception{//使用Properties类,可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();String methodName = (String) properties.get("method").toString();System.out.println("classfullpath= " + classfullpath);System.out.println("method= " + methodName);//使用反射机制解决// 加载类, 返回Class类型的对象clsClass cls = Class.forName(classfullpath);// 通过cls得到你加载的类 com.yzjedu.Cat 的对象实例Object o = cls.newInstance();System.out.println("o的运行类型=" + o.getClass());// 通过cls得到 加载的类 com.yzjedu.Cat 的方法对象//即在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);// 即通过method1 调用方法:即通过方法对象来实现调用方法method1.invoke(o);//传统方法 对象.方法(), 反射机制 方法.invoke(对象)System.out.println("==============分割============");//1. java.lang.reflect.Field: 代表类的成员变量,Field对象表示某个类的成员变量//1.1 得到name字段//1.2 getField 不能得到私有的属性Field nameFiled = cls.getField("age");System.out.println(nameFiled.get(o));//反射:成员变量.get(对象)//2. java.lang.reflect.Constructor: 代表类的构造方法,Constructor对象表示构造器Constructor constructor = cls.getConstructor();//()中可以指定构造器的参数类型,没有填写返回无参构造器System.out.println(constructor);//2.2这里传入String.class 就是带有String.class 就是 String 类的 Class 对象Constructor constructor2 = cls.getConstructor(String.class);System.out.println(constructor2);}
}

5. 反射的优点和缺点

  1. 优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
  2. 缺点:使用反射基本是解释执行,对执行速度有影响.
1. 应用案例
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class Reflection02 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {m1();//注意:运行时先将Cat hi()中的输出语句去除m2();}//1. 传统方法来调用hi()public static void m1() {Cat cat = new Cat();long start = System.currentTimeMillis();for (int i = 0; i < 90000000; i++) {cat.hi();}long end = System.currentTimeMillis();System.out.println("m1()耗时 = " + (end - start));}//2. 反射调用机制调用方法hi()public static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class aClass = Class.forName("com.yzjedu.Cat");Object o = aClass.newInstance();Method hi = aClass.getMethod("hi");long start = System.currentTimeMillis();for (int i = 0; i < 90000000; i++) {hi.invoke(o);}long end = System.currentTimeMillis();System.out.println("m2()耗时 = " + (end - start));}
}

6. 反射调用优化-关闭访问检查

  1. Method和Field、Constructor对象都有setAccessible(Q方法
  2. setAccessible作用是启动和禁用访问安全检查的开关
  3. 参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查
//3. 反射调用优化-关闭访问检查public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class aClass = Class.forName("com.yzjedu.Cat");Object o = aClass.newInstance();Method hi = aClass.getMethod("hi");hi.setAccessible(true);//3.1 在反射调用方法时,取消访问检查long start = System.currentTimeMillis();for (int i = 0; i < 90000000; i++) {hi.invoke(o);}long end = System.currentTimeMillis();System.out.println("m3()耗时 = " + (end - start));}

04. Class类

1. 基本介绍

在这里插入图片描述

  1. Class也是类,因此继承Object类
  2. Class类对象不是new出来的,而是系统创建的
  3. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
  4. 每个类的实例都会记得自己是由哪个Class实例所成
  5. 通过Class对象可以完整地得到一个类的完整结构,通过一系列API
  6. Class对象是存放在堆里的
  7. 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,访问权限等等)

2. 常用方法

方法名功能说明
static Class forName(String name)返回指定类名 name 的 Class对象
Object newInstance()调用缺省构造函数,返回该Class对象的一个实例
getName()返回此Class对象所表示的实体(类、接口、数组类、基本类型等)名称
Class [] getInterfaces()获取当前Class对象的接口
ClassLoder getClassLoder()返回该类的类加载器
Class getSuperclass()返回表示此Class所表示的实体的超类Class
Construtor[] getConstructors()返回一个包含某些Constructor对象的数组
Field[] getDeclareFields()返回Field对象的一个数组
Method getMethod返回一个Method对象,此对象的形参类型是paramType

应用案例

import com.yzjedu.Car;
import java.lang.reflect.Field;/*** 06. 演示Class类的常用方法*/
public class Class02 {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {String classAllPath = "com.yzjedu.Car";//设置自己的路径包名//1. 获取Car类对应的 Class对象//<?> 表示不确定的Java类型Class<?> cls = Class.forName(classAllPath);//1.1 输出clsSystem.out.println(cls);//显示cls对象,是哪个类的Class对象System.out.println(cls.getClass());//显示cls的运行类型//2. 得到包名System.out.println(cls.getPackage().getName());//3. 得到全类名System.out.println(cls.getName());//4. 通过cls创建对象实例Car car = (Car)cls.newInstance();System.out.println(car);//5. 通过反射获取属性 brand(不能用于private属性,后面会有解决方式)Field brand = cls.getField("brand");System.out.println(brand.get(car));//6. 通过反射给属性赋值brand.set(car, "Benz");System.out.println(brand.get(car));//7. 遍历得到所有的属性(字段)System.out.println("========所有的字段===========");Field[] fields = cls.getFields();for (Field f : fields) {System.out.println(f.getName());//名称}}
}

3. 获取 Class 类对象

  1. 前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException, 实例: Class cls1 =Class.forName( “java.lang.Cat” );
    **应用场景: **多用于配置文件,读取类全路径,加载类.
  2. 前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高实例: Class cls2 = Cat.class;
    应用场景: 多用于参数传递,比如通过反射得到对应构造器对象.
  3. 前提:已知某个类的实例,调用该实例的getClass(方法获取Class对象,实例: Class clazz =对象.getClass();//运行类型
    应用场景:通过创建好的对象,获取Class对象.
  4. 其他方式
    ClassLoader cl =对象.getClass().getClassLoader();
    Class clazz4 = cl.loadClass( "类的全类名”);
  5. 基本数据(int, char,boolean,float,double,byte,long,short)按如下方式得到Class类对象
Class cls = 基本数据类型.class
  1. 基本数据类型对应的包装类,可以通过.TYPE得到Class类对象
Class cls = 包装类.TYPE

4. 应用案例

import com.yzjedu.Car;public class GetClass_ {public static void main(String[] args) throws ClassNotFoundException {//1. Class.forName()String classAllPath = "com.yzjedu.Car";Class<?> aClass = Class.forName(classAllPath);System.out.println(aClass);//2. 类名.class,应用场景:多用于参数传递Class<Car> carClass = Car.class;System.out.println(carClass);//3. 通过对象.getClass(), 应用场景,有应用实例Car car = new Car();Class<? extends Car> aClass1 = car.getClass();System.out.println(aClass1);//4. 通过类加载器来获取到类的Class对象//4.1 先得到类加载器 carClassLoader classLoader = car.getClass().getClassLoader();//4.2 通过类加载器得到Class对象Class<?> aClass2 = classLoader.loadClass(classAllPath);System.out.println(aClass2);// aClass , carClass, aClass1, aClass2 其实是同一个对象System.out.println(aClass.hashCode());System.out.println(carClass.hashCode());System.out.println(aClass1.hashCode());System.out.println(aClass2.hashCode());//5.基本数据(int, char,boolean,float,double,byte,long,short)按如下方式得到Class类对象Class<Integer> integerClass = int.class;Class<Boolean> booleanClass = boolean.class;System.out.println(integerClass);//int//6. 基本数据类型对应的包装类,可以通过.TYPE得到Class类对象Class<Integer> type = Integer.TYPE;Class<Character> type1 = Character.TYPE;System.out.println(type);System.out.println(integerClass.hashCode());System.out.println(type.hashCode());}
}

05. 哪些类型有 Class 对象

1. 如下类型有 Class 对象

  1. 外部类、成员内部类、静态内部类、局部内部类、匿名内部类
  2. Interface:接口
  3. 数组
  4. Enum:枚举
  5. annotation:注解2
  6. 基本数据类型
  7. void

2. 应用实例

import java.io.Serializable;public class AllTypeClass {public static void main(String[] args) {Class<String> stringClass = String.class;Class<Serializable> serializableClass = Serializable.class;Class<Integer[]> aClass = Integer[].class;Class<float[][]> aClass1 = float[][].class;Class<Deprecated> deprecatedClass = Deprecated.class;Class<Thread.State> stateClass = Thread.State.class;Class<Long> longClass = long.class;Class<Void> voidClass = void.class;Class<Class> classClass = Class.class;System.out.println(stringClass);System.out.println(serializableClass);System.out.println(aClass);System.out.println(aClass1);System.out.println(deprecatedClass);System.out.println(stateClass);System.out.println(longClass);System.out.println(voidClass);System.out.println(classClass);}
}

06. 类加载

1. 基本说明

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。

  1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
  2. 动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性
  3. 举例说明:
    1. 不使用idea,idea检错能力很强
    2. 我们可以使用sublime之类的工具
    3. 体现效果
import java.util.*;
import java.lang.reflect.*;public class ClassLoad_ {public static void main(String[] args) throws Exception{Scanner scanner = new Scanner(System.in);System.out.println("请输入key");String key = scanner.next();switch(key) {// case "1":// 	Dog dog = new Dog();//静态加载// 	dog.cry();// 	break;case "2"://反射 -》 动态加载Class cls = Class.forName("Person");//加载Person类Object o = cls.newInstance();Method m = cls.getMethod("hi");m.invoke(o);System.out.println("ok");break;}}
}
/*
因为 new Dog() 是静态加载,以此必须编写Dog
Person类是动态加载,所以,没有编写Person类也不会报错,只有当动态加载该类的时候,才会报错,也就是你进入程序,在键盘输入2的时候*/
class Dog {public void cry() {System.out.println("小狗汪汪汪");}
}

2. 类加载时机

  1. 当创建对象时(new) //静态加载
  2. 当子类被加载时,父类也加载 //静态加载
  3. 调用类中的静态成员时 //静态加载
  4. 通过反射 //动态加载

3. 类加载过程图(重点)

在这里插入图片描述

4. 类加载各阶段完成任务在这里插入图片描述

1. 加载阶段

​ JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包、甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象

2. 连接阶段-验证
  1. 目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全
  2. 包括:文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
  3. 可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。
3. 连接阶段-准备
  1. JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、OL、 null、 false 等)。这些变量所使用的内存都将在方法区中进行分
  2. 举例说明:
package com.yzjedu.classload_;/*** @author Icaru* @version 1.0* @date 2024/3/13 11:18* 09.说明一个类加载的连接阶段-准备*/
public class ClassLoad02 {public static void main(String[] args) {}
}
class A {//属性-成员变量-字段//分析:连接阶段-准备 属性是如何处理的//1. n1是实例属性,不是静态变量,因此在准备阶段,是不会分配内存的//2. n2是静态变量,分配内存 n2 是默认初始化 0,而不是20//3. n3是static final 是常量,它和静态变量不一样,因为一旦赋值就不变public int n1 = 10;public static int n2 = 20;public static final int n3 = 30;
}
4. 连接阶段-解析
  1. 虚拟机将常量池内的符号引用替换为直接引用的过程。
  2. 在Java类加载的连接阶段中的解析阶段,主要任务是将类、字段、方法等符号引用解析为直接引用,以便在程序运行时能够准确地定位和访问相应的类、字段和方法。
5. Initialization(初始化)
  1. 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行
    <clinit>() 方法的过程。
  2. <clinit> ()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
  3. 虚拟机会保证一个类的<clinit> )方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化-个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit> ()方法完毕
package com.yzjedu.classload_;public class ClassLoad03 {public static void main(String[] args) {//1. 分析//1.1 加载B类,并生成B的class对象//1.2 链接 - num = 0//1.3 初始化阶段/*依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并合并static {System.out.println("B的静态代码块被执行");num = 300;num = 100;}合并num = 100;*///1.4new B();System.out.println(B.num);//100,如果直接使用类的静态属性,也会导致类的加载//看看加载类的时候,是有同步机制控制/*protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {//正因为有这个机制,才能保证某个类在内存中, 只有一份 Class 对象synchronized (getClassLoadingLock(name)) {//....}}*/}
}class B {static {System.out.println("B的静态代码块被执行");num = 300;}static int num = 100;public B() {System.out.println("B的构造器被执行");}
}

07. 通过反射获取类的结构信息

1. 第一组:java.lang.Class类(常用)

  1. getName: 获取全类名
  2. getSimpleName: 获取简单类名
  3. getFields: 获取所有的public修饰的属性,包含本类和父类的
  4. getDeclaredFields: 获取本类中所有的属性
  5. getMethods: 获取所有public修饰的方法,包含本类以及父类的
  6. getDeclaredMethods: 获取本类中所有的方法
  7. getConstructors: 获取本类中所有public修饰构造器
  8. getDeclaredConnstructors: 获取本类中所有的构造器
  9. getPackage: 以package形势返回 包信息
  10. getSuperClass: 以Class的形式返回父类信息
  11. getInterfaces:以Class[]形式返回接口信息
  12. getAnnotations: 以Annotation[]形式返回注解信息

2. 第二组:: java.lang.reflect.Field 类

  1. getModifiers:以int形式返回修饰符
    [说明:默认修饰符是0 , public 是1,private是2 , protected是4, static是8 , final 是16], public(1) + static (8) = 9
  2. getType:以Class形式返回类型
  3. getName:返回属性名

3. 第三组: java.lang.reflect.Method 类

  1. getModifiers:以int形式返回修饰符
    [说明:默认修饰符是0,public 是1 , private 是2,protected 是4, static是8 , final 是16]
  2. getReturnType:以Class形式获取返回类型
  3. getName:返回方法名
  4. getParameter Types:以Class[]返回参数类型数组

4. 第四组: java.lang.reflect.Constructor 类

  1. getModifiers:以int形式返回修饰符
  2. getName:返回构造器名(全类名)
  3. getParameter Types:以Class[]返回参数类型数组

5. 综合实例

import org.junit.Test;import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class ReflectionUtils {public static void main(String[] args) {}//第一组方法API@Testpublic void api_01() throws ClassNotFoundException {//得到Class对象Class<?> personCls = Class.forName("com.yzjedu.classload_.Person");//1. getName: 获取全类名System.out.println(personCls.getName());//2. getSimpleName: 获取简单类名System.out.println(personCls.getSimpleName());//3. getFields: 获取所有的public修饰的属性,包含本类和父类的Field[] fields = personCls.getFields();for (Field field : fields) {System.out.println("本类以及父类的属性= " + field.getName());}//4. getDeclaredFields: 获取本类中所有的属性Field[] declaredFields = personCls.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println("本类中所有的属性= " + declaredField.getName());}//5. getMethods: 获取所有public修饰的方法,包含本类以及父类的Method[] methods = personCls.getMethods();for (Method method : methods) {System.out.println("获取所有public修饰的方法,包含本类以及父类的" + method.getName());}//6. getDeclaredMethods: 获取本类中所有的方法Method[] declaredMethods = personCls.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println("获取本类中所有的方法" + declaredMethod.getName());}//7. getConstructors: 获取本类中所有public修饰构造器Constructor<?>[] constructors = personCls.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println("获取本类中所有public修饰构造器" + constructor.getName());}//8. getDeclaredConstructors: 获取本类中所有的构造器Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println("获取本类中所有的构造器" + declaredConstructor.getName());}//9. getPackage: 以package形势返回 包信息System.out.println(personCls.getPackage());//10. getSuperClass: 以Class的形式返回父类信息Class<?> superclass = personCls.getSuperclass();System.out.println(superclass);//11. getInterfaces:以Class[]形式返回接口信息Class<?>[] interfaces = personCls.getInterfaces();for (Class<?> anInterface : interfaces) {System.out.println(anInterface.getName());}//12. getAnnotations: 以Annotation[]形式返回注解信息Annotation[] annotations = personCls.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation);}}//第二组方法API@Testpublic void api_02() throws ClassNotFoundException {//得到Class对象Class<?> personCls = Class.forName("com.yzjedu.classload_.Person");//getDeclaredFields: 获取本类中所有的属性
//       1. getModifiers:以int形式返回修饰符
//      [说明:默认修饰符是0 , public 是1,private是2 , protected是4, static是8 ,
//      final 是16, public(1) + static (8) = 9
//       2. getType:以Class形式返回类型
//       3. getName:返回属性名Field[] declaredFields = personCls.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println("本类中所有的属性= " + declaredField.getName()+ "该属性的修饰符=" + declaredField.getModifiers()+ "该属性的类型=" + declaredField.getType());}}@Test//第三组方法APIpublic void api_03() throws ClassNotFoundException {//得到Class对象Class<?> personCls = Class.forName("com.yzjedu.classload_.Person");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("输出呢?");System.out.println("该方法的行参类型=" +parameterType);}}}@Test//第四组方法APIpublic void api_04() throws ClassNotFoundException {//得到Class对象Class<?> personCls = Class.forName("com.yzjedu.classload_.Person");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);}}}
}interface IA {
}interface IB {
}class AA {public String hobby;public void hi() {}public AA() {}public AA(String name) {}
}@Deprecated
class Person extends AA implements IA, IB {//属性public String name;protected static int age;//4 + 8 = 12String job;private double sal;//方法public void m1(String m1Name,int m1Age ,double m1Src ) {}protected String m2() {return null;}void m3() {}private void m4() {}public Person(String name) {this.name = name;}protected Person(String name, int age) {this.name = name;this.age = age;}Person(String name, int age, String job) {this.name = name;this.age = age;this.job = job;}private Person(String name, int age, String job, double sal) {this.name = name;this.age = age;this.job = job;this.sal = sal;}
}

08. 通过反射创建对象

  1. 方式-:调用类中的public修饰的无参构造器
  2. 方式二:调用类中的指定构造器
  3. Class类相关方法
    1. newInstance :调用类中的无参构造器,获取对应类的对象
    2. getConstructor(as…clazz):根据参数列表,获取对应的public构造器对象
    3. getDecalaredConstructor(as…clazz):根据参数列表,获取对应的所有构造器对象
  4. Constructor类相关方法
    1. setAccessible:暴破
    2. newInstance(Objc…obj):调用构造器

1. 案例演示

  1. 测试1:通过反射创建某类的对象,要求该类中必须有无参构造
  2. 测试2:通过调用某个特定的构造器方式,实现创建某类的对象
package com.yzjedu.reflection;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;/*** @author Icaru* @version 1.0* @date 2024/3/13 19:37* 12. 通过反射机制创建实例*/
public class ReflectCreateInstance {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {//1. 先获取到User类的Class对象Class<?> userClass = Class.forName("com.yzjedu.reflection.User");//2. 通过public的无参构造器创建实例Object o = userClass.newInstance();System.out.println(o);//3. 通过public的有参构造器创建实例//3.1 constructor 对象就是/*public User(String name) {this.name = name;}*///3.2 先得到对应的构造器Constructor<?> constructor = userClass.getConstructor(String.class);//3.3 然后创建实例Object yzj = constructor.newInstance("yzj");System.out.println(yzj);//4. 通过非public的有参构造器创建实例//4.1 先得到private构造器对象Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class);//4.2constructor1.setAccessible(true);//爆破(暴力破解),使用反射可以访问 private 构造器/方法/属性Object user2 = constructor1.newInstance(18, "karto");System.out.println(user2);}
}
class User {private int age = 10;private String name = "kra";public User() {}public User(String name) {this.name = name;}private User(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "User{" +"age=" + age +", name='" + name + '\'' +'}';}
}

09. 通过反射访问类中的成员

1. 访问属性

  1. 根据属性名获取Field对象
    Filed f = class对象.getDeclaredField(属性名);
  2. 爆破:f.setAccessible(true);//f 是Field
  3. 访问
    f.set(o, 值);//o表示对象(设置)
    syso(f.get(o))//o表示对象(获取)
  4. 注意:如果是静态属性, 则set和get中的参数o,可以写成null
import java.lang.reflect.Field;public class ReflectAccessProperty {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {//1. 得到Student类的Class对象Class<?> stuClass = Class.forName("com.yzjedu.reflection.Student");//2. 创建对象Object o = stuClass.newInstance();// o的运行类型是StudentSystem.out.println(o.getClass());//3. 使用反射得到age属性对象Field age = stuClass.getField("age");age.set(o,88);//通过反射来操作属性System.out.println(o);System.out.println(age.get(o));//返回age属性的值//4. 使用反射操作name属性Field name = stuClass.getDeclaredField("name");name.setAccessible(true);name.set(o,"Ricardo");//因为name是static属性,因此o也可以写成nullSystem.out.println(o);System.out.println(name.get(o));//获取属性值System.out.println(name.get(null));}
}
class Student {public int age;private static String name;public Student() {}@Overridepublic String toString() {return "Student{" +"age=" + age + " name=" + name +'}';}
}

2. 访问方法

  1. 根据方法名和参数列表获取Method方法对象: Method m =
    clazz.getDeclaredMethod(方法名,xx.class); //得到本类的所有方法
  2. 获取对象: Object o=clazz.newlnstance();
  3. 暴破: m.setAccessible(true);
  4. 访问: Object returnValue = m.invoke(o,实参列表);//o就是对象
  5. 注意:如果是静态方法,则invoke的参数o,可以写成null
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class ReflectAccessMethod {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {//1. 得到Boss类对应的Class对象Class<?> bossClass = Class.forName("com.yzjedu.reflection.Boss");//2. 创建对象Object o = bossClass.newInstance();//3. 调用public的hi方法
//        Method hi = bossClass.getMethod("hi", String.class); ok//3.1 得到hi方法对象Method hi = bossClass.getDeclaredMethod("hi", String.class);hi.invoke(o," kra");//4. 调用private static 方法//4.1 得到 say 方法对象Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class);say.setAccessible(true);System.out.println(say.invoke(o,32, "王二", '男'));//4.3 因为 say 方法是 static 的,还可以这样调用 ,可以传入 nullSystem.out.println(say.invoke(null, 30, "李四", '女'));//5. 在反射中,如果方法有返回值,统一返回 Object , 但是他运行类型和方法定义的返回类型一致Object invoke = say.invoke(null, 15, "王五", '男');System.out.println(invoke);}
}
class Boss {public int age;public static String name;public Boss() {}public static String say(int n, String s, char c) {return  n + " " + s + " " + c;}public void hi(String s) {System.out.println("hi" + s);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/543210.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站安全监测:守护网络空间的坚实防线

随着互联网技术的飞速发展和广泛应用&#xff0c;网站已成为企业、机构和个人展示形象、提供服务、传递信息的重要平台。然而&#xff0c;与此同时&#xff0c;网站也面临着日益严重的安全威胁。黑客攻击、数据泄露、恶意软件等安全问题频发&#xff0c;给网站运营者带来了巨大…

GUROBI建模之非线性约束的处理

官方文档 目录 官方文档&#xff1a;GRBModel.AddGenConstrXxx() - Gurobi Optimization 数学规划的约束类型 基本约束(fundamental constraints)&#xff1a; 通用约束(general constraints): 1. GUROBI求解器有针对这类约束的函数&#xff0c;直接调用这类函数即可 2.…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:RichText)

富文本组件&#xff0c;解析并显示HTML格式文本。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。该组件无法根据内容自适应设置宽高属性&#xff0c;需要开发者设置显示布局。 子组件 不包含子组…

flask库

文章目录 flask库1. 基本使用2. 路由路径和路由参数3. 请求跳转和请求参数4. 模板渲染1. 模板变量2. 过滤器3. 测试器 5. 钩子函数与响应对象 flask库 flask是python编写的轻量级框架&#xff0c;提供Werkzeug&#xff08;WSGI工具集&#xff09;和jinjia2&#xff08;渲染模板…

JMH287亲测【鸣潮】一键内测风景端V1.0.2已整理并录制视频教学

资源介绍&#xff1a; 否需要虚拟机&#xff1a;否 文件大小&#xff1a;压缩包约15G 支持系统&#xff1a;win7、win10、win11 硬件需求&#xff1a;运行内存16G 4核及以上CPU独立显卡 资源截图&#xff1a; 下载地址&#xff1a; JMH287【鸣潮】一键端 [V1.0.2]

MySql入门教程--MySQL数据库基础操作

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

精读《精通 console.log》

1 引言 本周精读的文章是 Mastering JS console.log like a Pro&#xff0c;一起来更全面的认识 console 吧&#xff01; 2 概述 & 精读 console 的功能主要在于控制台打印&#xff0c;它可以打印任何字符、对象、甚至 DOM 元素和系统信息&#xff0c;下面一一介绍。 c…

Linux 中搭建 主从dns域名解析服务器

CSDN 成就一亿技术人&#xff01; 作者主页&#xff1a;点击&#xff01; Linux专栏&#xff1a;点击&#xff01; CSDN 成就一亿技术人&#xff01; ————前言———— 主从&#xff08;Master-Slave&#xff09;DNS架构是一种用于提高DNS系统可靠性和性能的配置方式。…

以题为例浅谈文件包含

什么叫做文件包含 文件包含函数加载的参数没有经过过滤或严格定义&#xff0c;可以被用户控制&#xff0c; 包含其他恶意文件&#xff0c;导致了执行非预期代码。 文件包含漏洞&#xff08;File Inclusion Vulnerability&#xff09;是一种常见的网络安全漏洞&#xff0c;它允…

相机拍照与摄影学基础

1.相机拍照 相机可能形状和大小不同&#xff0c;但基本功能相同&#xff0c;包括快门速度、光圈和感光度&#xff0c;这些是摄影的通用概念。即使是一次性相机也是基于这三个理念工作的。不同类型相机在这三个概念上的唯一区别是你可以控制这些功能的程度。这三个参数被称为相…

动态库和静态库的新理解

旧理解(当初理解较浅&#xff0c;今再看到有新发现) 链接&#xff1a; 静态链接库和动态链接库区别_动态链接库和静态链接库的区别-CSDN博客 由于本人不是做架构方面&#xff0c;给大佬打螺丝。长时间的惯性思维就是要使用其他项目的类或者函数&#xff0c;先导出成dll。然后…

计算机设计大赛 题目:基于大数据的用户画像分析系统 数据分析 开题

文章目录 1 前言2 用户画像分析概述2.1 用户画像构建的相关技术2.2 标签体系2.3 标签优先级 3 实站 - 百货商场用户画像描述与价值分析3.1 数据格式3.2 数据预处理3.3 会员年龄构成3.4 订单占比 消费画像3.5 季度偏好画像3.6 会员用户画像与特征3.6.1 构建会员用户业务特征标签…