Java反射(reflection)java很多框架的底层都需要用到反射,至于API使用的话,还算简单,主要是类加载过程和反射机制的一个底层机制要了解一下

news2024/11/17 21:50:24

十六、反射(reflection)

反射可以通过外部文件配置,在不修改源码的情况下来控制程序,符合设计模式中的OCP原则(开闭原则:不修改源码,扩容功能)。

1、反射机制

(1)基本介绍
  • 反射机制允许程序在执行期间借助Reflection API 获取任何类的内部信息(比如:成员变量,构造器,成员方法等)。并能操作对象的属性方法。在设计模式和框架地层都会涉及
  • 加载完类之后,在堆中产生一个Class对象(一个类只有一个Class对象),对象包含类的完整结构信息。通过这个对象可以看到类的结构。Class对象就像一面镜子,通过镜子看到类的结构。
(2) 反射机制原理图

在这里插入图片描述

(3)反射可完成功能
  • 运行时判断对象所属类
  • 运行时构造一个任意类的对象
  • 运行时得到一个类所具有的成员变量和方法
  • 运行时调用任意一个对象的成员变量和方法
  • 生产动态代理
(4) 反射相关类
1.java.lang.Class 代表一个类,Class对象表示某个类加载后在堆中的对象
2.java.lang.reflect.Method 代表类的方法,Method对象表示某个类的方法
3.java.lang.reflect.Field 代表类的成员变量,Filed对象表示某个类的成员变量
4.java.lang.reflect.Constructor 代表类的构造方法,Constructor对象表示构造器

举例:

public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
    //1、使用Properties类读取配置信息
    Properties prop = new Properties();
    prop.load(new FileInputStream("src\\re.properties"));
    String classfullpath = prop.getProperty("classfullpath");
    String methodName = prop.getProperty("method");


    //2、使用反射机制
    //(1)加载类,返回class类型的对象cls
    Class cls = Class.forName(classfullpath);
    //(2)通过getInstance得到加载类的实例对象
    Object o = cls.newInstance();
    //(3)通过cls获得得到类的方法对象
    Method method1 = cls.getMethod(methodName);
    System.out.println("=====================");
    //(4)调用方法 传统方法为对象.方法(), 反射机制 方法.invoke(对象)
    method1.invoke(o);


    //java.lang.reflect.Field 代表类的成员变量,Field对象表示某个类的成员变量
    Field nameField = cls.getField("age");      //不能获取到私有的变量
    System.out.println(nameField.get(o));   //传统写法对象.成员变量, 反射: 成员变量对象.get(对象)

    //java.lang.constructor 代表类的构造方法,Constructor对象表示构造器
    Constructor constructor = cls.getConstructor();
    System.out.println(constructor);

    Constructor constructor2 = cls.getConstructor(String.class);
    System.out.println(constructor2);
}
(5)反射的优缺点
  • 优点:可以动态的创建和使用对象(框架底层核心),使用灵活,没有反射机制,框架技术就失去了底层支撑
  • 缺点:使用反射基本是解释执行,对执行速度有影响
  • 改进:关闭访问检查

举例:

public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
    m1();       //传统方法
    m2();       //反射方法
    m3();       //反射优化

}
//传统方法调用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("传统方法调用hi耗时:"+(end-start));
}
//反射机制调用方法hi
public static void m2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
    Class cls = Class.forName("JavaEE.chapter17.Cat");
    Object o = cls.newInstance();
    Method hi = cls.getMethod("hi");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 90000000; i++) {
        hi.invoke(o);
    }
    long end = System.currentTimeMillis();
    System.out.println("反射机制耗时:"+(end-start));
}

//反射机制优化
public static void m3() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
    Class cls = Class.forName("JavaEE.chapter17.Cat");
    Object o = cls.newInstance();
    Method hi = cls.getMethod("hi");
    hi.setAccessible(true);//在反射调用方法时,取消访问检查
    long start = System.currentTimeMillis();
    for (int i = 0; i < 90000000; i++) {
        hi.invoke(o);
    }
    long end = System.currentTimeMillis();
    System.out.println("反射优化机制耗时:"+(end-start));
}

2、class类

(1)基本介绍
  • class类也是类,因此继承了Object类
  • Class类对象不是new出来的,而是系统创建出来的
  • 对于某个类的class类对象,在内存中只有一份,因为类只加载一次
  • 每个类的实例都会记住自己是由哪个Class实例所生成的
  • 通过Class对象可以完整的得到一个类的完整结构
  • class对象存在堆当中
  • 类的字节码二进制数据,放在方法区当中,也称为类的元数据

举例:

public static void main(String[] args) throws ClassNotFoundException {
        //1、class也是类,继承了Object类
        //Class
        //2、Class对象不是new出来的,而是系统创建的
        //(1)传统new对象
        /*
         ClassLoader 类
         public Class<?> loadClass(String name) throws ClassNotFoundException {
            return loadClass(name, false);
        }*/
//        Cat cat = new Cat();
        //(2)反射方式
       /*
       ClassLoader 类, 仍然是通过ClassLoader 类加载Cat 类的Class 对象
            public Class<?> loadClass(String name) throws ClassNotFoundException {
            return loadClass(name, false);
        }*/
        //3、对于某个类的class对象,在内存中只有一份,类只加载一次
        Class cls1 = Class.forName("JavaEE.chapter17.Cat");
        Class cls2 = Class.forName("JavaEE.chapter17.Cat");
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());
    }
(2)获取Class类对象的方式
  1. Class.forName()获取

    • 前提:已知一个类的全类名,并且该类在类路径下,可以通过Class的静态方法forName获取,

    • 应用场景:多用于配置文件,读取类的全路径,加载类

    • 举例:

      //1、加载类的情况下,使用getclass,多用于配置文件的时候
      String classAllPath = "JavaEE.chapter17.Cat";       //通过读取文件配置获取
      Class<?> cls1 = Class.forName(classAllPath);
      System.out.println(cls1);
      
  2. 类.Class()获取

    • 前提:已经知道具体的类,通过类的Class进行获取,该方式最为安全可靠,程序性能最高

    • 应用场景:多用于参数的传递,比如通过反射获取到对应的构造器对象

    • 举例:

      //2、类名.Class,加载类的情况下,用于参数传递
      Class<?> cls2 = Cat.class;
      System.out.println(cls2);
      
  3. 对象.getClass()获取

    • 前提:已经知道具体的对象实例

    • 应用场景:有对象实例

    • 举例:

       //3、对象.getClass,运行的情况下,已经有对象实例,通过创建好的对象,获取Class对象
      Cat cat = new Cat();
      Class cls3 = cat.getClass();
      System.out.println(cls3);
      
  4. 类加载ClassLoader的loadClass进行获取

    • 举例:

      //4、通过类加载器【4种】获取类的Class对象
      //(1)先得到类加载器
      ClassLoader classLoader = cat.getClass().getClassLoader();
      //(2)通过类加载器获取到Class对象
      Class cls4 = classLoader.loadClass(classAllPath);
      System.out.println(cls4);
      
  5. 基本数据类型.class进行获取

    • 举例:

      //5、基本数据类型(int,char,boolean,float,double,byte,long,short),可以通过.class方式获取到class类对象
      Class<Integer> intClass = int.class;
      Class<Character> charClass = char.class;
      System.out.println(intClass);
      System.out.println(charClass);
      
  6. 基本数据类型的包装类.TYPE进行获取

    • 举例:

      //6、基本数据类型的包装类,可以通过.TYPE得到Class对象
      Class cls5 = Integer.TYPE;
      System.out.println(cls5);	 
      
(3)哪些类型有Class对象
  1. 外部类、成员内部类、静态内部类、局部内部类、匿名内部类
  2. interface:接口
  3. 数组
  4. enum:枚举
  5. annotation:注解
  6. 基本数据类型
  7. void

举例:

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;//class自己

3、类加载

(1)基本介绍

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

  1. 静态加载:**编译的时候加载相关的类,如果没有该类就会报错。**依赖性太强
  2. 动态加载:**运行的时候加载相关的类,如果运行的时候没有使用到这个类,即便不存在这个类,也不会报错。**降低了依赖性
(2)类加载的时机
  1. 当创建对象时(new),进行静态加载
  2. 当子类被加载时,父类也加载,进行静态加载
  3. 调用类的静态成员时,进行静态加载
  4. 通过反射时,进行动态加载
(3)类加载过程图

在这里插入图片描述

(4)类加载各阶段任务

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 加载阶段:

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

    • 验证 verification

      1. 目的是保证Class文件中的字节流包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
      2. 包括:文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
      3. 可以考虑使用-Xverify:none,参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
    • 准备 preparation

      1. JVM在该阶段为静态变量,分配内存并默认初始化(对应的数据类型的默认初始化值,如0,0L,null,false等)。这些变量使用的内存将在方法区中进行分配

      举例:

      //类加载阶段中连接阶段,属性如何准备
      //1、n1为实例属性,为静态变量,在准备阶段,不会分配内存
      //2、n2为静态变量,分配内存n2是默认初始化为0,而不是20
      //3、n3是static final是常量,与静态变量不一样,一旦赋值不会更改 n3 = 30
      public int n1 = 10;
      public static int n2 = 20;
      public final static int n3 = 30;
      
    • 解析 resolution

      1. 虚拟机将常量池内的符号引用替换为直接引用的过程
  • 初始化阶段: Initialization

    1. 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行()方法的过程
    2. ()方法是由编译器按照在源文件中出现的顺序,依次自动收集类中的所有的静态变量的赋值动作和静态代码块中的语句进行合并的
    3. 虚拟机会保证一个类的()方法在多线程环境中被正确的加锁、同步,如果多个线程同时初始化一个类,那么只有一个线程回去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()完毕。

    举例:

    public class ClassLoad03 {
        public static void main(String[] args) {
            System.out.println(B.num);      //直接使用类的静态属性,也会执行类加载过程
            /*
            * 1、加载B类,并生产B的class对象
            * 2、连接 num = 0
            * 初始化阶段
            * 依次收集类中的所有静态变量的赋值动作和静态代码块中的语句,并对其进行合并
            *
            clinit(){
                System.out.println("B 静态代码块被执行");
                num = 300;      //被后面的语句合并,这里不起作用,最后输出100
                num = 100;
            }
            * */
            new B();//加断点,追溯源码看是否有同步机制
            /*
            * 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 的构造器被执行");
    //    }
    }
    

4、反射获取类的结构信息

(1)java.lang.Class 类
getName:获取全类名
getSimpleNmae:获取简单类名
getFields:获取所有public修饰的属性,包含本类以及父类的
getDeclaredFields:获取本类中的所有属性
getMethods:获取所有public修饰的方法,包含本类以及父类的
getDeclaredMethods:获取本类的所有方法
getConstructors:获取本类所有public修饰的构造器
getDeclaredConstructors:获取本类的所有构造器
getPackage:以Package形式返回包信息
getSuperClass:以Class形式返回父类信息
getInterfaces:以Class[]返回接口信息
getAnnotations:以Annotation[]形式返回注解信息
(2)java.lang.reflect.Field 类
getModifiers:以int形式返回修饰符
【默认修饰符伟0public1private2protected4static8final16】
getType:以Class形式返回类型
getName:返回属性名
(3)java.lang.reflect.Method 类
getModifiers:以int形式返回修饰符
【默认修饰符伟0,public为1,private为2,protected为4,static为8,final为16】
getReturnType:以Class形式获取返回类型
getName:返回方法名
getParameterTypes:以Class[]类型返回参数类型数组
(4)java.lang.reflect.Constructor 类
getModifiers:以int形式返回修饰符
【默认修饰符伟0,public为1,private为2,protected为4,static为8,final为16】
getName:返回构造器名
getParameterTypes:以Class[]类型返回参数类型数组

举例:

public class ReflectionUtils {
    public static void main(String[] args) {

    }

    //第一组API
    @Test
    public void api_01() throws ClassNotFoundException {
        //得到Class对象
        Class<?> personCls = Class.forName("JavaEE.chapter17.Person");
        //getName:获取全类名
        System.out.println(personCls.getName());
        //getSimpleNmae:获取简单类名
        System.out.println(personCls.getSimpleName());
        //getFields:获取所有public修饰的属性,包含本类以及父类的
        Field[] fields = personCls.getFields();
        for (Field field : fields) {
            System.out.println("本类与父类的属性"+field.getName());
        }
        //getDeclaredFields:获取本类中的所有属性
        Field[] declaredields = personCls.getDeclaredFields();
        for (Field field : declaredields) {
            System.out.println("本类的所有属性"+field.getName());
        }
        //getMethods:获取所有public修饰的方法,包含本类以及父类的
        Method[] methods = personCls.getMethods();
        for (Method method : methods) {
            System.out.println("本类与父类的方法"+method.getName());
        }
        //getDeclaredMethods:获取本类的所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println("本类的方法"+method.getName());
        }
        //getConstructors:获取本类所有public修饰的构造器
        Constructor<?>[] constructors = personCls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("本类所有public构造器"+constructor);
        }
        //getDeclaredConstructors:获取本类的所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> constructor : declaredConstructors) {
            System.out.println("本类的所有构造器"+constructor);
        }
        //getPackage:以Package形式返回包信息
        System.out.println(personCls.getPackage());
        //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);
        }
    }

    @Test
    //第二组API
    public void API_02() throws ClassNotFoundException {
        //得到Class对象
        Class<?>personCls = Class.forName("JavaEE.chapter17.Person");
        //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);
            }
        }
    }
}

class A{
    public String hobby;
    public A(){

    }
    public void hi(){

    }
}

interface IA{

}

interface IB{

}

@Deprecated
class Person extends A implements IA,IB{
    //四种不同类型修饰符的属性
    public String name;
    protected int age;
    String job;
    private double sal;
    public Person(){}
    private Person(String name){}
    public Person(String name, int age, String job, double sal) {}
    //四种不同类型修饰符的方法
    public void m1() {

    }

    protected void m2(){

    }

    void m3(){

    }

    private void m4(){

    }

5、反射创建对象

  • 方式一:调用类中的public修饰的无参构造器
  • 方式二:调用类中的指定构造器
  • Class类的相关方法
    • newInstance:调用类中的午餐构造器,获取对应的类的信息
    • getConstructor(class...class):根据参数列表获取对应的public构造器对象
    • getDeclaredConstructor(class....class):根据参数列表,获取对应的所有构造器对象
  • Constructor类的相关方法
    • setAccessible:爆破
    • newInstance(object..obj):调用构造器

举例:

public class ReflectCreateInstance {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1、先得到Class对象
        Class<?> userCls = Class.forName("JavaEE.chapter17.User");
        //2、通过public的无参构造器
        Object o = userCls.getDeclaredConstructor().newInstance();
        System.out.println(o);
        //3、通过public的有参构造器
        //3.1先得到构造器
        Constructor<?> constructor = userCls.getConstructor(String.class);
        //3.2然后用构造器创建实例
        Object user1 = constructor.newInstance("user1");
        System.out.println(user1);
        //4、通过非公有的构造器创建实例
        //4.1先得到构造器
        Constructor<?> constructor2 = userCls.getDeclaredConstructor(int.class,String.class);
        //私有构造器,得先爆破,才能使用,暴破【暴力破解】, 使用反射可以访问private 构造器/方法/属性, 反射面前,都是纸老虎
        constructor2.setAccessible(true);
        //4.3然后用构造器创建实例
        Object user2 = constructor2.newInstance(200,"user2");
        System.out.println(user2);


    }
}

class User { //User 类
    private int age = 10;
    private String name = "名字";
    public User() {//无参public
    }
    public User(String name) {//public 的有参构造器
        this.name = name;
    }
    private User(int age, String name) {//private 有参构造器
        this.age = age;
        this.name = name;
    }
    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
}

6、反射访问类中的成员

(1)访问属性
  1. 根据属性名获取Field对象

    Field f = clazz对象.getDeclaredField(属性名);
    
  2. 爆破

     f.setAccessible(true);
    
  3. 访问

    f.set(o,) //o表示对象
    syso(f.get(o)) //o表示对象
    
  4. 如果是静态属性,则set和get中的参数o,可以写成null

举例:

public class ReflectAccessProprty {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1. 得到Student 类对应的Class 对象
        Class<?> stuClass = Class.forName("JavaEE.chapter17.Student");
        //2. 创建对象
        Object o = stuClass.newInstance();//o 的运行类型就是Student
        System.out.println(o.getClass());//Student
        //3. 使用反射得到age 属性对象
        Field age = stuClass.getField("age");
        age.set(o,88); //反射操作属性
        System.out.println(age.get(o));

        //4. 使用反射操作name 属性
        Field name = stuClass.getDeclaredField("name");
        //对name 进行暴破, 可以操作private 属性
        name.setAccessible(true);
        name.set(o, "小明");
        System.out.println(name.get(o));
        name.set(null,"小红");//因为name 是static 属性,因此o 也可以写出null
        System.out.println(name.get(o));
        System.out.println(name.get(null));//获取属性值, 要求name 是static
    }
}
class Student {//类
    public int age;
    private static String name;
    public Student() {//构造器
    }
    public String toString() {
        return "Student [age=" + age + ", name=" + name + "]";
    }
}
(2)访问方法
  1. 根据方法名和参数列表获取Method方法

    Method m = clazz.getDeclaredMethod(方法名,XX.class)//得到本类的所有方法
    
  2. 获取对象

    Object o = clazz.newInstance();
    
  3. 爆破

     m.setAccessible(true);
    
  4. 访问

    Object returnValue = m.invoke(o,实参列表);
    
  5. 注意:如果是静态放哪发,则invoke的参数o,可以写成null

举例:

public class ReflecAccessMethod {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //1. 得到Boss 类对应的Class 对象
        Class<?> bossCls = Class.forName("JavaEE.chapter17.Boss");
        //2. 创建对象
        Object o = bossCls.newInstance();
        //3. 调用public 的hi 方法
        //Method hi = bossCls.getMethod("hi", String.class);
        //3.1 得到hi 方法对象
        Method hi = bossCls.getDeclaredMethod("hi", String.class);
        //3.2调用方法
        hi.invoke(o,"大怪物");
        //4. 调用private static 方法
        //4.1 得到say 方法对象
        Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
        //4.2 因为say 方法是private, 所以需要暴破,原理和前面讲的构造器和属性一样
        say.setAccessible(true);
        System.out.println(say.invoke(o, 100, "张三", '男'));
        //4.3 因为say 方法是static 的,还可以这样调用,可以传入null
        System.out.println(say.invoke(null, 200, "李四", '女'));

        //5. 在反射中,如果方法有返回值,统一返回Object , 但是他运行类型和方法定义的返回类型一致
        Object reVal = say.invoke(null, 300, "王五", '男');
        System.out.println("reVal 的运行类型=" + reVal.getClass());//String
        System.out.println(reVal);

        //在演示一个返回的案例
        Method m1 = bossCls.getDeclaredMethod("m1");
        Object reVal2 = m1.invoke(o);
        System.out.println("reVal2 的运行类型=" + reVal2.getClass());//Monster
    }
}
class Monster {}
class Boss {//类
    public int age;
    private static String name;
    public Boss() {//构造器
    }
    public Monster m1() {
        return new Monster();
    }
    private static String say(int n, String s, char c) {//静态方法
        return n + " " + s + " " + c;
    }
    public void hi(String s) {//普通public 方法
        System.out.println("hi " + s);
    }
}

, 但是他运行类型和方法定义的返回类型一致
Object reVal = say.invoke(null, 300, “王五”, ‘男’);
System.out.println(“reVal 的运行类型=” + reVal.getClass());//String
System.out.println(reVal);

    //在演示一个返回的案例
    Method m1 = bossCls.getDeclaredMethod("m1");
    Object reVal2 = m1.invoke(o);
    System.out.println("reVal2 的运行类型=" + reVal2.getClass());//Monster
}

}
class Monster {}
class Boss {//类
public int age;
private static String name;
public Boss() {//构造器
}
public Monster m1() {
return new Monster();
}
private static String say(int n, String s, char c) {//静态方法
return n + " " + s + " " + c;
}
public void hi(String s) {//普通public 方法
System.out.println("hi " + s);
}
}


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud系列(7)--Eureka服务端的安装与配置

前言&#xff1a;上一章节我们介绍了Eureka的基础&#xff0c;本章节则介绍Eureka服务端的安装与配置 Eureka架构原理图 1、创建Eureka Server端服务注册中心模块 (1)在父工程下新建模块 (2)选择模块的项目类型为Maven并选择模块要使用的JDK版本 (3)填写子模块的名称&#xf…

【C++】:函数重载,引用,内联函数,auto关键字,基于范围的for循环,nullptr关键字

目录 一&#xff0c;函数重载1.1 函数重载的定义1.1.1.形参的类型不同1.1.2参数的个数不同1.1.3.参数的顺序不同1.1.4.有一个是缺省参数构成重载。但是调用时存在歧义1.1.5.返回值不同&#xff0c;不构成重载。因为返回值可接收&#xff0c;可不接受&#xff0c;调用函数产生歧…

如何设计单元测试用例?

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 最近一些大公司在进行去测试化的操作&#xff0c;这一切的根源大概可以从几年前微软一刀切砍掉所…

【深度学习实战(10)】图像推理之预处理

一、预处理流程 在把一张图像送入模型进行推理时&#xff0c;需要先进行预处理&#xff0c;预处理流程包括&#xff1a; &#xff08;1&#xff09;读取图像 &#xff08;2&#xff09;尺寸调整&#xff0c;letter_box&#xff08;不失真&#xff09; &#xff08;3&#xff0…

MATLAB绘制圆锥曲线:抛物线,双曲线,椭圆

MATLAB绘制圆锥曲线:抛物线,双曲线,椭圆 clc;close all;clear all;warning off;%清除变量x linspace(-10, 10, 1000); % 创建一个x值的向量&#xff0c;范围从-10到10&#xff0c;共1000个点 y x.^2; % 计算每个x值对应的y值% 使用plot函数绘制图形 figure; % 创建一个新的图…

排序 “壹” 之插入排序

目录 ​编辑 一、排序的概念 1、排序&#xff1a; 2、稳定性&#xff1a; 3、内部排序&#xff1a; 4、外部排序&#xff1a; 二、排序的运用 三、插入排序算法实现 3.1 基本思想 3.2 直接插入排序 3.2.1 排序过程&#xff1a; 3.2.2 代码示例&#xff1a; 3.2.3…

使用Spring进行文件的上传和下载

概览 使用Spring进行文件的上传和下载Spring上传文件接口设计dubbo接口设计上传文件流的RPC的接口设计 Spring文件下载接口设计dubbo接口设计下载文件流的RPC的接口设计 spring上传文件大小控制 使用Spring进行文件的上传和下载 本文主要介绍在Spring框架下面调用微服务的dubb…

YOLOv9改进策略 | 添加注意力篇 | 利用ILSVRC冠军得主SENetV1改善网络模型特征提取能力

一、本文介绍 本文给大家带来的改进机制是SENet&#xff08;Squeeze-and-Excitation Networks&#xff09;其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型&#xff0c;而是一个可以和现有的任何一个模型相结合的模块(可以看作是一…

项目实践:贪吃蛇

引言 贪吃蛇作为一项经典的游戏&#xff0c;想必大家应该玩过。贪吃蛇所涉及的知识也不是很难&#xff0c;涉及到一些C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。这里我会介绍贪吃蛇的一些思路。以及源代码也会给大家放到文章末尾。 我们最终的…

【Ne4j图数据库入门笔记1】图形数据建模初识

1.1 图形建模指南 图形数据建模是用户将任意域描述为节点的连接图以及与属性和标签关系的过程。Neo4j 图数据模型旨在以 Cypher 查询的形式回答问题&#xff0c;并通过组织图数据库的数据结构来解决业务和技术问题。 1.1.1 图形数据模型介绍 图形数据模型通常被称为对白板友…

【Gradle如何安装配置及使用的教程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

双链表的实现

我们知道链表其实有很多种&#xff0c;什么带头&#xff0c;什么双向啊&#xff0c;我们今天来介绍双向带头循环链表&#xff0c;了解了这个其他种类的链表就很简单了。冲冲冲&#xff01;&#xff01;&#xff01; 链表的简单分类 链表有很多种&#xff0c;什么带头循环链表&…

tcp-learner 数据包分析 20240420

输入输出&#xff1a; 数据包分析&#xff1a; learner和Adapter建立连接。 Learner让Adapter发送RST Adapter没有从SUT抓到任何回复&#xff0c;于是向learner发送timeout learner给adapter发送reset命令&#xff0c;让SUT重置。 这是第一次初始化&#xff0c;由于Adapter和…

Spring Boot后端与Vue前端融合:构建高效旅游管理系统

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

【简单讲解下npm常用命令】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

【hackmyVM】whitedoor靶机

文章目录 信息收集1.IP地址2.端口探测nmapftp服务 3.访问主页 漏洞利用1.反弹shell2.尝试提权3.base64解密 提权1.切换用户2.john爆破3.切换Gonzalo用户4.vim提权 信息收集 1.IP地址 ┌─[✗]─[userparrot]─[~] └──╼ $fping -ag 192.168.9.0/24 2> /dev/null192.168…

ZYNQ NVME高速存储之EXT4文件系统

前面文章分析了高速存储的各种方案&#xff0c;目前主流的三种存储方案是&#xff0c;pcie switch高速存储方案&#xff0c;zynq高速存储方案&#xff0c;fpga高速存储方案。虽然三种高速存储方案都可以实现高速存储&#xff0c;但是fpga高速存储方案是最烂的&#xff0c;fpga…

Android Studio 新建Android13 代码提示Build Tools revision XX is corrupted无法编译解决

Android Studio 新建Android13 代码提示Build Tools revision XX is corrupted无法编译解决 文章目录 Android Studio 新建Android13 代码提示Build Tools revision XX is corrupted无法编译解决一、前言二、分析解决1、原因分析2、解决方法 三、其他1、Android13 新项目无法编…

什么是时间序列分析

时间序列分析是现代计量经济学的重要内容&#xff0c;广泛应用于经济、商业、社会问题研究中&#xff0c;在指标预测中具有重要地位&#xff0c;是研究统计指标动态特征和周期特征及相关关系的重要方法。 一、基本概念 经济社会现象随着时间的推移留下运行轨迹&#xff0c;按…

随身WiFi真实测评推荐!格行vs新讯随身wifi对比,公认最好的随身WiFi格行随身wifi有什么优势?

在当前移动网络高度发达的时代&#xff0c;随身 WiFi 已成为人们出差、旅行等场景中不可或缺的工具。格行和新讯是目前比较受欢迎的无线随身wifi。本次评测将对比分析这两款产品的区别&#xff0c;做为随身WiFi推荐第一名的格行随身wifi到底有什么优势呢&#xff1f; 品牌对比&…