Java反射1.类加载器概述与获取class文件对象的三种方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cmm0401/article/details/82829766

类加载器概述

一、类的加载

(1)类的加载

  • 当Java程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三步来实现对这个类进行初始化。
  • 加载:就是指将类的class文件读入内存,并为之创建一个Class对象。任何类被使用时,系统都会建立一个Class对象。
  • 连接
    • 验证:是否有正确的内部结构,并和其他类协调一致。
    • 准备:负责为类的静态成员分配内存,并设置默认初始化值(类的静态成员随着类的加载而加载)。
    • 解析:将类的二进制数据中的符号引用替换为直接引用。
  • 初始化:就是以前接触过的普通的初始化步骤。

二、类的初始化时机

(1)类的初始化时机:类在什么时候做初始化工作呢?

  • 创建类的实例的时候
  • 访问类的静态变量,或者为静态变量赋值的时候
  • 调用类的静态方法的时候
  • 使用反射方式来强制创建某个类或接口对应的 java.lang.Class 对象的时候
  • 初始化某个类的子类的时候(先有父类才能有子类)
  • 直接使用 java.exe 命令来运行某个主类的时候

三、类加载器

(1)类加载器的作用:

  • 负责将 .class文件 加载到内存中,并为之生成对应的Class对象。
  • 虽然我们不需要关心类加载机制,但是了解这个类加载机制我们就能更好的理解程序的运行。

(2)类加载器的组成:

  • Bootstrap ClassLoader根类加载器
    • 也被称为引导类加载器,负责Java核心类的加载,比如System,String等。在JDKJRElib目录下rt.jar文件中。
  • Extension ClassLoader扩展类加载器
    • 负责JRE的扩展目录中jar包的加载。在JDKJRElib目录下的ext目录中。
  • System ClassLoader系统类加载器
    • 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。

(3)通过这些描述,我们就可以知道我们常用的东西的加载都是由谁(系统类加载器)来完成的。到目前为止,我们已经知道把class文件加载到内存中了,那么,如果我们仅仅站在这些class文件的角度,我们该如何来使用这些class文件中的内容呢这就是反射要研究的内容。

四、反射

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

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

/*
 * 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
 * Person p = new Person();
 * p.使用
 * 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。
 * Class类:
 *         成员变量    ——>    Field 类    ——>    调用类的方法来获取成员变量
 *         构造方法    ——>    Constructor 类    ——>    调用类的方法来获取构造方法
 *         成员方法    ——>    Method 类    ——>    调用类的方法来获取成员方法

 * 获取class文件对象的方式:
 * A: Object类的 getClass() 方法。 通过对象名:Person p = new Person();  Class c = p.getClass();
 * B: 数据类型的静态属性 class。  通过类名:Class c2 = Person.class;    任意数据类型都具备一个class静态属性,看上去要比第一种方式简单。
 * C: Class类中的静态方法:public static Class forName(String className)。将全路径类名作为字符串传递给Class类中的静态方法forName即可:Class c3 = Class.forName("cn.itcast_01.Person");
 *
 * 一般我们到底使用谁呢?
 *         A:自己玩    任选一种,第二种比较方便
 *         B:开发    第三种:为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。

 */

五、获取class文件对象的三种方式

1、获取class文件对象的三种方式举例

(1)Person类

package cn.itcast_01;
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 void method(String s) {
		System.out.println("method " + s);
	}
	public String getString(String s, int i) {
		return s + "---" + i;
	}
	private void function() {
		System.out.println("function");
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", address=" + address
				+ "]";
	}
}

(2)获取class文件对象的三种方式

package cn.itcast_01;
public class ReflectDemo {
	public static void main(String[] args) throws ClassNotFoundException {
		// 获取方式1
		Person p = new Person();
		Class c = p.getClass();
		Person p2 = new Person();
		Class c2 = p2.getClass();
		System.out.println(p == p2);// false
		System.out.println(c == c2);// true
		// 获取方式2
		Class c3 = Person.class;
		// int.class;
		// String.class;
		System.out.println(c == c3);// true
		// 获取方式3
		// ClassNotFoundException
		Class c4 = Class.forName("cn.itcast_01.Person");
		System.out.println(c == c4);// true
	}
}

猜你喜欢

转载自blog.csdn.net/cmm0401/article/details/82829766