类加载器
1.概念:类加载器是用来加载类的工具(从硬盘加载到JVM内存)
2.类加载的时机有哪些?
一句话总结:类在使用时才被加载,不使用不加载。想想类什么时候被使用到呢?
1)创建类的对象时
2)通过类名调用静态方法时
3)通过反射加载类
3.类加载器的分类(了解)
启动类加载器:Bootstrap ClassLoader
平台类加载器:Platform ClassLoader
应用程序类加载:System ClassLoader
类加载器的应用
Properties pro=new Properties();
//使用类加载器获取src目录下文件的输入流
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(“a.properties”);
//把配置文件中的键和值,加载到Properties集合
pro.load(in);
System.out.println(pro);
反射
反射可以在程序运行时,动态的获取每一个类的各个组成部分(成员变量Filed、成员方法Method、构造方法Constructor), 并使用。
假如你写了一段代码:Object o=new Object();
运行了起来!
首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进jvm的内存中,你的类Object加载到方法区中,创建了Object类的class对象到堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。
上面的流程就是你自己写好的代码扔给jvm去跑,跑完就over了,jvm关闭,你的程序也停止了。
为什么要讲这个呢?因为要理解反射必须知道它在什么场景下使用。题主想想上面的程序对象是自己new的,程序相当于写死了给jvm去跑。假如一个服务器上突然遇到某个请求哦要用到某个类,哎呀但没加载进jvm,是不是要停下来自己写段代码,new一下,哦启动一下服务器,(脑残)!
上面这段举例转自https://www.zhihu.com/question/24304289
因为写的太棒了_;
作者:CaryTseng
链接:https://www.zhihu.com/question/24304289/answer/147529485
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:CaryTseng
链接:https://www.zhihu.com/question/24304289/answer/147529485
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
获取clazz(字节码文件)
//1. Class.forName(“类的全路径名”);
Class clazz1=Class.forName(“com.ithiema.Student”);
//2. 类名.class
Class clazz2=Student.class;
//3. 对象名.getClass()
Student stu=new Student();
Class clazz3=stu.getClass();
示例
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException {
//获取class字节码文件
//方式1.类名.Class
Class<?> aClass1 = Student.class;
//方式2:对象名.getclass()
Student stu = new Student();
Class<?> aClass2 = stu.getClass();
//方式3.Class.Forname(类的全路径名)
Class<?> aClass3 = Class.forName("com.itheima.demo.Student");
System.out.println(aClass1==aClass2&&aClass2==aClass3);
System.out.println(aClass2==aClass3);
}
}
反射获取构造方法
public Constructor[] getConstructors()
获取构造方法的数组(public修饰的)
public Constructor getConstructor(Class<?>… parameterTypes)
获取一个构造方法(public修饰的)
public Constructor[] getDeclaredConstructors()
获取所有的构造方法(包括私有的)
public Constructor getDeclaredConstructor()
获取一个构造方法(可以获取私有)
示例
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取字节码
Class<?> clazz = Class.forName("com.itheima.demo.Student");
//空参构造
Constructor<?> con = clazz.getDeclaredConstructor();
System.out.println(con);
//有参构造1
Constructor<?> con1 = clazz.getDeclaredConstructor(String.class,int.class);
Student con2 = (Student) con1.newInstance("炸弹", 255);
System.out.println(con2);
//有参构造2
Constructor<?> con3 = clazz.getDeclaredConstructor(String.class);
con3.setAccessible(true);
Student con4 = (Student) con3.newInstance("时机");
System.out.println(con4);
}
}
反射获取成员变量
public Field[] getFields()
获取多个成员变量(public修饰的)
public Field getField(String name)
获取某一个成员变量(public修饰的)
public Field[] getDeclaredFields()
获取所有的成员变量(包括私有的)
public Field getDeclaredField(String name)
获取一个成员变量(可以获取私有的)
public class Demo5 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> clazz = Class.forName("com.itheima.demo.Student");
Field f = clazz.getDeclaredField("name");
System.out.println(f);
//创建学生对象
Object stu = clazz.newInstance();
//获取name的成员变量
Field f1 = clazz.getDeclaredField("name");
//暴力犯色
f1.setAccessible(true);
//设置成员属性
f1.set(stu,"狗仔");
System.out.println("-----------");
//获取成员属性
String name = (String) f1.get(stu);
System.out.println(name);
}
}
反射获取成员方法
public Method[] getMethods()
获取多个成员方法(public修饰的)
public Method getMethod(String name,Class ... parmars)
获取某一个成员方法(public修饰的)
public Method[] getDeclaredtMethods()
获取所有的成员方法(包括私有的)
public Method getDeclaredMethod(String name,Class ... parmars)
获取一个成员方法(可以获取私有的)
public class Demo6 {
public static void main(String[] args) throws Exception {
//获取字节码文件
Class<?> clazz = Class.forName("com.itheima.demo.method");
//创建对象
Object obj = clazz.newInstance();
//暴力反射
Method show1 = clazz.getDeclaredMethod("show");
show1.invoke(obj);
Method show2 = clazz.getDeclaredMethod("show", String.class);
show2.invoke(obj,"张三");
Method show3 = clazz.getDeclaredMethod("show", String.class,int.class);
show3.setAccessible(true);
show3.invoke(obj,"李四",12);
Method show4 = clazz.getDeclaredMethod("show", int.class,int.class);
show4.setAccessible(true);
Object result = show4.invoke(obj,32, 12);
System.out.println(result);
}
}
public class method {
public static void show() {
System.out.println("show.....");
}
public static void show(String m) {
System.out.println("show....." + m);
}
private static void show(String n, int p) {
System.out.println("show....." + n + p);
}
private static int show(int q, int w) {
return q + w;
}
}
创建一个方法多态化获取对象信息
public class Demo4 {
public static void main(String[] args) throws Exception{
//创建学生对象
Student ins1 = createInstance(Student.class);
System.out.println(ins1);
//创建老师对象
Teacher ins3 = createInstance(Teacher.class);
System.out.println(ins3);
}
//创建一个方法多态化获取对象信息
public static <T> T createInstance(Class<T> clazz) throws Exception {
Constructor<T> con = clazz.getDeclaredConstructor();
con.setAccessible(true);
T t = con.newInstance();
return t;
}
}
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
private Student(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
Student(){
}
}
public class Teacher {
private String naem;
private int age;
public Teacher(String naem, int age) {
this.naem = naem;
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"naem='" + naem + '\'' +
", age=" + age +
'}';
}
public Teacher() {
}
}
反射+配置文件
public class Demo {
public static void main(String[] args) throws IOException, Exception {
//读取配置文件
Properties pro = new Properties();
//使用类加载器读取src目录下文件 配置文件config.properties
InputStream inStream = ClassLoader.getSystemClassLoader().getResourceAsStream("config.properties");
//从输入流中读取属性列表
pro.load(inStream);
//获取对应的键对值
String classname = pro.getProperty("classname");
String methodname = pro.getProperty("methodname");
//获取类的字节码
Class<?> clazz = Class.forName(classname);
//创建类的对象
Object obj = clazz.newInstance();
//获取方法
Method method = clazz.getDeclaredMethod(methodname);
//暴力反射
method.setAccessible(true);
//执行
method.invoke(obj);
}
}
public class Student {
private static void stuShow(){
System.out.println("学生疯狂的学习");
}
}
public class Teacher {
private static void teaShow(){
System.out.println("老师疯狂的讲课");
}
}
public class Worker {
private static void worShow(){
System.out.println("工人彻底疯狂");
}
}
//配置文件config.properties
//类名
classname=com.itheima.job.Worker
//方法
methodname=worShow
练习题
1)写一个标准的Student类,要有空参数构造方法、get和set方法、以及toString()方法
2)在测试类中利用反射的方式获取构造方法,并创建对象
3)在测试类中利用反射的方式获取setXxx方法,给成员变量赋值
4)打印Student对象
public class Demo2 {
public static void main(String[] args) throws Exception {
//获取字节码文件
Class<?> clazz = Class.forName("com.itheima.job.Student2");
//获取对象
Object obj = clazz.newInstance();
//获取构造方法空参有参
Constructor<?> con1 = clazz.getDeclaredConstructor();
Constructor<?> con2 = clazz.getDeclaredConstructor(String.class, int.class);
//获取set方法
Method method1 = clazz.getDeclaredMethod("setName",String.class);
method1.setAccessible(true);
method1.invoke(obj, "张三");
Method method2 = clazz.getDeclaredMethod("setAge", int.class);
method2.setAccessible(true);
method2.invoke(obj, 20);
//获取Student2属性
System.out.println(obj);
}
}
public class Student2 {
private String name;
private int age;
public Student2(String name, int age) {
this.name = name;
this.age = age;
}
public Student2() {
}
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 "Student2{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}