类加载、反射

类的加载

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

加载

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

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

连接

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

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

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

初始化

初始化阶段,虚拟机负责对类的变量进行初始化

  • 声明类变量是指定初始值
  • 使用静态初始化块为类变量指定初始值

 

 Class类的初始化时机

Java虚拟机只有在程序首次主动使用一个类或接口的时候才会初始化它。只有6种活动被看作是程序对类和接口的主动使用

  1. 创建类的实例
  2. 调用类的静态方法
  3. 访问类或接口的静态变量,或者为静态变量赋值
  4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  5. 初始化某个类的子类
  6. 直接使用java.exe命令来运行某个主类

 

反射

JAVA反射机制是在运行状态中:

对于任意一个,都能够知道这个类的所有属性和方法

对于任意一个对象,都能够调用它的任意一个方法和属性

这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

 

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。

类也是一种类型

 

 

获取Class对象三种方式

 

 

方式一:调用Object类的getClass():任何类都会继承此方法

Person p = new Person();

Class c = p.getClass()

 

方式二:调用某个类的class属性来获取该类对应Class对象

Class s = Student.class

 

方式三:调用Class类的静态方法forName(String clazzName),参数的值是某个类的全限定类名(必须添加完整包名)

Class c3 = Class.forName("类的全限定类名");

 

目的:通过这个Class对象,可以获取Student类内部的成员属性、构造方法、成员方法的一些信息,并能够调用它们

 

学生类

class Student {
    // 成员变量
    public String name;
    public int age;
    private String address;

    // 构造方法
    public Student() {
        System.out.println("空参数构造方法");
    }

    public Student(String name) {
        this.name = name;
        System.out.println("带有String的构造方法");
    }

    // 私有的构造方法
    private Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("私有-------带有String,int的构造方法");
    }

    public Student(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
        System.out.println("带有String, int, String的构造方法");
    }

    // 成员方法
    // 没有返回值没有参数的方法
    public void m1() {
        System.out.println("没有返回值没有参数的方法");
    }

    // 没有返回值,有参数的方法
    public void m2(String name) {
        System.out.println("没有返回值,有参数的方法 name= " + name);
    }

    // 有返回值,没有参数
    public int m3() {
        System.out.println("有返回值,没有参数的方法");
        return 123;
    }

    // 有返回值,有参数的方法
    public String m4(String name) {
        System.out.println("有返回值,有参数的方法");
        return "哈哈" + name;
    }

    // 私有方法
    private void m5() {
        System.out.println("私有方法");
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", address=" + address + "]";
    }
}
学生类

 

通过反射获取构造方法

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

获取单个

Constructor getConstructor(Class ... parameterTypes):获取指定的"公有构造方法"

Constructor getDeclaredConstructor(Class ... parameterTypes):获取指定的构造方法(包括私有的)

批量获取构造方法

Constructor[] getConstructors() :获取所有的"公有构造方法"

Constructor[] getDeclaredConstructors() :获取全部(包括私有)的构造方法

暴力访问:如果想要访问私有成员,需要设置暴力访问

ConstructorsetAccessible(true):不进行权限检查

 

 通过反射方式创建对象(有构造)

步骤如下:

1. 获取到Class对象

2. 获取指定的构造方法

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

 

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
            InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        // 1. 获取到Class对象
        Class clazz = Class.forName("Student的全限定名");// 包名.类名
        // 2. 获取指定的构造方法
        Constructor c1 = clazz.getConstructor();

        // 相当于调用无参构造方法创建对象,返回Object类型的对象
        Object o1 = c1.newInstance();
    System.out.println("------------------------------------------");
        
        // 获取三个参数的构造方法
        Constructor c2 = clazz.getConstructor(String.class, int.class, String.class);
        // 调用三个参数的构造方法
        Object obj = c2.newInstance("小红", 22, "南京");
        // Student [name=小红, age=22, address=南京]
        System.out.println(obj);
    }
View Code

 

 

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

l 获取多个

Method[] getMethods():获取所有"公有方法"(包括继承的)

Method[] getDeclaredMethods() :获取所有成员方法(包括私有)

l 获取单个成员方法

Method getMethod(String name, Class... parameterTypes) :获取指定的"公有方法"

Method getDeclaredMethod(String name, Class... parameterTypes) :获取指定的方法,包括私有的

调用方法:(注意:1.要先创建此类的对象;2.调用私有方法前,要先设置暴力访问)

Method

Object invoke(Object obj, Object... args) :调用Method所代表的方法

返回值:此Method对象调用所代表的方法,所获取的返回值;

形参:

obj:方法所属对象;

args:Method所代表的那个方法的实参列表

 

posted @ 2020-06-30 17:05  飞力飞思  阅读(156)  评论(0编辑  收藏  举报