菜单

好像加载机制与反射

2018年12月16日 - jQuery

一. 类的加载,连接,起始化

一样、Java类加载机制

  1.1. JVM和类

当调用Java命令运行有Java程序时,该令将相会启动一个Java虚拟机进程。不管Java程序多么复杂,启动多少只线程,它们都地处该Java虚拟机进程里,都是使用和一个Java进程内存区。

JVM程序终止之艺术:

JVM进程停止,该过程四方内存中之状态将相会丢掉

1.概述

  1.2 类的加载

当次积极以某个类时,倘诺此类还非给加载到外存中,则网会经加载、连接、最先化三单步骤来对该类进行初始化。

类的加载时以该类的class文件读入内存,并为的创立一个java.lang.Class对象,也就是说,当次拔取其他像样时,系统还会面吧底立一个java.lang.Class对象。

网遭到兼有的好像实际上为是实例,它们如故java.lang.Class的实例

接近的加载通过JVM提供的类加载器完成,类加载器时先后运行的功底,JVM提供的切近加载器被称呼系统类加载器。除此之外,开发者可以透过继承ClassLoader基类来创建自己的类似加载器。

经过使用不同的切近加载器,可以从不同来加载类的二进制数据,平常爆发如下几栽来源。

  1. 自本土文件系统加载class文件,这是前边绝大部分实例程序的切近加载格局
  2. 自从jar包加载class文件,这种办法啊是老大宽泛的,jdbc编程所用底教类就位于jar文件中,JVM可以直接从jar文件中加载该class文件。
  3. 经过网络加载class文件
  4. 把一个Java源文件动态编译,并实施加载

接近加载器平常无需等及首不善利用该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。

  1.3 类的接连

当类被加载后,系统会为的深成一个相应的Class对象,接着会进入连接路,连接路负把看似的二进制数据统一及JRE中。类的链接可分为如下三单等级。

  1. 证实:验证阶段用于检验被加载的切近是否暴发不错的内部结构,并同外类协调一致
  2. 未雨绸缪:类准备阶段则负责为类的类变量分配内存,并设置默认开头值
  3. 分解:将类的二进制数据中之变量举办标记引用替换成直接引用

  1.4 类的起始化

再烦舒适化阶段,虚拟机负责对类举行伊始化,首要就对类变量进行最先化。在Java类吃针对近似变量指定起始值有星星点点种植情势:①望明类变量时指定起先值;②行使静态先导化块为接近变量指定初步值。

JVM开头化一个近乎富含如下步骤

  1. 加载并一连该类
  2. 优先开始化其直接父类
  3. 依次执行起先化语句

当执行第2步时,系统针对直接父类的初叶化也遵照1~3,以此类推

Class文件由类似装载器装载后,在JVM大校形成相同卖描述Class结构的排头音信目的,通过该元音讯目的可以获取知Class的构造消息:如构造函数,属性和格局等,Java允许用户借由那个Class相关的第一音信目的直接调用Class对象的效用。

  1.5 类起首化时机

当Java程序首涂鸦经过下边6种植办法选拔某个类或接口时,系统会先导化该类或接口

二. 类加载器

  2.1类加载器介绍

  接近加载器负责将.class文件加载到外存中,并也的别对应的java.lang.Class对象。

一个载入JVM的近乎闹一个唯一的标识。在Java中,一个类使用全限定类名(包括包名和类名)作为标识;但在JVM中,一个看似应用全限定类名和其类加载器作为唯一标识。

当JVM启动时,会形成由三独八九不离十加载器组成的起首类加载器层次结构

Bootrap
ClassLoader为誉为指点(也号称原始或与)类加载器,它当加载Java的主干类。跟类加载器不是java.lang.ClassLoader的子类,而是JVM自身实现之。

Extension
ClassLoader负责加载JRE拓展目录中之JAR包的类似,它的父类加载器是跟类加载器

System
ClassLoader,它承受在JVM启动时加载来自Java命令的-classpath选项、java.class,path系统特性,或CLASSPATH指定的jar包和类历经。系统而是通过ClassLoader的静态方法或区该系统类加载器。假若没特意指定,则用户从定义之近乎加载器都早已接近加载器作为父加载器

虚拟机把叙类的多寡从class文件加载到内存,并针对性数码举行校验,转换解析和初阶化,最终形成得叫虚拟机直接用的Java类型,这便是虚拟机的类加载机制。

  2.2 类加载机制

JVM类加载机制重点出三栽

类似加载器加载Class大致经过8独步骤

  1. 检测此Class是否载入了(即缓存区中是否生此Class),假设爆发则直进入第8步,否者接着第2步
  2. 倘父类加载器(父类      gt+
    加载器,要么Parent一定是跟类加载器,要么本身便是跟类加载器)不在,则调整到第4步执行
  3. 求使用父类加载器载入目的类,假诺成功载入调至第8步
  4. 要使用跟类加载器来载入目的类
  5. 眼下看似加载器尝试寻找Class文件(从与此ClassLoader相关的类路径中搜寻),假设找到则履行第6步,即便搜索不至执行第7步
  6. 由文本中载入Class,成功载入调至第8步
  7. 抛出ClassNotFoundException异常
  8. 再次来到对应之java.lang.Class对象

个中,第5、6步允许再写ClassLoader的findClass()方法来兑现协调之载入策略,甚至更写loadClass()方法来贯彻团结之载入过程。

2.干活体制

  2.3 创设并行使从定义之类似加载器

JVM除跟类加载器之外的富有类加载器都是ClassLoader子类的实例,开发者能够经过展开ClassLoader的子类,并更写该ClassLoader所包含的办法实现从定义之类似加载器。ClassLoader有如下两单重点办法。

假诺需即便兑现自定义的ClassLoader,则足以经重写以上两只措施来落实,通常推荐还写findClass()方法而休是loadClass()方法。

classLoader()方法的履行步骤:

  1. findLoadedClass():来检查是不是加载类,倘诺加载直接归。
  2. 父类加载器上调用loadClass()方法。假诺父类加载器为null,则使跟类加载器加载。
  3. 调用findClass(String)方法查找类

于上边看出,重写findClass()方法可以避免覆盖默认类加载器的父类委托,缓冲机制两种政策;假使重复写loadClass()方法,则贯彻逻辑更是复杂。

ClassLoader的有主意:

下程序支付了一个自定义的ClassLoader。该classLoader通过更写findClass()方法来贯彻由定义的接近加载机制。这一个ClassLoader可以以加载类在此以前先行编译该类的源文件,从而实现运行Java从前先行编译该次的靶子,这样即可通过该classLoader运行Java源文件。

 

package com.gdut.basic;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class CompileClassLoader extends ClassLoader {
private byte[] getBytes(String fileName) {
    File file = new File(fileName);
    Long len = file.length();
    byte[] raw = new byte[(int)len];

        FileInputStream fin = new FileInputStream(file);
        //一次读取class文件的二进制数据
        int r = fin.read(raw);
        if(r != len) {
            throw new IOException("无法读取文件"+r+"!="+raw);


    return null;
        }
}
    private boolean compile(String javaFile) throws IOException {
        System.out.println("正在编译"+javaFile+"...");
        Process p = Runtime.getRuntime().exec("javac"+javaFile);
        try {
            //其他线程都等待这线程完成
            p.waitFor();
        }catch(InterruptedException ie) {
            System.out.println(ie);
        }
        int ret = p.exitValue();
        return ret == 0;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class clazz = null;
        String findStub = name.replace(".", "/");
        String javaFileName = findStub+".java";
        String classFileName = findStub+".class";
        File javaFile = new File(javaFileName);
        File classFile = new File(classFileName);

        //但指定Java源文件存在,class文件不存在,或者Java源文件的修改时间比class文件修改的时间更晚时,重新编译
        if(javaFile.exists() && classFile.exists()
                || javaFile.lastModified() > classFile.lastModified()) {
            try {
            if(!compile(javaFileName)|| !classFile.exists()) {
                throw new ClassNotFoundException("ClassNotFoundExcetion"+javaFileName);
            }
            }catch(IOException ie) {
                ie.printStackTrace();
            }
        }
        if(classFile.exists()) {

                byte[] raw = getBytes(classFileName);

                clazz = defineClass(name,raw,0,raw.length);
        }
        //如果clazz为null,表明加载失败,则抛出异常
        if(clazz == null) {
            throw new ClassNotFoundException(name);
        }
        return clazz;
    }

    public static void main(String[] args) throws Exception {
        //如果运行该程序时没有参数,即没有目标类
        if (args.length<1) {
            System.out.println("缺少目标类,请按如下格式运行Java源文件:");
            System.out.println("java CompileClassLoader ClassName");
        }

        //第一个参数是需要运行的类
        String progClass = args[0];

        //剩下的参数将作为运行目标类时的参数,将这些参数复制到一个新数组中
        String[] progArgs = new String[args.length - 1];
        System.arraycopy(args, 1,progArgs,0, progArgs.length);

        CompileClassLoader ccl = new CompileClassLoader();
        //加载需要运行的类
        Class<?> clazz = ccl.loadClass(progClass);
        //获取运行时的类的主方法
        Method main = clazz.getMethod("main", (new String[0]).getClass());
        Object argsArray[] = {progArgs};
        main.invoke(null, argsArray);

    }
}

接通下好供任意一个略的主类,该主类无需编译就足以选拔方面的CompileClassLoader来运转他

package com.gdut.basic;

public class Hello {

    public static void main(String[] args) {
        for(String arg:args) {
            System.out.println("运行Hello的参数:"+arg);
        }

    }

}

不必编译该Hello.java,可以直接运行下边发号施令来运转该Hello.java程序

java CompileClassLoader hello 疯狂Java讲义

运作结果如下:

CompileClassLoader:正常编译 Hello.java...
运行hello的参数:疯狂Java讲义

 

使用由定义之近乎加载器,可以兑现如下效果

  1. 推行代码前自行验证数字签名
  2. 据悉用户提供的密码解密代码,从而可以实现代码混淆器来避免倒编译*.class文件
  3. 基于使用需求将任何数据因字节码的款式加载到以被。

    2.4 URLClassLoader类

此类时系统类加载器和开展类加载器的父类(此处的父类,是指类与类似中的之继承关系)。URLClassLoader效用相比较强,它可于本土文件系统获取二进制文件来加以载类,也得以自远程主机获取二进制文件加载类。

该类提供个别单构造器

脚程序示范了什么由文本系统受到加载MySQL驱动,并利用该让获取数据库连接。通过这种方法来获取数据库连接,无需将MySQL驱动上加至CLASSPATH中。

package java.gdut;

import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.Driver;
import java.util.Properties;

public class URLClassLoaderTest {
    private static Connection conn;

    public static Connection getConn(String url,String user,String pass)throws Exception{
        if(conn == null){
            URL[] urls = {new URL("file:mysql-connection-java-5.1.46-bin.jar")};
            URLClassLoader myClassLoader = new URLClassLoader(urls);
            //加载MySQL,并创建实例
            Driver driver = (Driver)myClassLoader.loadClass("com.mysql.jdbc.Driveer").newInstance();

            Properties properties = new Properties();
            properties.setProperty("user",user);
            properties.setProperty("pass",pass);
            //调用driver的connect方法来取得数据库连接
            conn = driver.connect(url,properties);
        }
        return conn;
    }

    public static void main(String[] args) throws Exception {
        System.out.println(getConn("jdbc:mysql://localhost:3306/tb_test","sherman","a123"));
    }
}

本程序类加载器的加载路径是当下路下之mysql-connection-java-5.1.46-bin.jar文件,将MySQL驱动复制到该路径下,那样保证ClassLoader可以正常加载到驱动类

恍如装载器就是摸索类似的许节码文件,并协会出类在JVM内部表示的靶子组件。在Java中,类装载器把一个类装入JVM中,要由此以下步骤:

三. 通过反射查看类音讯

Java程序中的大队人马靶在运转时还晤面起收外部传入的一个目标,该对象编译时类型是Object,但先后同时待调用该对象运行时的点子。

(1) 装载:查找和导入Class文件;

  3.1 获得class对象

每个接近让加载后,系统会为此类生成一个遥相呼应的Class对象,通过该Class对象能够看到JVM中之斯仿佛。得到Class对象平日两种模式

  1. 运Class类的forName(String
    clazz)静态方法。字符串参数传入全限定类名(必须加加包名),可能会师扔来ClassNotFoundexception非凡。
  2. 调用某个类的class属性来获取该类的的Class对象。
  3. 调用某个对象的getClass()方法,该法是Object类的一个艺术。

对此第一栽方法,第两种植的优势:

(2) 链接:把看似的二进制数据统一及JRE中;

  3.2 从Class中获取新闻

Class类提供了汪洋底实例方法赢得该Class对象所针对应类的详细音信

脚4只措施用于获取Class对象对应类的构造器

脚五个道取得Class对象对应类所富含方法。

脚五只点子得到Class对象对应类所蕴涵的分子变量。

正如多少个法子用于访问Class对应类的达到所涵盖的Annotation.

一般来说方法用于访问Class对应类的里边类

如下方法用于访问Class对应类的四处的表面类

如下方法用于访问Class对应类的所实现之接口

正如方法用于访问Class对应类的所累的父类

正如方法用于访问Class对应类的修饰符,所在包,类名等骨干信息

以下四只模式来判定该类是否为接口、枚举、声明类型

如上getMethod()方法与getConStructor()方法中,都用传入多独品种也Class<?>的参数,用于取指定的措施和构造器。要规定一个措施应该由艺术名和形参列表确定。例如下边代码获取clazz对应类的带来一个String参数的info方法:

clazz.getMethods("info",String.class)

  若使取得clazz对应类的带一个String参数,一个Integer参数的info方法

clazz.getMethods("info",String.class,Integer.class)

(a)校验:检查载入Class文件数量的不利;

  3.3 Java 8初添的方参数反射

Java
8初加了一个Executable抽象基类,该目的表示可尽之好像成员,该类派生了Constructor和Method两单子类。

Executable抽象基类提供了大气术来取修饰该法要构造器的声明信息;还提供了is
VarArgs()方法用于判断该模式依然构造器是否含有数据可变的形参,以及经过getModifiers()方法得到该办法或者构造器的修饰符。除此之外,还提供如下几个点子

Parameter类是Java
8初添的api,提供了汪洋计来拿到阐明该法或者参数个数的泛型信息,还提供了如下方法得到参数音信

欲提出的是,使用javac命令编译Java源文件时,默认生成的class文件并无分包方法的显得参名音信,由此调用isNamePresent()将回来false,调用getName()也非可以得该参数的展示参名。需要编译时保留形参音讯,则要该令指定-parameter选项。

下边示范了Java 8的参数反射功能

public class MethodParameterTest {
    public static void main(String[] args) throws Exception {
        Class<Test> clazz = Test.class;
        Method replace = clazz.getMethod("replace",String.class,List.class);
        System.out.println("replace方法的参数个数为:"+replace.getParameterCount());

        Parameter[] parameters = replace.getParameters();
        int index = 1;
        for(Parameter parameter:parameters){
            if(!parameter.isNamePresent()){
                System.out.println("-----第"+index+"行的参数信息-----");
                System.out.println("参数名:"+parameter.getName());
                System.out.println("形参类型:"+parameter.getType());
                System.out.println("泛型类型:"+parameter.getParameterizedType());
            }
        }
    }
}

图片 1

(b)准备:给类的静态变量分配存储空间;

  3.4 利用反射生成并操作对象

Class对象可以得到该类的道,构造器,成员变量。程序可以经过Method对象来推行相应之艺术,通过ConStructor对象调用对应的构造器创设实例,能经过菲尔德(Field)对象直接看并修改对象的积极分子变量值。

(c)解析:将记引用转成直接引用;

3.4.1 成立对象

通过反射生成对象有一定量栽办法。

(3) 开首化:对类的静态变量,静态代码块执行初叶化操作

3.4.2 调用方法

可透过Class对象的getMethods()方法以及getMethod()方法来博全体法和点名方法。

每个Method对象对应一个道,能够透过它们调用对应的形式,在Method里富含一个invoke()方法,该方法的签署如下。

下边程序是对准象池工厂加强版本,它同意在布置文件中增添部署对象的成员变量的价,对象池工厂会读取为该目的配置的积极分子变量值,并行使该对象的Setter方法设置成员变量的价。

package com.gdut.test0516;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class ExtendedObjectPoolFactory {
    //定义一个对象池,前面是对象名,后面是实际对象
    private Map<String,Object> objectPool = new HashMap<>();
    private Properties config = new Properties();

    public void init(String fileName)
    {
        try(FileInputStream fis = new FileInputStream(fileName))
        {
            config.load(fis);
        }catch(IOException ex){
            System.out.println("读取"+fileName+"异常");
        }
    }

   private Object createObject(String clazzName)throws ClassNotFoundException,
           InstantiationException,IllegalAccessException{
        Class<?> clazz = Class.forName(clazzName);
        //使用clazz默认构造器创建实例
        return clazz.newInstance();
   }


   public void initPool()throws ClassNotFoundException,
           InstantiationException,IllegalAccessException{
       for (String name:config.stringPropertyNames())
       {
           //没取出一个key-value对。如果key中不包含百分号(%),即可认为该key用于
           // 控制调用对象的setter方法设置值,%前半为对象名字,后半控制setter方法名
       if( !name.contains("%")){
           objectPool.put(name,createObject(config.getProperty(name)));
       }
       }
   }
   public Object getObject(String name){
        return objectPool.get(name);
   }

   public void initProperty()throws NoSuchMethodException,
   IllegalAccessException,InvocationTargetException {
       for (String name:config.stringPropertyNames()) {
           if(name.contains("%")){
               String[] objAndProp = name.split("%");
               Object target = getObject(objAndProp[0]);
               String mtdName = "set"+objAndProp[1].substring(1);
               Class<?> targetClass = target.getClass();
               Method mtd = targetClass.getMethod(mtdName);
               mtd.invoke(target,config.getProperty(name));
           }
       }
   }

    public static void main(String[] args)throws Exception {
        ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();
        epf.init("com/gdut/test0516/extObj.txt");
        epf.initPool();
        epf.initProperty();
        System.out.println(epf.getObject("a"));
    }
}

图片 2

  3.4.3 访问成员变量

经过Class对象的getFields()方法及getField(Field)()方法好博得该类包含的具有成员变量和点名成员变量。Field提供如下方法读取或设置成员变量值

3.4.4 操作数组

当java.lang.reflect包下还提供了一个Array类,Array对象好代表享有的数组。程序可以通过利用该类来成立数组,操作数组元素等。

Array提供如下方法

 

Java程序可以动态扩充是出于运行期动态加载与动态链接实现之;比如:假设编写一个下接口的应用程序,可以等及运行时再也指定其实际的实现(多态),解析过程有时候还足以于起先化之后执行;比如:动态绑定(多态);

【类最先化】

(1)
遭逢new、getstatic、putstatic或invokestatic这4长字节码指令时,如果类似没有开展过初叶化,则用事先点发该初阶化。生成当下4修指令的绝广的Java代码场景是:使用new关键字实例化对象的当儿,读取或安装一个像样的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的上,以及调用一个接近的静态方法的下。

(2)
使用java.lang.reflect包的方对类举行映调用的早晚,倘诺类似没有展开过最先化,则需要先点发其开始化。

(3)
当开始化一个类的下,假使发现这父类还一向不进展了起始化,则要先点发那多少个父类的先导化。

(4)当虚拟机启动时,用户要指定一个若履行的主类(包含main()方法的坏看似),虚拟机会先初步化这些主类。

除非上述四种植情景会触发先导化,也号称对一个近似举行主动引用,除此之外,所有其他方法还无会见触发先导化,称为被动引用

代码清单1

图片 3

上述代码运行后,只会面输出【—SuperClass init】, 而休相会输出【SubClass
init】,对于静态字段,只有平素定义是字段的类似才会为起头化,由此,通过子类来调用父类的静态字段,只会合硌父类的起初化,不过这是假设扣不同的虚拟机的差实现。

代码清单2

图片 4

此处不会合挑起SuperClass的伊始化,不过也碰了【[Ltest.SuperClass】的先导化,通过arr.toString()能够见到,对于用户代码来说,这不是一个官的切近名称,它是由虚拟机自动生成的,直接接轨于Object的子类,创立动作由字节码指令newarray触发,此时数组越界检查也会陪伴数组对象的有调用过程,越界检查并无是封装于三番两回组元素访问的切近吃,而是包装在屡次组访问的xaload,xastore字节码指令中.

代码清单3

图片 5

本着常量ConstClass.value
的援实际还给转接为NotInitialization类对自常量池的援,这半单近乎吃编译成class后非在任何关联。

【装载】

以装等,虚拟机需要形成以下3件工作

(1) 通过一个看似的全限定名来取定义此类的老二向前制字节流

(2) 将这些字节流所表示的静态存储结构转化为方法区的周转时数据结构

(3)
在Java堆中变化一个意味着者看似的java.lang.Class对象,作为方法区这一个数量的访问入口。

虚拟机规范被并从未可靠表达二上制字节流应该从何地得到与怎么样拿到,这里可以经定义自己的切近加载器去控制字节流的获情势。

【验证】

虚拟机假设无检查输入的字节流,对该全倚重的话,很可能碰面因为载入了有害的字节流而导致系统奔溃。

【准备】

未雨绸缪阶段是规范为接近变量分配并安装类变量开始值的级差,那么些内存都拿当方法区中进行分红,需要声明的是:

这会儿举行内存分配的仅包括类变量(被static修饰的变量),而非包实例变量,实例变量将会当靶实例化时乘机对象同分配在Java堆着;这里所说的起先值“常常状态”是数据类型的零值,假若:

public static int value = 123;

value以准备等之后底初叶值为0假使休是123,而将value赋值的putstatic指令将当起始化阶段才汇合让实践

第二、类加载器与老人委派模型

接近加载器

(1) Bootstrap ClassLoader :
将存放于\lib目录中的,或者被-Xbootclasspath参数所指定的门路中的,并且是编造机识其余(仅以文件名识别,如
rt.jar
名字不抱的类库即便在lib目录中为未会见受加载)类库加载到虚拟机内存中。启动类加载器不能被Java程序直接引用

(2) Extension ClassLoader :
将\lib\ext目录下之,或者被java.ext.dirs系统变量所指定的门路中的备类库加载。开发者可以一直动用增加类加载器。

(3) Application ClassLoader :
负责加载用户类路径(ClassPath)上所指定的类库,开发者可径直利用。

图片 6

上下委派模型

干活过程:若是一个近似加载器接收至了看似加载的乞求,它首先把这些要委托为他的父类加载器去就,每个层次的接近加载器都是这样,因而有的加载请求都应传送到顶层的启动类加载器中,只有当父加载器反馈自己没辙做到这个加载请求(它在摸范围被绝非找到所要的近乎)时,子加载器才会师尝试自己去加载。

补:java类就她的类加载器一起有了扳平栽含有优先级的层次关系。例如类java.lang.Object,它存放于rt.jar中,无论哪个类加载器要加载是类似,最终还谋面委派给启动类加载器举行加载,因而Object类在程序的各个类加载器环境面临仍然和一个近乎。相反,假诺用户自己写了一个叫作吧java.lang.Object的近乎,并置身程序的Classpath中,这系统被以会见产出五只不同之Object类,java类型系列受到最好基础的作为也不知所可担保,应用程序也会更换得一样切片混乱。

java.lang.ClassLoader中多少个极端要的法子:

//加载指定名称(包括包名)的亚上制类型,供用户调用的接口

public Class loadClass(String name);

//加载指定名称(包括包名)的亚上前制类型,同时指定是否解析(但是,这里的resolve参数不必然真正能达解析的成效),供继承用

protected synchronized Class loadClass(String name, boolean resolve);

protected Class findClass(String name)

//定义类型,一般以findClass方法吃读取到对诺字节码后调用,可以望不可持续(表明:JVM已经落实了对应之现实性职能,解析对应的配节码,爆发相应之内数据结构放置到方法区,所以不必覆写,直接调用就足以了)

protected final Class defineClass(String name, byte[] b, int off, int
len) throws ClassFormatError{}

ClassFormatError{}如下是促成上下委派模型的要代码:

图片 7

三、反射

Reflection机制允许程序在正在举行的长河被,利用Reflection
APIs取得任何已知名称的类的里边音信,包括:package、 type parameters、
superclass、 implemented interfaces、 inner classes、 outer classes、
fields、 constructors、 methods、
modifiers等,并可以在实施之长河中,动态生成instances、变更fields内容要滋生methods。

1、获取构造方法

Class类提供了季只public方法,用于获取有类的构造方法。

Constructor getConstructor(Class[] params)

基于构造函数的参数,再次回到一个具体的兼具public属性的构造函数

Constructor getConstructors()

再次回到所有具有public属性的构造函数数组

Constructor getDeclaredConstructor(Class[] params)

遵照构造函数的参数,返回一个现实的构造函数(不分public和非public属性)

Constructor getDeclaredConstructors()

回该类中具有的构造函数数组(不分public和非public属性)

图片 8

2、获取类的成员方法

跟博构造方法的法同,存在四种植拿到成员方法的计。

Method getMethod(String name, Class[] params)

据悉方法名和参数,重临一个实际的有public属性的艺术

Method[] getMethods()

回来所有具有public属性的格局数组

Method getDeclaredMethod(String name, Class[] params)

冲方法名和参数,重临一个切实可行的办法(不分public和非public属性)

Method[] getDeclaredMethods()

重临该类中之具备的法门数组(不分public和非public属性)

图片 9

3、获取类的分子变量(成员属性)

存在四种植拿到成员属性之计

Field getField(String name)

基于变量名,再次回到一个具体的拥有public属性的成员变量

Field[] getFields()

回去具有public属性的积极分子变量的数组

Field getDeclaredField(String name)

依据变量名,再次来到一个分子变量(不分public和非public属性)

Field[] getDelcaredFields()

重返所有成员变量组成的数组(不分public和非public属性)

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图