java基础——反射概念,类的加载过程

先定义一个Person类

package reflection;

public class Person {
    
    private String name;
    public int age;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Person() {
        super();
    }
    
    public Person(String name) {
        super();
        this.name = name;
    }
    public void show() {
        System.out.println("我是一个人");
    }
    private String showNation(String nation){
        System.out.println("我的国籍是"+nation);
        return nation;
    }
}

通过反射创建运行时类的对象

package reflection;

import org.junit.jupiter.api.Test;

/*
 * 通过反射创建对应的运行时类的对象
 * */

public class NewInstanceTest {
    
    @Test
    public void test1() throws InstantiationException, IllegalAccessException {//实例化异常, 权限异常
        Class<Person> clazz = Person.class;
        Object object = clazz.newInstance();
        System.out.println(object);
        
        /*
         * newInstance()创建对应的运行时 类的对象
         * 内部调用了空参数构造器
         * 要想此方法正常运行:1.运行时类必须提供空参数构造器,2.空参构造器的访问权限得够,通常设置为public
         *     因此在javabean中要求提供public 的空参构造器:1.便于反射创建运行时类对象 2.便于子类继承调用super()
         * */
        
        Person person = clazz.newInstance();//这儿直接能得到person类运行时类对象
        System.out.println(person);
    }
    
    @Test
    public void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String classPath = "";
        classPath = "java.util.Date";
        System.out.println(getInstance(classPath));
        classPath = "reflection.Person";
        System.out.println(getInstance(classPath));
    }
    //此方法创建一个指定全类名的实例
    public Object getInstance(String classPath) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class clazz = Class.forName(classPath);
        return clazz.newInstance();
    }
}

四种获得Class实例方式

/*    关于Class类的理解
     *         https://www.bilibili.com/video/av48144058?p=644
     *         1.类的加载过程:使用java.exe命令对某个字节码文件进行解释运行,
     *              相当于将某个字节码文件加载到内存中(jvm 的方法区,类的属性,构造器,方法都在此处),
     *              称为类的加载,加载到内存中的类,称其为运行时类
     *              此运行时类的信息被封装成一个对象,作为Class的一个实例clazz
     *         2.clazz对应着一个运行时类
     *         3.加载到内存中的运行时类,会缓存一定的时间之内,我们可以通过不同的方式获取此运行时类
     *         
     * */
    /*
     * 获取Class实例的四种方式
     * */
    @Test
    public void test3() throws ClassNotFoundException {
        //方式1:调用运行时类的属性;Class后面不加泛型也可以
        Class<Person> clazz1 = Person.class;
        System.out.println(clazz1);
        
        //方法2:通过运行时类的对象
        Person p1 = new Person();
        Class clazz2 = p1.getClass();
        System.out.println(clazz2);
        
        //方式3:调用Class静态方法forName(String classpath),classpath为类所在路径
        Class clazz3 = Class.forName("reflection.Person");
        System.out.println(clazz3);
    
        //方式4.使用类的加载器
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("reflection.Person");
        
        System.out.println(clazz1==clazz2);
        System.out.println(clazz1==clazz3);
        System.out.println(clazz1==clazz4);
    }
    
    /*
     * 
     * 任意类.class都可以是Class的对象
     * void,Object,Class...
     * */
    

} 

反射调用运行时类的属性,方法

@Test
    public void test1() throws Exception {
        Person p1 = new Person("Tom",12);
        
        //1.通过反射,创建Person类的对象
        Class clazz = Person.class;
        Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
        
        Object obj = cons.newInstance("Tom",12);
        Person p = (Person)obj;
        System.out.println(p.toString());
    
        //2.通过反射,调用对象指定的属性
        Field age = clazz.getDeclaredField("age");
        age.set(p, 10);
        System.out.println(p.toString());
    
        //3.通过反射,调用方法
        Method show = clazz.getDeclaredMethod("show");
        show.invoke(p);
        
        System.out.println("**********************************************************");
    }
    
    /*
     * 反射调用私有方法和属性
     * */
    @Test
    public void test2() throws Exception{
        try {
            //通过反射调用私有的方法和属性
            Class clazz = Person.class;
            //1.调用私有构造器
            Constructor cons1 = clazz.getDeclaredConstructor(String.class);
            cons1.setAccessible(true);
            Person person = (Person)cons1.newInstance("zsben");
            System.out.println(person);
                    
            //2.调用私有属性
            Field name = clazz.getDeclaredField("name");
            name.setAccessible(true);
            name.set(person, "Lilei");
            System.out.println(person);
                    
            //3.调用私有方法
            Method showNation =  clazz.getDeclaredMethod("showNation",String.class);
            showNation.setAccessible(true);
            showNation.invoke(person, "中国");
            
            //4.获得私有方法的返回值
            String string = (String)showNation.invoke(person, "中国");
            System.out.println(string);
        } catch (Exception e) {
        
            e.printStackTrace();
        }
    }

类的加载过程和类加载器

package reflection;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

import org.junit.jupiter.api.Test;
/*
 * 类的加载过程:
 *     1.类的加载:将类的class文件读入内存,并为之创建Class对象,此过程由类加载器完成
 *     2.类的链接:将类的二进制数据合并到JRE中,设置static变量的默认值(0,null,""等)
 *     3.类的初始化:JVM负责初始化,按顺序执行执行静态代码块和类属性的赋值
 * 
 * */


/*
 * 了解类的加载器
 * https://www.bilibili.com/video/av48144058?p=645
 * */

public class ClassLoaderTest {
    @Test
    public void test1() {
        //对于自定义类,得到ClassLoaderTest的类加载器:属于System Classloader,即系统类加载器
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);
        
        //调用系统类加载器的getParent().得到Extension Classloader,即扩展类加载器
        ClassLoader classLoader2 = classLoader.getParent();
        System.out.println(classLoader2);
        
        //Bootstap Classloader负责加载java核心类库,得不到了
        ClassLoader classLoader3 = classLoader2.getParent();
        System.out.println(classLoader3);
        
        //和3同理,String是java核心类库的
        ClassLoader classLoader4 = String.class.getClassLoader();
        System.out.println(classLoader4);
    }
    
    //读取读取配置文件
    @Test
    public void test4() throws Exception {
        //方式1
        Properties pros = new Properties();
        FileInputStream fis = new FileInputStream("jdbc.properties");
        pros.load(fis);
        
        String user = pros.getProperty("user");
        String passwd = pros.getProperty("password");
        System.out.println(user+passwd);
        
    }
        
}

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/12156926.html