Java学习笔记 --- 反射

news2024/10/6 18:28:33

一、反射机制

Java Reflection

1、反射机制允许程序在执行期间借助于 ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到

2、加载完类后,在堆中就产生了一个 Class 类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为反射

 

Java反射机制原理示意图

 

Java反射机制可以完成

1、在运行时判断任意一个对象所属的类

2、在运行时构造任意一个类的对象

3、在运行时得到任意一个类所具有的成员变量和方法

4、在运行时调用任意一个对象的成员变量和方法

5、生成动态代理

 

反射相关的主要类

1、java.lang.Class:代表一个类,Class 对象表示某个类加载后在堆中的对象

2、java.lang.reflect.Method:代表类的方法,Method 对象表示某个类的方法

3、java.lang.reflect.Field:代表类的成员变量,Field 对象表示某个类的成员变量

4、java.lang.reflect.Constructor:代表类的构造方法,Constructor 对象表示构造器

package com.javase.reflection.question;

import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 反射问题的引入
 */
public class ReflectionQuestion {
    public static void main(String[] args) throws Exception {
        //根据配置文件 re.properties 指定的信息,创建Cat对象并调用方法hi

        //传统的方式 new 对象 -> 调用方法
        //Cat cat = new Cat();
        //cat.hi();  ---> cat.cry();

        //尝试现有方式做一做 -> 明白反射
        //1. 使用 Properties 类,可以读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();
        String method = properties.get("method").toString();

        //2. 创建对象,传统的方式行不通 -> 反射机制
        //new classfullpath();

        //3. 使用反射机制解决
        //加载类,返回 Class 类型的对象
        Class cls = Class.forName(classfullpath);

        //通过cls 得到加载的类, com.javase.Cat 的对象实例
        Object o = cls.newInstance();
        System.out.println("运行类型:" + o.getClass());//com.javase.Cat

        //通过 cls 得到加载的类,com.javase.Cat 的 method 的 方法的对象
        //即:在反射中,可以把方法视为对象(万物皆为对象)
        Method method1 = cls.getMethod(method);

        //通过 method1 调用方法, 即通过方法对象来实现调用方法
        method1.invoke(o);//传统方法 对象.方法()  反射机制,方法.invoke(对象)

        //java.lang.reflect.Field:代表类的成员变量,Field 对象表示某个类的成员变量
        //得到 name 字段
        //getField 不能得到私有的属性
        Field age = cls.getField("age");
        //反射:成员变量对象.get(对象)
        System.out.println(age.get(o));

        //java.lang.reflect.Constructor:代表类的构造方法,Constructor 对象表示构造器
        Constructor constructor = cls.getConstructor();//() 中可以指定构造器的参数类型,返回的是无参构造器
        System.out.println(constructor);

        //String.Class 就是 String 类的Class对象
        Constructor constructor1 = cls.getConstructor(String.class);
        System.out.println(constructor1);
    }
}

 

反射的优点和缺点

1、优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑

2、缺点:使用反射基本是解释执行,对执行速度有影响

 

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

1、Method 和 Field、Constructor 对象都有 setAccessible() 方法

2、setAccessible() 作用是启动和禁用访问安全检查的开关

3、参数值为 true 表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为 false 则表示反射的对象执行访问检查

package com.javase.reflection;

import com.javase.Cat;

import java.lang.reflect.Method;

/**
 * 测试反射调用的性能,和优化方案
 */
public class Reflection01 {
    public static void main(String[] args) {
        m1();
        m2();
        m3();
    }

    //传统方法调用方法hi
    public static void m1() {
        Cat cat = new Cat();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 999999999; i++) {
            cat.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统方法调用hi 耗时:" + (end - start));
    }

    //反射机制调用方法hi
    public static void m2() {
        try {
            Class aClass = Class.forName("com.javase.Cat");
            Object o = aClass.newInstance();
            Method hi = aClass.getMethod("hi");
            long start = System.currentTimeMillis();
            for (int i = 0; i < 999999999; i++) {
                hi.invoke(o);
            }
            long end = System.currentTimeMillis();
            System.out.println("反射机制调用hi 耗时:" + (end - start));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //反射调用优化 + 关闭访问检查
    public static void m3() {
        try {
            Class aClass = Class.forName("com.javase.Cat");
            Object o = aClass.newInstance();
            Method hi = aClass.getMethod("hi");
            //在反射调用方法时,取消访问检查
            hi.setAccessible(true);
            long start = System.currentTimeMillis();
            for (int i = 0; i < 999999999; i++) {
                hi.invoke(o);
            }
            long end = System.currentTimeMillis();
            System.out.println("反射机制+关闭访问检查调用hi 耗时:" + (end - start));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

 

二、Class类

基本介绍

1、Class 也是类,因此也继承 Object 类(类图)

2、Class 类对象不是 new 出来的,而是系统创建的

3、对应某个类的 Class 类对象,在内存中只有一份,因此类只加载一次

4、每个类的实例都会记得自己是由哪个 Class 实例所生成

5、通过 Class 对象可以完整的得到一个类的完整结构,通过一些列API

6、Class 对象是存放在堆的

7、类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限等)

 

Class类的常用方法

import com.javase.Car;

import java.lang.reflect.Field;

/**
 * 演示 Class 类的常用方法
 */
public class Class02 {
    public static void main(String[] args) throws Exception {
        String classAllpath = "com.javase.Car";
        //获取到Car类对应的 Class 对象
        //<?> 表示不确定的Java类型
        Class<?> cls = Class.forName(classAllpath);

        //输出Class
        System.out.println(cls);//显示cls对象,是哪个类的 Class对象 com.javase.Car
        System.out.println(cls.getClass()); //输出 cls 的运行类型 java.lang.Class

        //得到包名
        System.out.println(cls.getPackage().getName()); //包名 com.javase

        //得到全类名
        System.out.println(cls.getName());

        //通过 cls 创建对象实例
        Car car = (Car)cls.newInstance();
        System.out.println(car);

        //通过反射获取属性,brand
        Field brand = cls.getField("brand");
        System.out.println(brand.get(car));

        //通过反射给属性赋值
        brand.set(car, "宝马");
        System.out.println(brand.get(car));

        //得到所有的属性
        Field[] fields = cls.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
    }
}

 

 

三、获取Class类对象

1、前提:已知一个类的全类名,且该类在类的路径下,可通过 Class 类的静态方法 forName() 获取,可能抛出 ClassNotFoundException

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

2、前提:若已知具体的类,通过类的 class 方式获取,该方式是最为安全可靠,程序性能最高

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

3、前提:已知每个类的实例,调用该实例的 getClass() 方法获取 Class 对象

      应用场景:通过创建好的对象,获取 Class 对象

4、其它方式:

      ClassLoader cl = 对象.getClass().getClassLoader();

      Class clazz4 = cl.loadClass("类的全类名");

5、基本数据类型(int, char, boolean, float, double, byte, long, short)按如下方式得到 Class 类对象

      Class cls = 基本数据类型.class

6、基本数据类型对应的包装类,可以通过 .TYPE 得到 Class 类对象

      Class cls = 包装类.TYPE

import com.javase.Car;

/**
 * 演示得到Class对象的各种方式
 */
public class GetClass {
    public static void main(String[] args) throws Exception {
        //1. Class.forName
        String classAllpath = "com.javase.Car"; //通过读取配置文件获取
        Class<?> cls1 = Class.forName(classAllpath);
        System.out.println(cls1);

        //2. 类名.class 应用场景:多用于参数传递
        Class cls2 = Car.class;
        System.out.println(cls2);

        //3. 对象.getClass() 应用场景:有对象实例
        Car car = new Car();
        Class cls3 = car.getClass();
        System.out.println(cls3);

        //4. 通过类加载器(4种),来获取到类的 Class 对象
        //先得到类加载器 car
        ClassLoader classLoader = car.getClass().getClassLoader();
        //通过类加载器得到 Class 对象
        Class cls4 = classLoader.loadClass(classAllpath);
        System.out.println(cls4);

        //5. 基本数据类型(int, char, boolean, float, double, byte, long, short)按如下方式得到 Class 类对象
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.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); //int
    }
}

 

 

四、哪些类型有Class对象

1、外部类,成员内部类,静态内部类,局部内部类,匿名内部类

2、interface:接口

3、数组

4、enum:枚举

5、annotation:注解

6、基本数据类型

7、void

package com.javase.reflection.class_;

import java.io.Serializable;

/**
 * 演示哪些类型有 Class 对象
 */
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;//void数据类型                    
        Class<Class> classClass = Class.class;//Class
    }
}

 

 

五、类加载

基本说明

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

1、静态加载:编译时加载相关的类,如果没有则报错,依赖性太强

2、动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性

 

类加载时机

1、当创建对象时(new)

2、当子类被加载时

3、调用类中的静态成员时

4、通过反射

 

类加载过程图

 

类加载各阶段完成任务

 

加载阶段

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

 

连接阶段-验证

1、目的是为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全

2、包括:文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和符合引用验证

3、可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间

 

连接阶段-准备

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

class A{
    //属性-成员变量-字段
    //分析类加载的链接阶段-准备 属性是如何处理
    //1. n1 是实例属性,不是静态变量,因此在准备阶段,是不会分配内存
    //2. n2 是静态变量,分配内存,n2 是默认初始化0,而不是20
    //3. n3 是 static final 是常量,它和静态属性不一样,因为一旦赋值就不变 n3 = 30
    public int n1 = 10;
    public static int n2 = 20;
    public static final int n3 = 30;
}

 

连接阶段-解析

        虚拟机将常量池内的符号引用替换为直接引用的过

 

Initialization(初始化)

1、到了初始化阶段,才真正开始执行类中定义的 Java 程序代码,此阶段是执行 <clinit>() 方法的过程

2、<clinit>() 方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并

3、虚拟机会保证一个类的 <clinit>() 方法在多线程的环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的 <clinit>() 方法,其他线程都需要阻塞等待,直到活动线程执行 <clinit>() 方法完毕

/**
 * 演示类加载-初始化阶段
 */
public class ClassLoad02 {
    public static void main(String[] args) {
        //分析
        //1. 加载B类,并生成B的Class对象
        //2. 连接
        //3. 初始化阶段
        //   依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并
        /*
             clinit() {
                System.out.println("B 的静态代码块被执行");
                //num = 300;
                num = 100;
             }
             合并:num = 100
         */
        
        //new B();
        System.out.println(B.num);//如果直接使用类的静态属性,也会导致类的加载
    }
}

class B{
    static {
        System.out.println("B 的静态代码块被执行");
        num = 300;
    }

    static int num = 100;

    public B() {
        System.out.println("B 的构造器被执行");
    }
}

 

 

六、通过反射获取类的结构信息 

第一组:java.lang.Class类

1、getName:获取类全名

2、getSimpleName:获取简单类名

3、getFields:获取所有 public 修饰的属性,包含本类以及父类的

4、getDeclaredFields:获取本类中所有属性

5、getMethods:获取所有 public 修饰的方法,包含本类以及父类的

6、getDeclaredMethods:获取本类中所有方法

7、getConstructors:获取本类中所有 public 构造器

8、getDeclaredConstructors:获取本类中所有构造器

9、getPackage:以 Package 形式返回 包信息

10、getSuperClass:以 Class 形式返回父类信息

11、getInterfaces:以 Class[] 形式返回接口信息

12、getAnnotations:以 Annotation[] 形式返回注解信息

 

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

1、getModifiers:以 int 形式返回修饰符

    【说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16】

2、getType:以 Class 形式返回类型

3、getName:返回属性名

 

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

1、getModifiers:以 int 形式返回修饰符

    【说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16】

2、getReturnType:以 Class 形式获取返回类型

3、getName:返回方法名

4、getParameterTypes:以 Class[] 返回参数类型数组

 

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

1、getModifiers:以 int 形式返回修饰符

2、getName:返回构造器名(全类名)

3、getParameterTypes:以 Class[] 返回参数类型数组

import org.junit.jupiter.api.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) {

    }

    //第一组方法
    @Test
    public void api_01() throws Exception {
        //得到 Class对象
        Class<?> personCls = Class.forName("com.javase.reflection.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(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(constructor.getName());
        }

        //8、getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getName());
        }

        //9、getPackage:以Package形式返回 包信息
        Package aPackage = personCls.getPackage();
        System.out.println(aPackage);

        //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);
        }
    }

    @Test
    public void api_02() throws Exception {
        //得到 Class对象
        Class<?> personCls = Class.forName("com.javase.reflection.Person");

        //getDeclaredFields:获取本类中所有属性
        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(declaredConstructor.getName());
            Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("构造器的形参类型:" + parameterType);
            }
        }
    }
}

interface IA{

}

interface IB{

}

class C {
    public String hobby;

    public C() {
    }

    public void hi() {

    }
}

@Deprecated
class Person extends C implements IA, IB {
    //属性
    public String name;
    private int age;
    String job;
    private double sal;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    private Person(int age) {
        this.age = age;
    }

    //方法
    public void m1(String name, double sal, int age) {

    }

    protected String  m2() {
        return null;
    }

    void m3() {

    }

    private void m4() {

    }
}

 

 

七、通过反射创建对象

1、方式一:调用类中的 public 修饰的无参构造器

2、方式二:调用类中的指定构造器

3、Class 类相关的方法

      newInstance:调用类中的无参构造器,获取对应类的对象

      getConstructor(Class...clazz):根据参数列表,获取对应的构造器对象

      getDecalaredConstructor(Class...clazz):根据参数列表,获取对应的构造器对象

4、Constructor 类相关方法

      setAccessible:暴破

       newInstance(Object...obj):调用构造器

import java.lang.reflect.Constructor;

/**
 * 演示通过反射机制创建实例
 */
public class ReflectCreateInstance {
    public static void main(String[] args) throws Exception {
        //1. 获取到 User 类的 Class 对象
        Class<?> userClass = Class.forName("com.javase.reflection.User");

        //2. 通过 public 的无参构造器创建实例
        Object o = userClass.newInstance();
        System.out.println(o);

        //3. 通过 public 的有参构造器创建实例
        /*
            constructor对象就是
            public User(String name) {
                this.name = name;
            }
         */
        //先得到对应的构造器
        Constructor<?> constructor = userClass.getConstructor(String.class);
        //创建实例 并传入实参
        Object ls = constructor.newInstance("李四");
        System.out.println(ls);

        //4. 通过 非public 的有参构造器创建实例
        //先得到对应的构造器
        Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class);
        //创建实例 并传入实参
        //暴破(暴力破解),使用反射可以访问 private 构造器/方法/属性
        declaredConstructor.setAccessible(true);
        Object ll = declaredConstructor.newInstance(15, "老六");
        System.out.println(ll);
    }
}

class User {
    private int age = 20;
    private String name = "张三";

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    private User(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

 

 

八、通过反射访问类中的成员 

访问属性

1、根据属性名获取 Field 对象

      Field f = clazz对象.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.Constructor;
import java.lang.reflect.Field;

/**
 * 演示反射操作属性
 */
public class ReflectAccessProperty {
    public static void main(String[] args) throws Exception {
        //1. 得到对应的 Class 对象
        Class<?> stuClass = Class.forName("com.javase.reflection.Student");

        //2. 创建对象
        Object o = stuClass.newInstance();//o 的运行类型就是 Student
        System.out.println(o.getClass());//Student

        //3. 使用反射得到 age 属性的对象
        Field age = stuClass.getField("age");
        age.set(o, 20);//通过反射来操作属性
        System.out.println(o);
        System.out.println(age.get(o));//返回age属性的值

        //4. 使用反射操作 name 属性
        Field name = stuClass.getDeclaredField("name");
        name.setAccessible(true);//暴破后就可以操作私有的属性
        //name.set(o, "张三");
        name.set(null, "张三");//因为 name 是静态的,因此 o 也可以写成 null
        System.out.println(o);
        System.out.println(name.get(o));
    }
}

class Student {
    public int age;
    private static String name;

    public Student() {
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

 

访问方法

1、根据方法名和参数列表获取 Method 方法对象

      Method m = clazz.getDeclaredMethod(方法名,XX.class);

2、获取对象:Object o = clazz.newInstancet();

3、暴破:m.setAccessible(true);

4、访问:Object returnValue = m.invoke(o, 实参列表);

5、注意:如果是静态方法,则 invoke 的参数 o,可以写成 null

import java.lang.reflect.Method;

/**
 * 演示通过反射调用方法
 */
public class ReflectAccessMethod {
    public static void main(String[] args) throws Exception {
        //1. 得到对应的Class对象
        Class<?> bossClass = Class.forName("com.javase.reflection.Boss");

        //2. 创建对象
        Object o = bossClass.newInstance();

        //3. 调用 public 的 hi方法
        //Method hi = bossClass.getMethod("hi", String.class); //只能得到 public
        //得到 hi 方法的对象
        Method hi1 = bossClass.getDeclaredMethod("hi", String.class);//可以得到所有的方法
        //调用
        hi1.invoke(o, "张三");

        //4. 调用 private static 方法
        //得到 say 方法对象
        Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class);
        //私有的方法需要暴破
        say.setAccessible(true);//暴破
        System.out.println(say.invoke(o, 20, "李四", '男'));
        //因为say方法是静态的 也可以传入 null
        System.out.println(say.invoke(null, 30, "老六", '女'));

        //5. 在反射中,如果方法有返回值,统一返回 Object 但是运行类型和方法定义的返回类型一致
        Object invoke = say.invoke(null, 30, "老六", '女');
        System.out.println(invoke.getClass());//class java.lang.String
    }
}

class Boss {
    public int age;
    private static String name;

    public Boss() {
    }

    private 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.coloradmin.cn/o/84205.html

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

相关文章

数学基础从高一开始6、全称量词与存在量词

数学基础从高一开始6、全称量词与存在量词 目录 数学基础从高一开始6、全称量词与存在量词 全称量词 存在量词 1.判断命题的真假 2.判断命题的真假 阅读下列两组命题&#xff0c;语言上有什么特点? A组&#xff1a; (1)对任意一个x∈Z&#xff0c;2x1是整数; (2)每一个素…

Pod使用进阶

Pod使用进阶 封面 写在前面 语雀上阅读效果更佳&#xff0c;请访问如下地址&#xff1a; 197 Pod使用进阶 语雀 《197 Pod使用进阶》 1、Pod 资源配置 实际上上面几个步骤就是影响一个 Pod 生命周期的大的部分&#xff0c;但是还有一些细节也会在 Pod 的启动过程进行设置&…

Hive 计算用户留存率(次日,3日,N日)

文章目录什么是用户留存率&#xff1f;创建数据源计算留存率计算 N 日的留存率什么是用户留存率&#xff1f; 用户留存率是指在特定时间段内&#xff0c;用户在使用某个产品或应用程序后&#xff0c;再次使用该产品或应用程序的比例。 它可以帮助公司了解用户是否喜欢他们的产…

2022 第十四届蓝桥杯模拟赛第二期题目题解(比赛时使用方法)

目录 第一题&#xff1a;最小的2022 第二题&#xff1a;经过天数 第三题&#xff1a;特殊的十六进制数 第四题&#xff1a;矩阵的最小路径 第五题&#xff1a;质数拆分 第六题&#xff1a;拷贝时间 第七题&#xff1a;单词去重 第八题&#xff1a;最短回文串 第九题&a…

[附源码]Node.js计算机毕业设计大学校园二手教材与书籍Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

GoWeb 优雅的 ORM 框架之 GORM,实现 MySQL 数据库的增删改查等操作(附案例全代码)

1、前言 什么是web应用,Web应用程序简单流程如下图所示 通过上图我们发现,我们 GoWeb 实战项目还缺少最后关键的环节数据库。那么如何使用 GO 语言操作数据库并完成增删改查等操作是我们今天学习的目标。 GoWeb 的 MVC 入门实战案例,基于 Iris 框架实现(附案例全代码) …

[附源码]Python计算机毕业设计Django的连锁药店销售管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

11.校验token和解析token获取数据代码优化

校验token和解析token获取数据代码优化 解决方案 基于ThreadLocal 拦截器的形式统一处理 一、使用拦截器进行统一身份鉴权 1.1定义拦截器 package com.tanhua.server.interceptor;import com.tanhua.commons.utils.JwtUtils; import org.springframework.web.servlet.Handl…

[附源码]Nodejs计算机毕业设计基于java旅游信息分享网站Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

二、物理层(一)通信基础

目录 1.1通信基础概念 1.2传输方式 1.2.1串行传输和并行传输 1.2.2单工通信、半双工通信和全双工通信 1.3编码与调制 1.3.1数字数据编码为数字信号 1.3.2数字数据调制为模拟信号 1.3.3模拟信号编码为数字信号 1.3.4模拟数据调制为模拟信号 1.4电路交换、报文交换与分…

装了就不舍得卸载,4款电脑必装软件,功能实用又免费

下面4款电脑软件&#xff0c;每一个都是你绝对能用得上的神器&#xff0c;可遇不可求。 1、AutoOff AutoOff是一款完全免费&#xff0c;纯绿色的电脑操作定时工具&#xff0c;功能强大且实用&#xff0c;体积不到1M&#xff0c;非常小巧&#xff0c;支持自动关机、重启、休眠、…

Mysql批量插入对比(附github仓库demo)

前言 本文记录个人使用MySQL插入大数据总结较实用的方案&#xff0c;通过对常用插入大数据的4种方式进行测试&#xff0c; for循环单条拼接SQL批量插入saveBatch()循环 开启批处理模式 最近趁空闲之余&#xff0c;在对MySQL数据库进行插入数据测试 准备工作 测试环境&…

189:vue+openlayers 上传CSV文件,导出Geojson格式文件

第189个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+openlayers上传CSV文件,导出GeoJSON文件。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果; 注意如果OpenStreetMap无法加载,请加载其他来练习 文章目录 示例效果使用的csv文件安装依赖配置方…

直播场控助手 | 为什么说直播场控比主播更重要?

在竞争白热化的直播时代&#xff0c;作为主播最亲密的伙伴&#xff0c;场控的作用不容忽视。 优秀的场控掌握着关键成交节点&#xff0c;实时帮助主播带节奏、促转化。在精细化直播运营中&#xff0c;优秀的场控能力胜过十位主播&#xff0c;让直播间轻松实现销量翻倍。 「帷幄…

基于jsp+mysql+ssm水果蔬菜销售系统-计算机毕业设计

项目介绍 生活中&#xff0c;人们买水果或者蔬菜都是去菜市场买&#xff0c;因为那里是卖水果、蔬菜的聚集地。农商们把水果、蔬菜从远处运到那里&#xff0c;进行销售。但是这种销售方式的不足在于每次运输的数量是有限的&#xff0c;并且运输过程中也影响了水果、蔬菜的口感…

使用 TVMC 编译和优化模型

内容一览&#xff1a;本节讲解使用 TVMC 编译和优化模型。TVMC 是 TVM 的命令驱动程序&#xff0c;通过命令行执行 TVM 功能。本节是了解 TVM 工作原理的基础。 关键词&#xff1a;TVMC TVM 机器学习 本节将介绍 TVMC&#xff08;TVM 的命令行驱动程序&#xff09;。TVM…

单片机扫盲

一、从电路到集成电路 集成电路&#xff1a;使用微器件为“积木”&#xff0c;去搭建一个具备一定功能的电路板 微器件出现之前&#xff0c;一个电路功能需要很大一块电路板才能实现&#xff0c;有了微器件电路板的体积可以降到mm级别。 IC芯片就是将电路的所有微器件集成到一…

大数据时代,数据仓库究竟是干嘛的?

前言 无论你是否专门从事大数据开发&#xff0c;作为一个开发人员&#xff0c;应该都听说过数据仓库的概念&#xff0c;那你知道为什么会出现数据仓库&#xff1f;数据仓库究竟是干嘛的吗&#xff1f;有什么价值和意义呢&#xff1f;那么本文就带到入门&#xff0c;揭开数据仓…

大数据分析工具-FineReport地产行业通用单选按钮组控件插件

1. 概述 1.1 版本 报表服务器版本 JAR 包版本 插件版本 10.0 2018-09-05 V1.3.4 9.0 2015-08-09 V1.3.2 8.0 2015-08-09 V1.3.2 1.2 应用场景 地产行业具有比较特殊的筛选需求&#xff0c;而现有的单选按钮组控件不能很好的满足这一点。我们希望可以实现多层级多…

空间音频技术与生态发展高峰论坛成功举办,业界首个Audio Vivid创作工具花瓣三维声亮相

11月26日至27日&#xff0c;UWA世界超高清视频产业联盟&#xff08;以下简称“UWA联盟”&#xff09;、上海交通大学-南加州大学文化创意产业学院、华为联合举办了“互联智慧&#xff0c;共赢未来” 超高清音视频技术与生态发展高峰论坛暨Audio Vivid空间音频工具花瓣三维声训练…