zoukankan      html  css  js  c++  java
  • 类的加载器和反射

    类的加载

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

     加载

    就是指将class文件读入内存,并为之创建一个Class对象。

    任何类被使用时系统都会建立一个Class对象

      连接

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

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

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

    类的初始化时机

    1. 创建类的实例

    2. 类的静态变量,或者为静态变量赋值

    3. 类的静态方法

    4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

    5. 初始化某个类的子类

    6. 直接使用java.exe命令来运行某个主类

    类加载器:

    负责将.class文件加载到内存中,并为之生成对应的Class对象。

    类加载器的组成

    1.  Bootstrap ClassLoader 根类加载器

    也被称为引导类加载器,负责Java核心类的加载

    比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

    2. Extension ClassLoader 扩展类加载器

    负责JRE的扩展目录中jar包的加载。

    在JDK中JRE的lib目录下ext目录

    3.  System ClassLoader 系统类加载器

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

    反射

    Class类

     获取Class对象的三种方式

     

        //1通过Object类中的getObject()方法
            Person p=new Person();
            Class c=p.getClass();
            System.out.println(c);
            //2通过类名获取,类名.class 获取到字节码文件对象
            Class c1=Person.class;
            System.out.println(c1);
            System.out.println(c==c1);//true
            System.out.println(c.equals(c1));//true
            //3通过Class类的静态方法forName(包名.类名)获取
            Class c2 = Class.forName("com.oracle.DEMO.Person");// 包名.类名
            System.out.println(c2);

    Person类:

    package com.oracle.DEMO;
    
    public class Person {
        public String name;
        private int age;
        public Person(){
            System.out.println("公共构造方法");
        }
        public Person(String name,int age){
            this.name=name;
            this.age=age;
            System.out.println("公共有参构造");
        }
        private Person(int age,String name){
            this.name=name;
            this.age=age;
            System.out.println("私有有参构造");
        }
        public void eat(){
            System.out.println("公共方法");
        }
        public void sleep(String name){
            this.name=name;
            System.out.println(name+"公共有参方法");
        }
        private void playGames(){
            System.out.println("私有有参方法");
        }
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
        
    }

    通过反射获取构造方法并使用

      在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示。其中,构造方法使用类Constructor表示。可通过Class类中提供的方法获取构造方法:

     返回一个构造方法

       public Constructor<T> getConstructor(Class<?>... parameterTypes) 获取public修饰, 指定参数类型所对应的构造方法

       public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型所对应的构造方法(包含私有的)

      返回多个构造方法

        public Constructor<?>[] getConstructors() 获取所有的public 修饰的构造方法

        public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法(包含私有的)

    获取构造方法:

    //获取构造方法
        public static void method2() throws Exception{
            //获取字节码文件对象
            Class c = Class.forName("com.oracle.DEMO.Person");
            /*Constructor[] cons=c.getConstructors();
            //h=获取非私有构造方法数组
            for(Constructor con:cons){
                System.out.println(con);
            }*/
        /*    //获取空参构造
            Constructor con=c.getConstructor();
    //        System.out.println(con);
            //使用空参构造创建对象
            Object obj = con.newInstance();
            Person p=(Person)obj;
            p.eat();
    //        System.out.println(obj);
    */    
            /*//获取有参构造并调用
            Constructor con1 = c.getConstructor(String.class,int.class );
            Object obj = con1.newInstance("张三",13);
            System.out.println(obj);*/
            //针对空参构造有一个快捷创建对象的方式
            //1Person类中必须有空参构造方法
            //2.空参构造必须是public修饰’
            Object obj = c.newInstance();
            System.out.println(obj);
        }

    通过反射方式,获取构造方法(包括私有),创建对象

    public static void method3() throws Exception{
            Class c = Class.forName("com.oracle.DEMO.Person");
            /*//获得所有构造方法,包括私有
            Constructor[] con = c.getDeclaredConstructors();
            for(Constructor co:con){
                System.out.println(co);
            }*/
            //获取私有构造方法并使用
            Constructor con = c.getDeclaredConstructor(int.class,String.class);
            con.setAccessible(true);//取消Java检查,通过反射获取私有构造---暴力反射,不推荐使用
            //破坏了程序的封装性和安全性,好比抢银行
            Object obj = con.newInstance(13,"王五");
            System.out.println(obj);
            
        }

    通过反射,创建对象,获取指定的成员变量,进行赋值与获取值操作

      返回一个成员变量

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

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

      返回多个成员变量

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

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

    public static void method4()  throws Exception{
            Class c = Class.forName("com.oracle.DEMO.Person");
            Object obj = c.newInstance();
            //获取公共成员变量并使用
            /*Field field=c.getField("name");
            field.set(obj,"张三");*/
    //        System.out.println(obj);
            //获取私有成员并使用
            Field f=c.getDeclaredField("age");
            f.setAccessible(true);
            f.set(obj, 18);
            Field f1=c.getDeclaredField("name");
            f1.setAccessible(true);
            f1.set(obj, "小王");
            System.out.println(f.get(obj));
            System.out.println(f1.get(obj));
            
        }

    获取成员方法并使用:

        public static void method5()  throws Exception{
            //获取字节码文件对象
            Class c = Class.forName("com.oracle.DEMO.Person");
            Object obj = c.newInstance();
            //获取空参的成员方法 并运行
            Method method=c.getMethod("eat");
            method.invoke(obj);
            //获取有参成员方法并运行
            Method method1=c.getMethod("sleep",String.class);
            method1.invoke(obj,"张三");
            
        }

    泛型擦除

      程序编译后产生的.class文件中是没有泛型约束的,这种现象我们称为泛型的擦除。

    package com.oracle.DEMO;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    public class demo02 {
    
        public static void main(String[] args)throws Exception {
            //泛型擦除,泛型不进class文件
            ArrayList<String> arr=new ArrayList<String>();
            arr.add("1");
            Class c = arr.getClass();
            Method method1=c.getMethod("add",Object.class);
            
            method1.invoke(arr, 1.5);
            System.out.println(arr);
        }
    
    }

    反射配置文件

    测试类:

    package com.oracle.DeGai;
    
    import java.io.FileReader;
    import java.lang.reflect.Method;
    import java.util.Properties;
    
    public class Test {
    
        public static void main(String[] args) throws Exception {
    //        new Person().eat();
            //反射配置文件实现
            //把我们要运行的类和方法,以键值对的形式写在文本中
            //运行哪个类的方法,只需要改配置文件即可
            //1准备配置文件,键值对
            //2.IO读取配置文件,Reader
            //3.将文件中的键值对保存在Properties集合中,键值对,就i是类和方法名
            //4.通过反射获取指定类的class文件对象
            //5.通过class文件对象获取指定方法
            //6.运行方法
            FileReader fr=new FileReader("src/config.properties");
            Properties pro=new Properties();
            pro.load(fr);
            String className=pro.getProperty("className");
            String methodName=pro.getProperty("methodName");
            //获取字节码文件对象
            Class c = Class.forName(className);
            Object obj = c.newInstance();
            Method method=c.getMethod(methodName);
            method.invoke(obj);
        }
    
    }

    配置文件内容例子:

    className=com.oracle.DeGai.Student
    methodName=study
  • 相关阅读:
    Memcached简介
    TP5 volist
    Getting command line access to PHP and MySQL running MAMP on OSX
    PHP use
    PHP 命名空间(namespace)
    mac 使用 pf 做端口转发
    微信测试帐号如何设置URL和Token,以及相关验证的原理
    ionic开发笔记
    Eclipse下配置Maven
    css引用第三方字体库
  • 原文地址:https://www.cnblogs.com/lzw123-/p/9561531.html
Copyright © 2011-2022 走看看