类加载器,,,,,反射,,,,,泛型擦除,,,,, 反射配置文件

    类加载器

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

l  加载

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

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

l  连接

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

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

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

l  初始化

就是我们以前讲过的初始化步骤(进栈进堆调方法)

      类初始化时机(什么时候类进内存)

1. 创建类的实例(new类对象的时候,创建class文件对象)

2. 类的静态变量,或者为静态变量赋值(类名 . 静态成员变量或成员变量赋值时,进内存)

3. 类的静态方法(调用类的静态方法时进内存)

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

5. 初始化某个类的子类(初始化子类时,父类会进内存。因为构造方法先调super())

6. 直接使用java.exe命令来运行某个主类(main方法所在的类,主类)

//如何证明进内存:一进内存就会执行静态代码块

public class Demo01 {
public static void main(String[] args) {
    //System.out.println(Person.a);//先进内存再打印a
    //Person.aa();//先进内存再调方法
    new Person();//先父类进内存,再子类进内存
}
}
public class Person extends God{
    public static int a=1;
static{
    System.out.println("Person类进内存了");
}
public static void aa(){
    System.out.println("静态方法");
}

}
public class God {
static{
    System.out.println("父类进内存了");
}
}

      类加载器

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

      类加载器的组成

l  Bootstrap ClassLoader 根类加载器(已经写好的JDK中的类)

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

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

l  Extension ClassLoader 扩展类加载器

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

在JDK中JRE的lib目录下ext目录(jdk所依赖的jar包里面的类)

l  System ClassLoader 系统类加载器(我们自定义的类,以及导入jar包里面的类)

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

     反射

      Class类(字节码类)

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

l  获取Class对象的三种方式

方式一: 通过Object类中的getObject()方法

方式二: 通过 类名.class 获取到字节码文件对象(任意数据类型都具备一个class静态属性,看上去要比第一种方式简单)。

方式三: 通过Class类中的方法(将类名作为字符串传递给Class类中的静态方法forName即可)。

public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
    //获取Class字节码文件对象的方式
    Person p=new Person();
    Class c1=p.getClass();//person类的字节码文件对象
    System.out.println(c1);//公共空参构造(new调用构造方法执行的),class是Person类的字节码文件对象
    //Class属性获取
    Class c2=Person.class;
    System.out.println(c2);
    //System.out.println(c1==c2);获取只有一个,一个类的字节码文件只有一个
    //通过class。forname()
    Class c3=Class.forName("com.oracle.demo06.Person");//要加载类的完整包名+类名
    System.out.println(c3);
}
}
public class Person {
public String name;
private int age;
public Person(){
    System.out.println("公共空参构造");
}
public Person(String name){
    System.out.println("公共有参构造");
}
private Person(String name,int age){
    System.out.println("私有有参构造");
}
public void eat(){
    System.out.println("公共无参方法");
}
public void sleep(String name){
    System.out.println("公共有参方法");
}
public void smoke(int age){
    System.out.println("私有有参方法");
}

反射获取构造方法并使用

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

//构造方法封装成一个类

l  返回一个构造方法

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

//Class<?>字节码文件对象(参数写的啥就获取啥),... 可变参

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

l  返回多个构造方法

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

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

public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    //获取Person的字节码文件对象
    Class c=Class.forName("com.oracle.demo06.Person");
    //获取公共指定构造方法对象
    Constructor con=c.getConstructor(String.class);//完整报名+类名String.class
    System.out.println(con);//公共有参public修饰完整包名+类名,String类完整包名+类名
    //获取私有构造方法对象
    Constructor con2=c.getDeclaredConstructor(String.class,int.class);
    System.out.println(con2);
    //用公共构造方法对象创建Person对象
    //返回值Object类型
    Person p=(Person)con.newInstance("admin");
    p.eat();//调方法
    //用私有构造方法创建Person类对象
    //暴力反射(不提倡,破坏了面向对象封装)
    //con2.setAccessible(true);
    //不用暴力反射报错:不能被创建
    Person p2=(Person)con2.newInstance("小红",18);
    p2.eat();
}
}

Person类

public class Person {
public String name;
private int age;
public Person(){
    System.out.println("公共空参构造");
}
public Person(String name){
    System.out.println("公共有参构造");
}
private Person(String name,int age){
    System.out.println("私有有参构造");
}
public void eat(){
    System.out.println("公共wu参方法");
}
public void sleep(String name){
    System.out.println("公共有参方法");
}
public void smoke(int age){
    System.out.println("siyou有参方法");
}
}

    通过反射方式,获取构造方法,创建对象

获取构造方法,步骤如下:

1. 获取到Class对象

2. 获取指定的构造方法

3. 通过构造方法类Constructor中的方法,创建对象

public T newInstance(Object... initargs)

//1,获取到Class对象
        Class c = Class.forName("cn.oracle_01_Reflect.Person");//包名.类名
        //2,获取指定的构造方法
        //public Person()
        //Constructor con = c.getConstructor(null);
        
        //public Person(String name, int age, String address)
        Constructor con = c.getConstructor(String.class, int.class, String.class);
        
        //3,通过构造方法类中Constructor的方法,创建对象
        //Object obj = con.newInstance(null);
        Object obj = con.newInstance("小明", 22, "哈尔滨");
        
        //显示
        System.out.println(obj);

      通过反射获取成员变量并使用

在反射机制中,把类中的成员变量使用类Field表示。可通过Class类中提供的方法获取成员变量:

l  返回一个成员变量

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

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

l  返回多个成员变量

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

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

 

//通过反射获取成员变量并使用
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
    //获取Person类的字节码文件
    Class c=Class.forName("com.oracle.demo06.Person");
    //获取成员变量对象
    Field fl=c.getField("name");
    //System.out.println(fl);
    //快速创建对象,只能调用空参构造
    Person p=(Person)c.newInstance();
    fl.set(p,"小红帽");
    System.out.println(p.name);//获得成员变量
}
}

      通过反射获取成员方法并使用

在反射机制中,把类中的成员方法使用类Method表示。可通过Class类中提供的方法获取成员方法:

l  返回获取一个方法:

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

                           获取public 修饰的方法

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

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

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

l  返回获取多个方法:

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

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

        

//获取成员方法
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    //获取字节码
    Class c=Class.forName("com.oracle.demo06.Person");
    Method m=c.getMethod("sleep", String.class);//获取对象方法
    //快速创建对象
    Person p=(Person)c.newInstance();
    //调用方法
    m.invoke(p, "小红帽");
}
}

      泛型擦除

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

//泛型擦除,泛型不进class文件
public class Demo03 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    ArrayList<String> arr=new ArrayList<String>();
    arr.add("abc");
    //获取arr的字节码文件对象
    Class c=arr.getClass();
    //获取add的方法对象
    Method method=c.getMethod("add", Object.class);
    //调用方法:执行add()方法
    method.invoke(arr, 123);
    System.out.println(arr);
}
}

      反射配置文件

l  通过反射配置文件,运行配置文件中指定类的对应方法

读取Peoperties.txt文件中的数据,通过反射技术,来完成Person对象的创建

package com.oracle.demo08;

public class Worker {

    public void work(){
        System.out.println("工人工作");
    
}
}
public class Student {
public void study(){
    System.out.println("学生学习");
}
}
public class Doctor {

    public void job(){
        System.out.println("医生工作");
    
}
}
public class Demo01 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    //创建Properties集合对象
    Properties pro=new Properties();
    //创建输入流读取
    FileInputStream fis=new FileInputStream("src/com/oracle/demo08/pro.properties");
    pro.load(fis);//读到集合中
    //获取类名
    String className=pro.getProperty("className");
    String methodName=pro.getProperty("methodName");
    //反射获取字节码文件
    Class c=Class.forName(className);
    //获取方法对象
    Method m=c.getMethod(methodName);
    //快速创建对象
    Object obj=c.newInstance();
    //调用方法
    m.invoke(obj);
    
}
}

创建对象的三种方法:new,反序列,反射

原文地址:https://www.cnblogs.com/111wdh/p/13443377.html