类加载器
1.jvm用什么方式把class文件加载到内存中?
2.默认类加载器有哪几个,它们的关系是什么; 默认父加载器能不能加载子类加载器的Class
1.概述:
在jvm中,负责将本地上的class文件加载到内存的对象
2.分类:
1. BootstrapClassLoader 根类加载器-->C语言写的,我们获取不到
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。
jre/lib/rt.jar下的类都是核心类
2. ExtClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
3. AppClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包(第三方jar包)和类路径。或者自定义的类
关联: AppClassLoader的父加载器是ExtClassLoader
ExtClassLoader的父加载器是BootstrapClassLoader
但是他们不是子父类继承关系,他们有一个共同的爹-->ClassLoader
双亲委派作用
假如:ext和boot都不加载,app才会自己加载
class Test{
new Person()
}
a.AppClassLoader负责加载Test,然后按道理来讲Person也是由AppClassLoader加载到内存
但是App先不加载,先去找ExtClassLoader,Ext不负责加载自定义类,Ext就去找Boot
但是Boot只负责加载核心类,所以Boot也不加载
b.最后App看两个双亲不加载,自己就加载了Person
5.双亲委派作用:
能够让Class类加载一次
创建一个Class对象
/*
类名.class.getClassLorder()这个类的加载器
ClassLorder类的方法 getParent()返回父加载器
*/0
public class ClassLoader {
@Test
public void classLorder(){
//三个类加载器的关系
//父子关系
ClassLoader c1 = ClassLoader.class.getClassLoader();
System.out.println(c1);
ClassLoader c2 = c1.getParent();
System.out.println(c2);
ClassLoader c3 = c2.getParent();
System.out.println(c3);
}
//获取AppClassLoader 系统类加载器
@Test
public void app(){
//ClassLoader为本类类名
ClassLoader c1 = ClassLoader.class.getClassLoader();
System.out.println(c1);
}
//获取ExtClassLoader 扩展类加载器
@Test
public void ext(){
ClassLoader c1 = DNSNameService.class.getClassLoader();
System.out.println(c1);
}
//BootstrapClassLoader 根类加载器
@Test
public void boot(){
//引导类加载器,不是类,JVM内部,返回值null
ClassLoader cl = String.class.getClassLoader();
System.out.println(cl);
}
}
八:反射
根据JVM创建的Class对象去操作、解析Class对象中的成员,让代码灵活性强、扩展性强。
获取Class对象的三种方式:
Class.forName(类的全限定名)
类名.Class
对象.getClass()
Class文件加载几次?
Class对象又创建几次?
答案:1次-->由于类加载器的加载机制(双亲委派-->全盘负责委托机制)
三种方式谁最常用:
forName最常用:扩展性最好,灵活性最高
因为:forName方法参数为一个字符串,将来我们可以将字符串放在文件中,然后用IO读取
这个字符串,然后放在forName方法中,这样,我想获取不同的Class对象,直接改文件就可以了
不用修改源代码
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name){
this.name = name;
System.out.println("我是私有的构造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return name+"..."+age;
}
}
//测试类
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
//每个数据类型,不管基本还是引用数据类型,jvm都赋予了这个类型一个静态属性,名字叫class
Class aClass = Person.class;
Class aClass1 = Class.forName("cn.itcast.day15.class02.Person");
//Object类中的getClass方法
Person person = new Person();
Class aClass2 = person.getClass();
System.out.println(aClass==aClass1);
System.out.println(aClass==aClass2);
}
}
获取Class对象的构造方法
获取Class对象中的构造:
1. Constructor[] getConstructors()
获取所有的public修饰的构造方法
2. Constructor getConstructor(Class... parameterTypes)
根据参数类型获取构造方法对象,只能获得public修饰的构造方法。
如果只获取空参构造,getConstructor()
3.根据获取出来的构造方法对象,创建对象
T newInstance(Object... initargs)
如果new无参构造,参数不用写
public class Test02_Constructor {
public static void main(String[] args) throws Exception {
//获取Person的class对象
Class aClass = Class.forName("cn.itcast.day15.class02.Person");
method02_Constructor(aClass);
method03_ConstructorVar(aClass);
}
获取有参构造
private static void method03_ConstructorVar(Class aClass)throws Exception {
//获取有参构造
Constructor constructor = aClass.getConstructor(String.class, int.class);
//创建对象
Object o = constructor.newInstance("柳岩", 36);//Person person = new Person("柳岩", 36)
System.out.println(o);
}
//获取空参构造
public static void method02_Constructor(Class aClass) throws Exception{
//获取空参构造对象
Constructor constructor = aClass.getConstructor();
Object o = constructor.newInstance();//Person person = new Person()
System.out.println(o);
}
//获取类中所有的public的构造方法
public static Class method01_Constructors(Class aClass) throws ClassNotFoundException {
//获取Person的Class对象中的所有构造
Constructor[] constructors = aClass.getConstructors();
//遍历
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
return aClass;
}
}