类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现这个类进行初始化。

  • 加载

指将class文件读入内存中,并创建一个Class对象。任何类被使用都系统都会创建一个Class对象。

  • 连接
    • 验证 - 是否有正确的内部结构,并和其他类协调一致
    • 准备 - 负责为类的静态成员分配内存,并设置默认初始化值
    • 解析 - 将类的二进制数据中的符号引用替换为直接引用
  • 初始化

jvm负责对类进行初始化
**
反射机制 - 图1

类的初始化

  • 创建类的实例
  • 类的静态变量,或为静态变量赋值
  • 类的静态方法
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

反射机制 - 图2

反射的概述

java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象都能调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法称为java的反射机制。

java反射机制:**

  • 反射机制是java中底层的一个功能,就是通过这个机制可以进行对象的灵活的调用和处理。
  • 在后期学习中会用到反射的相关内容,但是都是底层的理解,比如:文件的加载,spring框架底层……

目前我们要掌握反射的使用。

  • java中提供了一个api - Class类
  • java.lang包下,不需要导包


反射需要用到的成员:**

  • Class类
  • Constructor 构造器
  • Method 方法
  • Field 字段(属性)
  • newInstance 创建实例
  • invoke 激活方法(执行方法)

**

Class对象

要想解剖一个类,必须先要获取该类的字节码文件对象。而解刨这个类,使用的就是Class类中的方法,所以先要获取到每个字节码文件对应的Class类型对象。

获取Class类对象的常用方式:**

  • 明确类型.class
  • 已知对象.getClass
  • Class.forName(完全限定名) - 完全限定名(包名.类名),获取Class对象 - 比较常用(安全)

同一个类获取到的Class对象是同一个。

  1. import org.junit.Test;
  2. /**
  3. * 当前案例演示利用反射的机制获取对象的属性。
  4. */
  5. public class ReflectDemo {
  6. //对象的获取直接使用反射获取 - 不使用new
  7. @Test
  8. public void test1(){
  9. //已知明确的类型,获取Class对象
  10. Class cla = Student.class;
  11. System.out.println(cla);//class Student
  12. }
  13. @Test
  14. public void test2(){
  15. //已知对象,获取class对象
  16. Student s = new Student();
  17. Class cla = s.getClass();//getClass()是顶级父类Object中的方法
  18. System.out.println(cla);//class Student
  19. }
  20. @Test
  21. public void test3() throws ClassNotFoundException {
  22. //完全限定名(包名.类名),获取Class对象 - 比较常用(安全)
  23. String className = "Student";
  24. //forName()返回这个地址值锁所对应的类
  25. Class cla = Class.forName(className);
  26. System.out.println(cla);//class Student
  27. }
  28. //测试结果:通过不同的反射获取对象判断是不是同一个?
  29. @Test
  30. public void test4() throws ClassNotFoundException {
  31. Class cla1 = Student.class;
  32. Student s1 = new Student();
  33. Class cla2 = s1.getClass();
  34. Class cla3 = Class.forName("Student");
  35. //比较
  36. System.out.println(cla1==cla2);//true
  37. System.out.println(cla2==cla3);//true
  38. System.out.println(cla1==cla3);//true
  39. }
  40. }

**

利用Class对象创建实例对象

反射操作构造方法:

  • 无参构造

Class cla = Student.class;
Object obj = cla.newInstance();//默认调用无参构造 - 创建实例

  • 有参构造

Class cla = Student.class;
Constructor ctor = cla.getConstructor(int.class,String.class);
//通过构造函数为属性赋值
Object obj = ctor.newInstance(20,”Tom”);

  1. import org.junit.Test;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.InvocationTargetException;
  4. /**
  5. * 通过java反射机制构建对象的测试 - 这些操作平时主要我们创建对象,内存中就偷偷的帮我们做了
  6. * 步骤:
  7. * 1.创建该类的Class对象
  8. * 2.利用Class对象去创建类对象
  9. * 3.利用Class对象中的newInstance方法创建对象,类中有公共的无参构造
  10. * 4.最后利用Class类中的构造函数对象,通过构造函数创建实例对象
  11. *
  12. */
  13. public class ReflectDemo2 {
  14. @Test
  15. public void test1() throws IllegalAccessException, InstantiationException {
  16. //类中有无参构造
  17. Class cla = Student.class;
  18. Object obj = cla.newInstance();//默认调用无参构造 - 创建实例
  19. System.out.println(cla);//class Student
  20. System.out.println(obj);//Student{id=0, name='null'} - 当前的Object进行了向下转型给了反射获取到的类Student
  21. }
  22. @Test
  23. public void test2() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
  24. //获取Class类中的构造函数对象
  25. Class cla = Student.class;
  26. //获取构造函数 - 有参
  27. Constructor ctor = cla.getConstructor(int.class,String.class);
  28. //通过构造函数为属性赋值
  29. Object obj = ctor.newInstance(20,"Tom");
  30. System.out.println(obj);//Student{id=20, name='Tom'}
  31. }
  32. //演示普通方式实例化对象做不到的事情(私有的set方法)
  33. @Test
  34. public void test3(){
  35. Student s = new Student();
  36. s.setId(1);
  37. //s.setName();不能赋值,方法私有
  38. System.out.println(s);//Student{id=1, name='null'}
  39. }
  40. }

反射操作成员方法:

操作public方法:

流程:

  1. 获取实例对象
  2. 获取方法,需要明确形参列表
  3. 确定实例对象,并执行方法,传参

    1. @Test
    2. public void test(){
    3. //1.获取实例
    4. Class cla = Class.forName("package.Bean");
    5. Object obj = cla.newInstance();//通过无参构造创建对象
    6. //2.获取方法
    7. Method method = cla.getMethod("setId",String.class);
    8. //3.执行方法
    9. method.invoke(obj,"b002");
    10. }

    操作私有方法:

    步骤:

  4. 获取实例

  5. 获取方法
  6. 强制设置运行访问为私有访问(暴力)
  7. 执行

    1. @Test
    2. public void test(){
    3. //1.获取实例
    4. Class cla = Class.forName("package.Bean");
    5. Object obj = cla.newInstance();//通过无参构造创建对象
    6. //2.获取方法
    7. Method method = cla.getMethod("show",String.class);
    8. //3.强制设置运行访问私有访问(暴力)
    9. method.setAccessible(true);
    10. //4.执行方法
    11. method.invoke(obj,"b002");
    12. }

    处理静态方法

    步骤:

  8. 获取Class

  9. 获取方法
  10. 执行方法 ```java import org.junit.Test;

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;

/**

  • 反射处理静态方法 */ public class ReflectDemo3 { @Test public void test1(){

    1. //静态方法的调用 - 普通
    2. int count = Student.getCount(10);
    3. System.out.println(count);

    }

    @Test public void test2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {

    1. //利用反射机制来处理
    2. //1.创建Class
    3. String className = "Student";
    4. Class cla = Class.forName(className);
    5. //2.调用静态方法
    6. Method m_getCount = cla.getMethod("getCount", int.class);
    7. //3.根据类型传参 - invoke方法表示映射,这里因为不需要实例,所以可以传参null
    8. Object returnValue = m_getCount.invoke(null,2);//(对象,参数)

    } }

  1. <a name="e2sy6"></a>
  2. ### 操作public字段
  3. **步骤:**
  4. 1. **获取实例对象**
  5. 1. **获取字段**
  6. 1. **给字段赋值**
  7. 1. **获取字段值**
  8. ```java
  9. @Test
  10. public void test(){
  11. Class cla = new Class.forName("User");
  12. Object obj = cla.newInstance();
  13. Field id = cla.getField("id");
  14. id.set(obj,20);
  15. Object id_value = id.get(s1);
  16. System.out.println(id_value);
  17. }

操作私有字段

步骤:

  1. 获取实例对象
  2. 获取字段
  3. 给字段赋值
  4. 获取字段值
    1. @Test
    2. public void test(){
    3. Class cla = new Class.forName("User");
    4. Object obj = cla.newInstance();
    5. Field id = cla.getField("id");
    6. id.setAccessible(true);
    7. id.set(obj,20);
    8. Object id_value = id.get(s1);
    9. System.out.println(id_value);
    10. }