类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现这个类进行初始化。
- 加载
指将class文件读入内存中,并创建一个Class对象。任何类被使用都系统都会创建一个Class对象。
- 连接
- 验证 - 是否有正确的内部结构,并和其他类协调一致
- 准备 - 负责为类的静态成员分配内存,并设置默认初始化值
- 解析 - 将类的二进制数据中的符号引用替换为直接引用
- 初始化
jvm负责对类进行初始化
**
类的初始化
- 创建类的实例
- 类的静态变量,或为静态变量赋值
- 类的静态方法
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类

反射的概述
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对象是同一个。
import org.junit.Test;/*** 当前案例演示利用反射的机制获取对象的属性。*/public class ReflectDemo {//对象的获取直接使用反射获取 - 不使用new@Testpublic void test1(){//已知明确的类型,获取Class对象Class cla = Student.class;System.out.println(cla);//class Student}@Testpublic void test2(){//已知对象,获取class对象Student s = new Student();Class cla = s.getClass();//getClass()是顶级父类Object中的方法System.out.println(cla);//class Student}@Testpublic void test3() throws ClassNotFoundException {//完全限定名(包名.类名),获取Class对象 - 比较常用(安全)String className = "Student";//forName()返回这个地址值锁所对应的类Class cla = Class.forName(className);System.out.println(cla);//class Student}//测试结果:通过不同的反射获取对象判断是不是同一个?@Testpublic void test4() throws ClassNotFoundException {Class cla1 = Student.class;Student s1 = new Student();Class cla2 = s1.getClass();Class cla3 = Class.forName("Student");//比较System.out.println(cla1==cla2);//trueSystem.out.println(cla2==cla3);//trueSystem.out.println(cla1==cla3);//true}}
利用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”);
import org.junit.Test;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;/*** 通过java反射机制构建对象的测试 - 这些操作平时主要我们创建对象,内存中就偷偷的帮我们做了* 步骤:* 1.创建该类的Class对象* 2.利用Class对象去创建类对象* 3.利用Class对象中的newInstance方法创建对象,类中有公共的无参构造* 4.最后利用Class类中的构造函数对象,通过构造函数创建实例对象**/public class ReflectDemo2 {@Testpublic void test1() throws IllegalAccessException, InstantiationException {//类中有无参构造Class cla = Student.class;Object obj = cla.newInstance();//默认调用无参构造 - 创建实例System.out.println(cla);//class StudentSystem.out.println(obj);//Student{id=0, name='null'} - 当前的Object进行了向下转型给了反射获取到的类Student}@Testpublic void test2() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {//获取Class类中的构造函数对象Class cla = Student.class;//获取构造函数 - 有参Constructor ctor = cla.getConstructor(int.class,String.class);//通过构造函数为属性赋值Object obj = ctor.newInstance(20,"Tom");System.out.println(obj);//Student{id=20, name='Tom'}}//演示普通方式实例化对象做不到的事情(私有的set方法)@Testpublic void test3(){Student s = new Student();s.setId(1);//s.setName();不能赋值,方法私有System.out.println(s);//Student{id=1, name='null'}}}
反射操作成员方法:
操作public方法:
流程:
- 获取实例对象
- 获取方法,需要明确形参列表
确定实例对象,并执行方法,传参
@Testpublic void test(){//1.获取实例Class cla = Class.forName("package.Bean");Object obj = cla.newInstance();//通过无参构造创建对象//2.获取方法Method method = cla.getMethod("setId",String.class);//3.执行方法method.invoke(obj,"b002");}
操作私有方法:
步骤:
获取实例
- 获取方法
- 强制设置运行访问为私有访问(暴力)
执行
@Testpublic void test(){//1.获取实例Class cla = Class.forName("package.Bean");Object obj = cla.newInstance();//通过无参构造创建对象//2.获取方法Method method = cla.getMethod("show",String.class);//3.强制设置运行访问私有访问(暴力)method.setAccessible(true);//4.执行方法method.invoke(obj,"b002");}
处理静态方法
步骤:
获取Class
- 获取方法
- 执行方法 ```java import org.junit.Test;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
/**
反射处理静态方法 */ public class ReflectDemo3 { @Test public void test1(){
//静态方法的调用 - 普通int count = Student.getCount(10);System.out.println(count);
}
@Test public void test2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//利用反射机制来处理//1.创建ClassString className = "Student";Class cla = Class.forName(className);//2.调用静态方法Method m_getCount = cla.getMethod("getCount", int.class);//3.根据类型传参 - invoke方法表示映射,这里因为不需要实例,所以可以传参nullObject returnValue = m_getCount.invoke(null,2);//(对象,参数)
} }
<a name="e2sy6"></a>### 操作public字段**步骤:**1. **获取实例对象**1. **获取字段**1. **给字段赋值**1. **获取字段值**```java@Testpublic void test(){Class cla = new Class.forName("User");Object obj = cla.newInstance();Field id = cla.getField("id");id.set(obj,20);Object id_value = id.get(s1);System.out.println(id_value);}
操作私有字段
步骤:
- 获取实例对象
- 获取字段
- 给字段赋值
- 获取字段值
@Testpublic void test(){Class cla = new Class.forName("User");Object obj = cla.newInstance();Field id = cla.getField("id");id.setAccessible(true);id.set(obj,20);Object id_value = id.get(s1);System.out.println(id_value);}
