java 类加载机制和反射机制
一.类的加载机制
jvm把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成jvm可以直接使用的java类型的过程。
(1)加载
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。
(2)链接 将java类的二进制代码合并到jvm的运行状态之中的过程。
- 验证:确保加载的类信息符合jvm规范,没有安全方面的问题。
- 准备:正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。
- 解析:虚拟机常量池内的符号引用替换为直接引用的过程。(比如String s ="aaa",转化为 s的地址指向“aaa”的地址)
(3)初始化
初始化阶段是执行类构造器方法的过程。类构造器方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。
当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先初始化其父类的初始化
虚拟机会保证一个类的构造器方法在多线程环境中被正确加锁和同步
当访问一个java类的静态域时,只有真正声明这个静态变量的类才会被初始化。
二.java反射机制
通俗地说:反射就是将Student类中的方法、成员变量、构造方法,抽象出来可以让Class的对象单独进行访问。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
1、获取Class对象的三种方式
(1)通过调用forName(String className),注意className的格式为:包名.类名获得Class对象。
(2)通过类获取Class对象,String.class、int.class这些字节码是Class类的对象。
(3)通过类的对象获取Class对象。
1 public static void getClass1() throws ClassNotFoundException { 2 //获取Class的方法 3 //正射 4 Student stu=new Student(); 5 //第一种(优先选择):传的是包名.类名,通过包名和类名获得反射Class 6 Class cl1=Class.forName("day20.Student"); 7 //第二种:通过类来获取Class对象 8 Class cl2=Student.class; 9 //第三种:通过对象获取Class对象 10 Student s=new Student(); 11 Class cl3=s.getClass(); 12 //判断三种方法是否是同一个Class对象 13 System.out.println(cl1==cl2); 14 System.out.println(cl2==cl3); 15 16 }
2、获取构造方法
(1)获取公开的构造方法
(2)获取所有的构造方法
主要为调取Student类中的私有方法。注意:不能获得Student类的父类Human中的构造方法。
(3)调用特定的构造方法
无参构造和有参构造方法Constructors1.newInstance();//实例化获取的类
私有构造方法的调用,要注意要设置其访问权限Constructors1.setAccessible(true)。
1 public static void getConstruction() throws Exception { 2 //获取构造方法 3 Class cl=Class.forName("day20.Student"); 4 System.out.println("==========公开的构造方法=========="); 5 //获得公开的构造方法 6 Constructor[] cons=cl.getConstructors(); 7 for(Constructor con:cons) { 8 System.out.println(con); 9 } 10 System.out.println("==========所有的构造方法=========="); 11 //获得所有的构造方法 12 Constructor[] constructors=cl.getDeclaredConstructors(); 13 for (Constructor con:constructors 14 ) { 15 System.out.println(con); 16 } 17 System.out.println("==========调用构造方法=========="); 18 //调用无参构造方法 19 Constructor constructors1=cl.getConstructor(); 20 Student student=(Student)constructors1.newInstance(); 21 //调用有参构造方法 22 Constructor constructors2=cl.getConstructor(String.class); 23 Student student1=(Student) constructors2.newInstance("英语"); 24 //调用私有构造方法 25 Constructor constructors3=cl.getDeclaredConstructor(int.class); 26 constructors3.setAccessible(true);//因为是私有化的方法,所以要设置访问权限 27 Student student2=(Student) constructors3.newInstance(2); 28 }
执行结果:
==========公开的构造方法========== |
3、获取方法
私有属性的调用,要注意要设置其访问权限Constructors1.setAccessible(true)。
1 private static void getMethod1() throws Exception { 2 Class cl=Class.forName("day20.Student"); 3 //获取所有公开的方法,包括Object中的类 4 Method[] method=cl.getMethods(); 5 for (Method m:method 6 ) { 7 System.out.println(m.getName()); 8 } 9 //获取本类中所有的方法,不包括父类和eObject 10 System.out.println("==========私有方法=========="); 11 Method[] methods=cl.getDeclaredMethods(); 12 for (Method ms:methods 13 ) { 14 System.out.println(ms.getName()); 15 } 16 //调取方法 17 System.out.println("==========调取特有方法=========="); 18 //获取非静态的无参方法 19 Method method1=cl.getMethod("eat"); 20 //获取Student类的成员 21 Constructor constructor=cl.getConstructor(); 22 Student student=(Student)constructor.newInstance(); 23 method1.invoke(student); 24 //获取非静态含参方法 25 Method method2=cl.getMethod("study", String.class); 26 method2.invoke(student,"物理"); 27 //获取静态无参方法 28 Method method3=cl.getMethod("sleep"); 29 method3.invoke(null); 30 //获取静态含参方法 31 try { 32 Method method4=cl.getMethod("saveMoney", double.class); 33 method4.setAccessible(true); 34 method4.invoke(null,100.0); 35 }catch (NoSuchMethodException e){ 36 e.getMessage(); 37 }catch(Exception e){ 38 e.getMessage(); 39 } 40 41 }
执行结果:
getName |
4、获取属性
1 private static void getAttribute1() throws Exception{ 2 Class cl=Class.forName("day20.Student"); 3 //获取所有属性 4 Field[] fields=cl.getFields(); 5 for (Field field:fields 6 ) { 7 System.out.println("属性值有:"+field.getName()); 8 } 9 //获取私有化属性 10 Field field=cl.getDeclaredField("money"); 11 field.setAccessible(true); 12 //获取Student类的成员 13 Constructor constructor=cl.getConstructor(); 14 Student student=(Student)constructor.newInstance(); 15 student.setMoney(100); 16 System.out.println("通过对象.方法进行属性赋值:"+student.getMoney()); 17 field.set(student,200); 18 System.out.println("通过Field对象.方法进行赋值:"+student.getMoney()); 19 }
执行结果:
属性值有:name |
Student类和父类
1 package day20; 2 3 public class Student extends Human{ 4 public String name; 5 int age; 6 private double money; 7 8 public Student() { 9 System.out.println("无参构造方法"); 10 } 11 public Student(String subject) { 12 System.out.println("有参构造方法"+subject); 13 } 14 15 private Student(int i) { 16 System.out.println("私有构造方法"+i); 17 } 18 public String getName() { 19 return name; 20 } 21 public void setName(String name) { 22 this.name = name; 23 } 24 public int getAge() { 25 return age; 26 } 27 public void setAge(int age) { 28 this.age = age; 29 } 30 public double getMoney() { 31 return money; 32 } 33 public void setMoney(double money) { 34 this.money = money; 35 } 36 37 public void eat(){ 38 System.out.println("吃饭"); 39 } 40 41 public void study(String subject){ 42 System.out.println("学习"+subject); 43 } 44 45 public static void sleep(){ 46 System.out.println("睡觉"); 47 } 48 49 private static void saveMoney(double money){ 50 System.out.println("存款"+money); 51 } 52 } 53 54 55 package day20; 56 57 public class Human { 58 private String sex; 59 public Human(){ 60 61 } 62 63 private Human(int i){ 64 65 } 66 67 public String getSex() { 68 return sex; 69 } 70 71 public void setSex(String sex) { 72 this.sex = sex; 73 } 74 }