1. 类加载器
我们程序猿编写的是java文件,编译之后就是class文件,但并不是编译完成之后就能用了,具体的使用,得加载到虚拟机中运行,那么从硬盘到虚拟机内存中的这个步骤,就会使用到这边的类加载器!
1.1 类加载时机
一句话概括就是你用到的时候,他才会把class文件放入内存。那具体是什么时机呢?
- 你new 一个对象的时候
- 调用静态方法或者调用静态变量,也就是当你用类名直接点方法,或者点具体的变量的时候。
- 反射,强制创建一个对象。
- 创建子类的时候,父类也会被创建
- 通过java.exe 运行某个类的时候
1.2 类加载过程
1.3 类加载器种类
了解一下就好分别是启动类加载器、平台类加载器、系统类加载器、除此之外我们这也可以自定义加载器,而我们用的最多的其实就是这个系统类加载器。这些加载器能加载的范围不一样。
代码看一下,比较特殊的就是启动类是null,null就是他的地址。这边还有个方法就是通过类加载器去加载文件,注意这个文件是在src目录下的。
public static void main(String[] args) throws IOException {
//系统类加载器
ClassLoader classloader1 = ClassLoader.getSystemClassLoader();
//平台类加载器
ClassLoader parent = classloader1.getParent();
//启动类加载器
ClassLoader parent1 = parent.getParent();
System.out.println(classloader1);
System.out.println(parent);
System.out.println(parent1);
InputStream resourceAsStream = classloader1.getResourceAsStream("test.properties");
Properties pp = new Properties();
pp.load(resourceAsStream);
System.out.println(pp);
resourceAsStream.close();
}
2. 反射
?我直接形容一下使用到反射的场景,我们一般创建对象都是通过new ,但试想一种场景,我编写好了100个类,我现在还没想好运行哪一个类的哪一个方法,怎么办?我编写代码的时候我也不知道我会用到具体哪个类,具体哪个方法。那么这个时候就需要用到动态配置,到时候运行的时候我改一下配置文件,我想运行哪个类就运行哪个类,想用哪个方法用哪个方法岂不美哉?反射就可以实现。下面代码见。
2.1 获取class 对象(3种方式)
public static void main(String[] args) throws ClassNotFoundException {
//第一种方式
Class<?> aClass = Class.forName("com.yxlm.dmxy.Yasuo");
//第二种方式
Class<Yasuo> aClass1 = Yasuo.class;
//第三种方式
Yasuo yasuo = new Yasuo();
Class<? extends Yasuo> aClass2 = yasuo.getClass();
//这边注意一下 aClass==aClass1==aClass2 这三个都是相等的
}
2.2 获取类的属性
一个class有三大属性,field 是成员变量,construct是构造方法,method 是成员方法。
2.2.1 获取构造方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//第一种方式
Class<?> aClass = Class.forName("com.yxlm.dmxy.Yasuo");
//获取所有公有的构造方法 public 修饰的
Constructor<?>[] constructors = aClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("getConstructors"+constructor);
}
//获取所有构造方法
Constructor<?>[] constructorsAll = aClass.getDeclaredConstructors();
for (Constructor constructor : constructorsAll) {
System.out.println("getDeclaredConstructors"+constructor);
}
//根据入参返回具体构造方法,这边的入参数是class,获取的只能公有的私有的获取不到
//返回的是public Yasuo()
Constructor<?> constructor = aClass.getConstructor();
System.out.println("获取无参构造" + constructor);
//private Yasuo(int age) 获取私有的只能是这个方法,当然也可以获取公有的
Constructor<?> constructor2 = aClass.getDeclaredConstructor(int.class);
System.out.println("获取无参构造1" + constructor2);
}
2.2.2 反射创建对象
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//第一种方式
Class<?> aClass = Class.forName("com.yxlm.dmxy.Yasuo");
//反射创建对象,这边等于new,当然无参构造也是一样的道理
Constructor<?> constructor = aClass.getConstructor(int.class, String.class);
Yasuo hasaki = (Yasuo) constructor.newInstance(23, "hasaki");
System.out.println(hasaki);
//这边构造有新的方法,了解一下就行
Yasuo o1 = (Yasuo) aClass.newInstance();
//获取私有构造方法,需要强制访问,暴力反射!!!!
Constructor<?> constructor1 = aClass.getDeclaredConstructor(int.class);
//强制访问私有方法
constructor1.setAccessible(true);
Yasuo o = (Yasuo) constructor1.newInstance(122);
}
2.2.3 获取所有成员变量
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//第一种方式
Class<?> aClass = Class.forName("com.yxlm.dmxy.Yasuo");
//反射获取成员变量,public
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println("获取所有公共的成员方法"+field);
}
//获取所有
Field[] fieldsAll = aClass.getDeclaredFields();
for (Field field : fieldsAll) {
System.out.println("所有"+field);
}
//获取单个公有的,同理获取私有的就不演示了
Field nickname = aClass.getField("nickname");
System.out.println("单个"+nickname);
}
2.2.4 get&set
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//第一种方式
Class<?> aClass = Class.forName("com.yxlm.dmxy.Yasuo");
Yasuo o = (Yasuo) aClass.newInstance();
Field msg = aClass.getDeclaredField("r");
msg.set(o,"hasaihasaihasai");
System.out.println(o);
//有的小伙伴就要问了直接
//o.setAge();多方便,但是这个方法是可以在没有set方法的时候给变量赋值
Field nickname = aClass.getDeclaredField("nickname");
String o1 = (String) nickname.get(o);
System.out.println(o1);
}
?2.2.5 获取成员方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//第一种方式
Class<?> aClass = Class.forName("com.yxlm.dmxy.Yasuo");
//获取所有方法,这个会返回父类的所有方法,不包括私有方法
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println("所有方法"+method);
}
//获取自己的成员方法,包含自己的私有方法
Method[] methodsSelf = aClass.getDeclaredMethods();
for (Method method : methodsSelf) {
System.out.println("自己的方法"+method);
}
//获取单个方法
Method getAge = aClass.getMethod("getAge");
System.out.println("单个"+getAge);
//获取有参数的方法
Method setAge = aClass.getMethod("setAge", int.class);
System.out.println("单个setAge"+setAge);
//获取私有的方法
Method kill = aClass.getDeclaredMethod("kill");
System.out.println("kill"+kill);
}
2.2.6 使用方法 invoke
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//第一种方式
Class<?> aClass = Class.forName("com.yxlm.dmxy.Yasuo");
Method kill = aClass.getDeclaredMethod("kill");
Constructor<?> constructor = aClass.getConstructor(int.class, String.class);
kill.setAccessible(true);
kill.invoke(constructor.newInstance(1,"haihaihai!!!"));
}
|