zoukankan      html  css  js  c++  java
  • java-反射

    类的加载

    当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

    • 加载

    就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象

    • 连接

    验证 是否有正确的内部结构,并和其他类协调一致。

    准备 负责为类的静态成员分配内存,并设置默认初始化值。

    解析 将类的二进制数据中的符号引用替换为直接引用。

    • 初始化

    类加载器的组组成:

    • Bootstrap ClassLoader 根类加载器

    也被称为引导类加载器,负责Java核心类的加载,比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

    • Extension ClassLoader 扩展类加载器

    负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录

    • System ClassLoader 系统类加载器

    负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。


    理解:

    1.程序运行时,类加载器将class文件载入数据共享区,并在堆中创建了一个class文件的对象。     

    2.在什么情况会初始化类(不是):

    (1)创建类的实例

    (2)初始化类的某个子类

    (3)使用反射方式来强制创建某个类或接口对应的java.lang.Class对象     暂时写3种。

    3.为什么用反射(运行时起作用)?

    (1)为添加新功能(类)而不修改原有代码,要使用这个新功能时,通过这个class文件对象,拿出相应功能执行。拿出的方式,解剖的方式就是反射。程序通过反射从class文件把功能拿出来执行,随时给个新的类,随时都能运行。

    (2)类先加载进入共享区,然后加载器给文件创建一个class文件对象,反射区解剖,用户无权创建和销毁这个对象。


    获取class文件对象的三种方式

    //1.
    Person p=new Person;
    Class c1=p.getClass();
    //2.
    Class c2=Person.class;
    //3.字符串要包名.类名
    Class c3=ClassForName("包名.类名");

    注:第三种和前两种的区别

    前两种你必须明确Person类型.

    后面是指定这种类型的字符串就行.这种扩展更强.我不需要知道你的类.我只提供字符串,按照配置文件加载就可以了。

    Class类似于String的引用类型。


    获取构造器:

    除private修饰外的构造器

         Class c=Class.forName("wei.Person");
            //获取除private修饰的多个构造器
            Constructor []cons=c.getConstructors();
            //获取除private修饰的, 指定参数类型所对应的构造方法,不写参数是空参构造器
            Constructor cons1=c.getConstructor(String.class,int.class);
            //通过构造方法创建Object对象
            Object obj=cons1.newInstance("lili",15);
            //父类Object不能调用子类的方法特有,要转型
            Person p=(Person)obj;
            p.method3();
    Class c=Class.forName("wei.Person");
    //可直接获得运行时对象,前提是类又空参构造器
    Object obj=c.newInstance();

    注:同理获取所有构造器

    改用调用getDeclaredConstructor()和getDeclaredConstructors()。

    但不推荐这么做,因为破坏了类的封装性。

    获取之后要传私有属性需要将 构造器引用.setAccessible(true),参数值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。参数值为 false 则指示反射的对象应该实施 Java 语言访问检查。

    这个是父类的方法。


    获取成员变量

    • 返回一个成员变量

    public Field getField(String name) 获取指定的 public修饰的变量

    public Field getDeclaredField(String name) 获取指定的任意变量

    • 返回多个成员变量

    public Field[] getFields() 获取所有public 修饰的变量

    public Field[] getDeclaredFields() 获取所有的 变量 (包含私有)

    例如:Field nameField = c.getField("name");

    设置成员变量

     public void set(Object obj, Object value)

    在指定对象obj中,将此 Field 对象表示的成员变量设置为指定的新值

    public Object get(Object obj)

    返回指定对象obj中,此 Field 对象表示的成员变量的值

    例如:
    Field ageField = c.getField("age"); ageField.get(obj); ageField.set(obj, 23);

    获取方法

    • 返回获取一个方法:

    public Method getMethod(String name, Class<?>... parameterTypes)

                             获取public 修饰的方法

    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

                             获取任意的方法,包含私有的

    参数1: name 要查找的方法名称; 参数2: parameterTypes 该方法的参数类型

    • 返回获取多个方法:

    public Method[] getMethods() 获取本类与父类中所有public 修饰的方法

    public Method[] getDeclaredMethods() 获取本类中所有的方法(包含私有的)

    例如:
    //获取一个方法:
    //public void method1()
    Method method = c.getMethod("method1", null);

    使用方法

    Method m4 = c.getMethod("method4", String.class);
    
    m4.invoke(obj, "啦啦啦");

  • 相关阅读:
    Java实现数字转化成字符串左边自动补零方法
    java如何对map进行排序详解(map集合的使用)
    java字符串比较的原理
    rancher快速创建mysql和redis
    k8s Ingress介绍和部署IngressController
    k8s+rancher+阿里云镜像简单部署flask项目
    helm 部署minio
    k8s存储数据卷
    k8s搭建redis集群
    团队作业4:第二篇Scrum冲刺博客
  • 原文地址:https://www.cnblogs.com/findlisa/p/10777293.html
Copyright © 2011-2022 走看看