Java-37 类加载器,反射,配置文件,动态代理

一、类加载器

1、类的加载:

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

2、加载:

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

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

3.连接:

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

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

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

4、初始化

5、类初始化时机

  创建类的实例

  访问类的静态变量,或者为静态变量赋值

  调用类的静态方法

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

  初始化某个类的子类

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

6、类加载器

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

  虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。

  1、类加载器的组成

    1、Bootstrap ClassLoader 根类加载器

    2、Extendsion ClassLoader 扩展类加载器

    3、System ClassLoader 系统类加载器

  2、类加载器的作用

    Bootstrap ClassLoader 根类加载器

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

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

    Extendsion ClassLoader 扩展类加载器

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

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

    System ClassLoader 系统类加载器

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

如何使用累加器产生的.class文件呢?

那就是:反射

1、概念:JAVA反射机制时在运行状态中,对任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法对的功能称之为Java语言的反射机制。

就是将类的各个组成部分封装成其他对象

2、反射的好处:

  1、可以在程序运行过程中,操作这些对象

  2、可以解耦,提高程序的可扩展性

3、获取class对象的方式:

一般我们到底使用谁呢?

  注意,一般我们自己学习或者练习的时候,任选一种,但是,实际开发过程中,我们选择第三种,因为第三种传的是一个字符串,而不是一个具体的类名,这样我们就可以把这样的字符串配置到配置文件中。

public class ReflexDemo {
    public static void main(String[] args) throws Exception {
        //学习反射之前
//        Person person = new Person();
//        person.show();

        //1.Class.forName("全类名")
        Class cls = Class.forName("shujia.day1.day26.Person");
        System.out.println(cls);//class shujia.day1.day26.Person

        //2.类名.class
        Class cls2 = Person.class;
        System.out.println(cls2);//class shujia.day1.day26.Person

        //3.对象.class
        Person person = new Person();
        Person person1 = new Person();
        Class cls3 = person.getClass();
        Class<? extends Person> cls4 = person1.getClass();
        System.out.println(cls);//class shujia.day1.day26.Person
        System.out.println(cls3 == cls4);//true
        System.out.println(person == person1);//false
        //比较三个对象
        System.out.println(cls == cls2);//true
        System.out.println(cls == cls3);//true
        //说明同一段字节码文件在程序运行过程中,只会加载一次,不论通过哪种方法获取class对象
    }
}

Person类

public class Person {
    private String name;
    int age;
    public String address;

    public Person() {

    }

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

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

    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public void show() {
        System.out.println("这是公共的show方法");
    }

    public String getString(String s, int i) {
        return s + "---" + i;
    }

    void fun(String name) {
        System.out.println("姓名是:" + name);
    }

    private void fun2(int age) {
        System.out.println("这是私有的fun2方法 " + age);
    }

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

Class文件中成员

成员变量: Field

成员方法:Method

构造方法: Constructor

反射的获取功能

获取构造方法并使用

//通过反射创建对象并使用反射调用方法
        Constructor<?> cons = c.getConstructor();
        Object o = cons.newInstance();

测试类:

import java.lang.reflect.Constructor;

/*
如何通过反射获取的class文件对象来创建该类的对象呢?
            获取class文件中的构造方法
 */
public class ReflexDemo1 {
    public static void main(String[] args) throws Exception {
        //获取class文件对象
        Class<?> c1 = Class.forName("shujia.day1.day26.Person");

        //public Constructor<?>[] getConstructors()
        //返回一个包含Constructor对象的数组,
        // 反映由此Constructor对象表示的类的所有公共类函数。
        //不包括获取私有的,默认的修饰构造方法
        Constructor<?>[] constructors = c1.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("--------------------------------------------");
        //public Constructor<?>[] getDeclaredConstructors()
        //返回反映Constructor对象表示的类声明的所有Constructor对象的数组类 。
        //获取所有的构造方法,包括私有,该方法,打破了原先私有构造方法不能创建对象的隔阂
        Constructor<?>[] declaredConstructors = c1.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        System.out.println("------------------------------------------");
        //获取单个的构造方法
        //public Constructor<T> getConstructor(Class<?>... parameterTypes)
        //返回一个Constructor对象,该对象反映Constructor对象表示的类的指定的公共类函数。
        Constructor<?> constructor = c1.getConstructor();
        System.out.println("获取无参构造方法:" + constructor);
        Constructor<?> constructor1 = c1.getConstructor(String.class, int.class, String.class);
        System.out.println("获取带参数的构造方法:" + constructor1);
        System.out.println("--------------------------------------------------");
        //public Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
        //返回一个Constructor对象,该对象反映Constructor对象表示的类或接口的指定类函数
        Constructor<?> declaredConstructor = c1.getDeclaredConstructor(String.class);
        System.out.println("获取私有的带参数的构造方法:" + declaredConstructor);
        System.out.println("-----------------------------------------------");

        //获取构造方法的目的是创建对象
        //public T newInstance(Object... initargs)
        //对象表示的构造函数,使用指定的初始化参数创建和初始化构造函数的声明类的新实例。
        Object o = constructor.newInstance();
        System.out.println(o);
//        Person p = (Person)o;
//        System.out.println(p);

        //在通过使用获取到私有的构造方法创建对象的时候,报错了,非法访问异常
        //java.lang.IllegalAccessException
        //暴力访问
        declaredConstructor.setAccessible(true);
        Object o1 = declaredConstructor.newInstance("小草");
        System.out.println(o1);

    }
}

获取成员变量并使用:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/*
 通过反射获取成员变量并使用
 */
public class ReflexDemo2 {
    public static void main(String[] args) throws Exception {
        //获取class文件对象
        Class<?> cls = Class.forName("shujia.day1.day26.Person");

        //获取所有的(public修饰的)公共成员变量
        Field[] fields = cls.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("---------------------------------");

        //获取指定(public修饰的)成员变量
        Field address = cls.getField("address");

        //通过反射获取无参构造方法,然后再通过反射一个一个成员变量进行赋值
        Constructor<?> cons = cls.getConstructor();
        Object o = cons.newInstance();
        System.out.println(o);//Person{name='null', age=0, address='null'}
        //获取单个的成员变量
        //public Field getField(String name)
        //返回一个Field对象,它反映此表示的类或接口的指定公共成员字段类对象。
        //name - 字段名称
        Field a = cls.getField("address");
        //Field类中有一个方法可以给成员变量进行赋值
        //void set(Object obj, Object value)
        //将指定对象参数上的此 Field对象表示的字段设置为指定的新值。
        a.set(o,"合肥");
        System.out.println(o);//Person{name='null', age=0, address='合肥'}
        //public Field[] getDeclaredFields()
        //获取所有的成员变量,包括公共,受保护,默认(包)访问和私有字段
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName());
        }

        //public Field getDeclaredField(String name)
        //返回一个Field对象,它反映此表示的类或接口的指定已声明字段类对象。
        Field name = cls.getDeclaredField("name");
        //java.lang.IllegalAccessException
        //暴力访问
        name.setAccessible(true);
        name.set(o,"张三");
        System.out.println(o);//Person{name='张三', age=0, address='合肥'}

        //获取age这个成员变量并赋值
        Field age = cls.getDeclaredField("age");
        age.set(o,18);
        System.out.println(o);//Person{name='张三', age=18, address='合肥'}
    }
}

 

获取成员方法并使用  

测试类:

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/*
 通过反射获取成员方法并使用
 */
public class ReflexDemo3 {
    public static void main(String[] args) throws Exception {
        //获取字节码文件对象
        Class<?> c = Class.forName("shujia.day1.day26.Person");

        //通过反射创建对象并使用反射调用方法
        Constructor<?> cons = c.getConstructor();
        Object o = cons.newInstance();
        
        
        //获取所有的成员
        //public 方法[] getMethods()
        //返回包含一个数组方法对象反射由此表示的类或接口的所有公共方法类对象,
        // 包括那些由类或接口和那些从超类和超接口继承的声明。
        //获取的是所有公共的方法,不光获取的是自己的公共方法,还包括父类的
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("------------------------");

        //public 方法[] getDeclaredMethods()
        //返回包含一个数组方法对象反射的类或接口的所有声明的方法,通过此表示类对象,
        // 包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。
        //只能获取自己的所有方法,包括私有的
        Method[] declaredMethods = c.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        System.out.println("------------------------");

        //获取show方法并调用
        //public 方法 getMethod(String name,类<?>... parameterTypes)
        //返回一个方法对象,它反映此表示的类或接口的指定公共成员方法类对象。
        //注意:只写方法名,不写小括号
        Method show = c.getMethod("show");
        System.out.println(show);//public void shujia.day1.day26.Person.show()
        System.out.println("=============================");
        //Object invoke(Object obj, Object... args)
        //在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。
        show.invoke(o);//调用对象o中show方法

        System.out.println("------------------------");
        //java.lang.NoSuchMethodException
//        Method fun2 = c.getMethod("fun2");
        Method fun2 = c.getDeclaredMethod("fun2",int.class);
        //java.lang.IllegalAccessException
        //暴力访问
        fun2.setAccessible(true);
        fun2.invoke(o,18);

        System.out.println("------------------------");
        Method fun = c.getDeclaredMethod("fun", String.class);
        fun.invoke(o,"小花");

    }
}

 

 

 

 

 

 

配置文件(Properties集合)

properties类表示一个持久的属性,Properties可保存流中或从流中加载

Properties集合是唯一和IO流相结合的集合

  可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到流中存储

  可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用

属性列表中每个键及其对应值都是一个字符串

  Properties集合是一个双列集合,key和value默认字符串

import java.util.Properties;
import java.util.Set;

/*
       使用Properties集合存储数据,遍历取出Properties集合中的数据
       Properties集合是一个双列集合,key和value默认都是字符串
       Properties集合操作字符串特有的方法
           public Object setProperty(String key,String value)调用Hashtable方法put 。
           public String getProperty(String key) 通过key找到value,此方法相当于map集合中的get(key)方法
           public Set<String> stringPropertyNames()返回此属性列表中的一组键,相当于map集合中的keyset方法
        */
public class PropertiesText {
    public static void main(String[] args) {
        show1();
    }

    private static void show1(){
        //创建properties集合
        Properties prop = new Properties();
        //使用setProperties往集合中添加数据
        prop.setProperty("翔阳","18");
        prop.setProperty("影山","18");
        prop.setProperty("研磨","18");
        //使用String getProperty(String key)把集合中的键取出,存储在set集合中
        Set<String> set = prop.stringPropertyNames();
        //遍历set
        for (String key : set) {
            //使用getProperty(String key) 通过key找到value
            String value = prop.getProperty(key);
            System.out.println(key+"----"+value);
        }
    }
}

 

 可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到流中存储

import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

/*
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到流中存储
使用步骤:
1、创建Properties集合,添加数据
2、创建字节输出流/字符输出流,构造方法中绑定要输出的目的地
    注意:字符流可以写中文,字节流不能写中文
3、使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
4、释放资源
 */
public class PropertiesText2 {
    public static void main(String[] args) throws IOException {
        show1();
    }

    private static void show1() throws IOException {
        //创建properties集合
        Properties prop = new Properties();
        //使用setProperties往集合中添加数据
        prop.setProperty("翔阳","18");
        prop.setProperty("影山","18");
        prop.setProperty("研磨","18");

        //创建字节输出流/字符输出流,构造方法中绑定要输出的目的地
        FileWriter fw = new FileWriter("prop.txt");
        //使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
        prop.store(fw,"save data");

        //释放资源
        fw.close();
    }
}

 

 

 可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用

 

import java.io.FileReader;
import java.util.Properties;
import java.util.Set;

public class PropertiesText3 {
    public static void main(String[] args) throws Exception {
        show1();
    }

    private static void show1() throws Exception {
        //创建properties集合
        Properties prop = new Properties();
        //使用Properties集合对象中的方法load读取键值对文件
        prop.load(new FileReader("prop.txt"));

        //遍历集合
        Set<String> set = prop.stringPropertyNames();
        for (String key : set) {
            String value = prop.getProperty(key);
            System.out.println(key+"="+value);
        }
    }
} 

text文件

 

 

 

posted @ 2021-10-28 19:55  艺术派大星  阅读(134)  评论(0)    收藏  举报
levels of contents