类的加载机制和反射机制
- 类加载机制的原理?
- 有哪些类加载器?
- 获得Class对象的几种方式?
- 如何通过Class对象获得构造方法对象?
- 如何通过构造方法对象实例化?
1.类加载机制的原理?
1)启动JVM
2)将需要运行的class文件加载到虚拟机内存中
3)找到主类,开始执行主函数
2.有哪些类加载器?
class文件是如何被加载到JVM内存中的?
通过类加载器将class文件加载到JVM内存中
类加载器:ClassLoader
AppClassLoader 应用类加载器,负责加载核心类,加载自己写的类
ExtClassLoader 扩展类加载器,负责加载扩展类库
bootstrap JVM内置的加载器
Bootstrap类加载器是JVM的一部分,是由C++编写的,
随着启动虚拟机就会创建一个bootstrap类加载器对象
加载步骤:
1)先委托父类加载类,如果父类已经加载,就不需要再次加载,如果父类没有加载,再由本加载器加载
为什么要先委托父类加载类?
MyClassLoader 自定义类加载器
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
/**
* 自定义类加载器移除先委托父类加载类的功能
*/
public class MyClassLoader extends ClassLoader{
//class文件的根路径
String parent="D:\idea11\untitled\类的加载机制和反射机制";
//加载Class对象的方法
public Class<?> findClass(String name){
Class c=null;
try {
//先委托给父类加载器加载
c = super.loadClass(name);
//如果父类加载器未加载
if(c==null) {
byte[] bs = loadClassData(name);
c = this.defineClass(name, bs, 0, bs.length);
}
}catch (Exception ef){
ef.printStackTrace();
}
return c;
}
//根据类名来从class文件中读取字节数据
//com.newer.test.Student
private byte[] loadClassData(String name){
//将类类路径解析为文件路径
name = name.replace(".","\\");
name = name+".class";
String path = parent+"\\"+name;
try {
//建立文件字节输入流
FileInputStream fis = new FileInputStream(path);
//创建一个字节数组输出流来缓存读入的数据
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int t = fis.read();
while(t!=-1){
bos.write(t);
t = fis.read();
}
//将字节数组输出流转换成字节数组
byte[] bs = bos.toByteArray();
fis.close();
bos.close();
return bs;
}catch (Exception ef){
ef.printStackTrace();
}
return null;
}
}
测试类
输出结果
出现了学生不是学生的情况
因为加载了2次中Student是系统的Student
自动加载器解决方法:
2)解析类路径,将类路径转换成文件路径
3)通过文件输入流来读取class文件,得到字节数组
4)将字节数组转换成类对象,对象的类型是Class类型
任何一个类都只能被加载一次
每一个class文件读取到JVM内中之后,都转换成了一个Class对象
3.获得Class对象的几种方式?
获得Class对象的几种方式
//1.通过类名.class
Class c1 = Student.class;
//2.通过对象的getClass()方法
Class c2 = stu.getClass();
//3.通过类加载器获得class对象
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Class c3 = classLoader.loadClass(“com.newer.test.Student”);
//4.通过 Class.forName()获得Class对象;
Class c4 = Class.forName(“com.newer.test.Student”);
MainClass 对象获得class
public class MainClass {
public static void main(String[] args) throws Exception {
Student student = new Student();
//获得Student的Class对象
//1.通过类名.class
Class c1 = Student.class;
//2.通过对象的getClass()方法
Class c2 = student.getClass();
//3.通过类加载器获得class对象
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class c3 = loader.loadClass("text.Student");
//4.通过 Class.forName()获得Class对象;
Class c4 = Class.forName("text.Student");
System.out.println(c1 == c2);
System.out.println(c2 == c3);
System.out.println(c3 == c4);
}
}
输出结果
数组类型的Class对象
数组与二维数组不是同一个class
第一种方式,类型.class
Class c1 = int[].class;
Class c2 = long[].class;
System.out.println(c1);
System.out.println(c2);
System.out.println(c1==c2);
输出结果
第二种方式 数组对象
int[] a = {1,2,3,4,5,6};
Class c3 = a.getClass();
基本数据类型类型的Class对象
类型.class
Class c5 = int.class;
Class c6 = long.class;
System.out.println(c5==c6);
包装类的Class对象
第一种方式 类型.class
第二种方式 类型.TYPE
Class c5 = int.class;
Class c8 = Integer.TYPE;
System.out.println(c5==c8);
输出结果:
为什么Interger.TYPE和int.class相等?
Interger.TYPE获得的是int的class
拿到包装类对应的基本类型的Class对象
4.如何通过Class对象获得构造方法对象?
反射机制
1.为什么需要获得Class对象
程序在运行时能够动态的获得类的相关信息的机制,叫做反射机制
正着走:先拿到类的信息,再使用这个类
反着走:先使用这个类,再拿到类的信息
类的所有信息都在Class对象中
Class类的反射机制中的核心类
如何拿到JVM内存中的class文件的数据?
Student类
package text;
public class Student {
private int age;
private String name;
private int num;
public Student() {
}
private Student(int age) {
this.age = age;
}
public Student(int age, String name, int num) {
this.age = age;
this.name = name;
this.num = num;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", num=" + num +
'}';
}
}
//1.获得所有可见的构造方法
Constructor[] cons= c.getConstructors();
//加载类,获得类的Class对象
Class c = Class.forName("text.Student");
//通过Class对象获得类的信息
//1.获得所有可见的构造方法
Constructor [] cons = c.getConstructors();
for (Constructor con : cons){
System.out.println(con);
}
输出结果
//2.获得所有已经声明的构造方法
Constructor[] cons2= c.getDeclaredConstructors();
//2.获得所有已经声明的构造方法
Constructor [] cons2 =c.getDeclaredConstructors();
for (Constructor con : cons2){
System.out.println(con);
}
输出结果:
//3.获得指定的可见的某一个构造方法
Constructor cc = c.getConstructor(int.class,String.class,int.class);
不定项参数的方法
//一个方法中只能有一个不定项参数
//不定项参数必须是最后一个参数
public static void test(int a,int…t){
}
//3.获得指定的可见的某一个构造方法
Constructor con1=c.getConstructor(int.class,String.class,int.class);
System.out.println(con1)
输出结果:
如果用此方法调用私有的构造方法?
输出结果:
//4.从声明的方法中获得指定的构造方法
Constructor cc2 = c.getDeclaredConstructor(int.class);
Constructor con2=c.getDeclaredConstructor(int.class);
System.out.println(con2);
输出结果:
5.如何通过构造方法对象实例化?
//通过构造方法对象得到类的实例对象
Object obj = con1.newInstance(22,"张三",18);
System.out.println(obj);
输出结果:
//通过私有构造方法实例化对象
//设置允许访问私有构造方法
con2.setAccessible(true);
Object obj2 = con2.newInstance(11);
System.out.println(obj2);
输出结果: