java学习(17)
这篇来写关于类加载器以及反射
1.类加载器
1.1类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,
初始化三步来实现对这个类进行初始化
1)加载
就是指将class文件读入内存,并为之创建一个Class对象. 任何类被使用时系统都会建立一个Class对象。
2)连接
2.1)验证 是否有正确的内部结构,并和其他类协调一致
2.2)准备 负责为类的静态成员分配内存,并设置默认初始化值
2.3)解析 将类的二进制数据中的符号引用替换为直接引用
3)初始化
1.2类的加载时机
1 )创建类的实例
2 ) 访问类的静态变量,或者为静态变量赋值
3 )调用类的静态方法
4 )使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5 )初始化某个类的子类
6 )直接使用java.exe命令来运行某个主类
1.3加载器分类
1)类加载起的作用
负责将.class文件加载到内在中,并为之生成对应的Class对象。
2 )类加载器的分类
A)Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责Java核心类的加载:比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
B)Extension ClassLoader 扩展类加载器,负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录
C)Sysetm ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件
2.反射
2.1一个类会对应有一个字节码文件(.class文件),把它看成一个对象,这个对象就叫字节码文件对象,对应的类是Class类
2.2反射:通过字节码文件对象去使用成员。
2.3获取字节码文件对象的三种方式:
A:Object类的getClass()方法
B:数据类型的静态class属性
C:Class类的静态方法forName()
注意:在平常写案例的时候,直接使用第二种最方便。但是实际开发中,我们一般用的都是第三种。是因为第三种接收的是一个字符串类型的参数,我们可以把这个参数作为配置文件的内容进行配置,这样就实现了一个变化的内容。
代码示例:
这里建了一个Student类便于演示:
测试实现类:public class Student { private String name; private int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } public Student() { super(); // TODO Auto-generated constructor stub } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } 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; } }
public static void main(String[] args) throws Exception { //A:Object类的getClass()方法 Student s = new Student(); Class c = s.getClass(); System.out.println(c); System.out.println("================"); //B:数据类型的静态class属性 Class c2 = Student.class; System.out.println(c2); System.out.println("================"); //C:Class类的静态方法forName() Class c3 = Class.forName("com.edu01.Student"); System.out.println(c3); }运行:
注意:第三种方法里面使用的是全类名
2.4反射的使用步骤
Class:
成员变量 Field
构造方法 Constructor
成员方法 Method
2.5反射:class字节码文件对象 -- 去得到对应的成员对象 -- 通过该成员的对象调用方法使用
这里提供一个Teacher类,对于构造方法,成员变量,成员方法使用不同的修饰符进行修饰,便于后面演示:
public class Teacher { //成员变量,被各种修饰符修饰 String name; public int age; private String sex; protected int salary; //构造方法,被各种修饰符修饰 Teacher(String name){ this.name = name; } public Teacher(int age){ this.age =age; } private Teacher(String name,int age){ this.name = name; this.age = age; } protected Teacher(String name,int age,int salsry){ this.name = name; this.age = age; this.salary = salary; } //成员方法,被各种修饰符修饰 void method1(){ System.out.println("这是第一个method方法"); } public void method2(){ System.out.println("这是第二个method方法"); } private void method3(){ System.out.println("这是第三个method方法"); } protected void method4(){ System.out.println("这是第四个method方法"); } @Override public String toString() { return "Teacher [name=" + name + ", age=" + age + ", sex=" + sex + ", salary=" + salary + "]"; } }
2.6通过反射获取构造方法并使用
2.6.1通过反射获取构造方法
(1)public Constructor[] getConstructors() 获取公共的构造方法
(2)public Constructor[] getDeclaredConstructors() 获取所有的构造方法(包括私有)
(3)public Constructor getConstructor(Class... parameterTypes) 根据构造参数获取公共的指定构造
(4)public Constructor getDeclaredConstructor(Class<?>... parameterTypes) 根据构造参数获取指定构造(包括私有,但是私有在使用的时候需要取消访问限制)
代码示例:
运行:public static void main(String[] args) throws Exception { //获取字节码文件对象 Class c = Class.forName("com.edu02.Teacher"); //public Constructor[] getConstructors() //获取公共的构造方法 Constructor[] con1 = c.getConstructors(); //遍历 for (Constructor con : con1) { System.out.println(con); } System.out.println("====================="); //public Constructor[] getDeclaredConstructors() // 获取所有的构造方法(包括私有) Constructor[] con2 = c.getDeclaredConstructors(); //遍历 for (Constructor con : con2) { System.out.println(con); } System.out.println("====================="); //public Constructor getConstructor(Class... parameterTypes) //根据构造参数获取公共的指定构造 Constructor con3 = c.getConstructor(int.class); System.out.println(con3); System.out.println("====================="); //public Constructor getDeclaredConstructor(Class<?>... parameterTypes) //根据构造参数获取指定构造(包括私有,但是私有在使用的时候需要取消访问限制) Constructor con4 = c.getDeclaredConstructor(String.class,int.class); System.out.println(con4); }
2.6.2通过反射获取构造方法并创建对象
public T newInstance(Object... initargs)
示例:
运行:public static void main(String[] args) throws Exception { //获取字节码文件对象 Class c = Class.forName("com.edu02.Teacher"); //获取构造方法 Constructor con = c.getDeclaredConstructor(String.class,int.class); //取消访问检测 con.setAccessible(true); //通过反射获取构造方法并创建对象 //public T newInstance(Object... initargs) Object obj = con.newInstance("李老师",45); System.out.println(obj); }
分析:这里给出了一种获取构造方法并创建对象的方法,需要注意的是对于不是公有的构造方法,在创建对象的时候要取消访问检测,即:
con.setAccessible(true);置为true即可,否则会报错。
2.7通过反射获取成员变量并使用
(1)public Field[] getFields()获取公有的成员变量
(2)public Field[] getDeclaredFields()获取全部的成员变量,包括私有
(3)public Field getDeclaredField(String name) 传入变量名称返回指定的成员变量对象,包括私有
(4)public Field getField(String name)传入变量名称返回指定的成员变量对象,仅可获取共有的
示例:
运行:public static void main(String[] args) throws Exception { //获取字节码文件对象 Class c = Class.forName("com.edu02.Teacher"); //public Field[] getFields()获取公有的成员变量 Field[] field1 = c.getFields(); for (Field field : field1) { System.out.println(field); } System.out.println("================="); //public Field[] getDeclaredFields()获取全部的成员变量,包括私有 Field[] field2 = c.getDeclaredFields(); for (Field field : field2) { System.out.println(field); } System.out.println("================="); //public Field getDeclaredField(String name) 传入变量名称返回指定的成员变量对象,包括私有 Field field3 = c.getDeclaredField("name"); System.out.println(field3); System.out.println("================="); //public Field getField(String name)传入变量名称返回指定的成员变量对象,仅可获取共有的 Field field4 = c.getField("age"); System.out.println(field4); }
(5)public void set(Object obj,Object value)给一个对象的一个字段设置一个值
分析:给变量设置值类似于上述对象创建,获取字节码文件对象,再通过反射获取一个构造方法,创建一个对象,利用set方法进行对应变量的赋值。
2.8通过反射获取成员方法并使用
(1)public Method[] getMethods()获取所有公共成员方法
分析:不仅获取自身的公共成员方法,还能获取到父类的公共成员方法//public Method[] getMethods()获取所有公共成员方法 Method[] methods = c.getMethods(); for (Method method : methods) { System.out.println(method); }运行:
(2)public Method[] getDeclaredMethods()获取所有成员方法,包括私有
分析:也会获取父类的方法,包括私有的Method[] methods2 = c.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); }
(3)public Method getMethod(String name, Class<?>... parameterTypes)参数一:方法名 参数二:方法参数类型.class 获取指定的公共方法
(4)public Method getDeclaredMethod(String name,Class<?>... parameterTypes)参数一:方法名 参数二:方法参数类型.class 获取指定的方法,包括私有
(5)Object invoke(Object obj, Object... args) 让某一个对象使用这个方法,并且传入参数
分析:这里的获取成员方法使用与上述获取构造方法,成员变量基本相同,不再做叙述。
772

被折叠的 条评论
为什么被折叠?



