类加载和反射

一、类加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象实例。Class对象封装了类在方法区内的数据结构,并且向Java程序提供了访问方法区内的数据结构的方法
类加载并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使用,那么累加载器就不会报告错误

  • 类加载的几个阶段

加载: 查找并加载类的二进制数据。(把类的.class文件的二进制数据读入内存,存放在运行时数据区的方法区;类加载的最终结果是产生 堆区中描述对应类的Class对象);

连接: 包括验证、准备和解析三个子阶段;

☞☞☞验证:确保补加载类的正确性;

☞☞☞准备:为类的静态变量分配内存,并设定默认值;

☞☞☞解析:把类中的符号引用转换为直接引用;

初始化: 给类中的静态变量赋予正确的初始值;

  • 类加载器
    Java虚拟机自带以下几种加载器:
    ☞☞☞启动(Bootstrap)类加载器: 没有父类加载器。负责加载虚拟机核心类,sun.boot.class.path路径下类库,java.lang.*; 实现依赖于底层操作系统,没有继承java.lang.ClassLoader;(系统提供的)
    ☞☞☞扩展(Extension)类加载器: 父加载器为根加载器;加载java.ext.dirs下的类库 和 JDK目录下jre/lib/ext目录下类库;继承于java.lang.ClassLoader;
    ☞☞☞应用程序(Application)类加载器: 也称应用类加载器,父加载器为扩展类加载器;加载classpath路径下指定的类库;继承于java.lang.ClassLoader,也是自定义加载器的默认父类;(自己写的类
  • 反射—获取字节码文件对象的三种方式
    一个类的组成部分
  • 构造方法
  • 成员方法
  • 成员变量
    想要通过一个字节码文件获取里面的上述成员,必须先将字节码文件转换成字节码文件对象
    获取字节码文件对象的三种方式:
  • Class clazz = Person.class
  • Person p = new Person(); Class clazz2 = p.getClass()
  • Class clazz3 = Class.forName(“类路径”);(开发中最常用

代码实现:

package cn.edu360;

public class ReflectDemo {

	public static void main(String[] args) throws Exception {
		//①
		Class clazz = Person.class;
		//②
		Person p = new Person();
		Class clazz2 = p.getClass();
		//③
		Class clazz3 = Class.forName("cn.edu360.Person");
		
		System.out.println(clazz == clazz2);//true
		System.out.println(clazz == clazz3);//true
	}
}

Person.java

package cn.edu360;

public class Person{
	
	private String name;
	private int age;
	private String address;
	private char sex;
	
	public Person() {
		
	}
	Person(String name, int age){
		this.name = name;
		this.age = age;
	}
	private Person(String name,char sex){
		this.name = name;
		this.sex = sex;
	}
	public void show(){
		System.out.println("show");
	}
	protected void test(String msg){
		System.out.println(msg);
	}
	int getNum(int a, int b){
		return a+b;
	}
}
  • 获取构造方法并创建对象
    访问所有的构造方法,方法比较多,开发中最常用的就一个
  • public Constructor getDeclaredConstructors(相应参数)
  • public void setAccessible(boolean flag)值为true则取消java语法检查
    注意事项:构造方法对象一般是用来创建对象的

代码实现:

package cn.edu360;

import java.lang.reflect.Constructor;

public class ReflectConstructor {

	public static void main(String[] args) throws Exception {
		Class clazz = Class.forName("cn.edu360.Person");
		Constructor c = clazz.getDeclaredConstructor(String.class, char.class);
		c.setAccessible(true);//暴力反射
		Object object = c.newInstance("王五",'男');
		System.out.println(object);
	}
}

Person.java

package cn.edu360;

public class Person{
	
	private String name;
	private int age;
	private String address;
	private char sex;
	
	public Person() {
		
	}
	Person(String name, int age){
		this.name = name;
		this.age = age;
	}
	private Person(String name,char sex){
		this.name = name;
		this.sex = sex;
	}
	public void show(){
		System.out.println("show");
	}
	protected void test(String msg){
		System.out.println(msg);
	}
	int getNum(int a, int b){
		return a+b;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", address=" + address
				+ ", sex=" + sex + "]";
	}
}
  • 获取成员方法对象并使用
  • public Object invoke(Object obj, Object … args)该方法对象想在obj对象上面调用,参数为args
    obj-------从中调用底层方法的对象
    args-----用于方法调用的参数

案例展示:

package cn.edu360;

import java.lang.reflect.Method;

public class ReflectConstructor {

	public static void main(String[] args) throws Exception {
		Class clazz = Class.forName("cn.edu360.Person");
		Method method = clazz.getDeclaredMethod("show2", String.class);
		method.setAccessible(true);//暴力反射,取消java语法检查
		Object result = method.invoke(clazz.newInstance(), "我是结果");
		System.out.println(result);
	}

}
  • 注册与登录图解说明
    类加载和反射_第1张图片

你可能感兴趣的:(温习基础)