类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现这个类进行初始化。
- 加载
指将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
@Test
public void test1(){
//已知明确的类型,获取Class对象
Class cla = Student.class;
System.out.println(cla);//class Student
}
@Test
public void test2(){
//已知对象,获取class对象
Student s = new Student();
Class cla = s.getClass();//getClass()是顶级父类Object中的方法
System.out.println(cla);//class Student
}
@Test
public void test3() throws ClassNotFoundException {
//完全限定名(包名.类名),获取Class对象 - 比较常用(安全)
String className = "Student";
//forName()返回这个地址值锁所对应的类
Class cla = Class.forName(className);
System.out.println(cla);//class Student
}
//测试结果:通过不同的反射获取对象判断是不是同一个?
@Test
public 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);//true
System.out.println(cla2==cla3);//true
System.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 {
@Test
public void test1() throws IllegalAccessException, InstantiationException {
//类中有无参构造
Class cla = Student.class;
Object obj = cla.newInstance();//默认调用无参构造 - 创建实例
System.out.println(cla);//class Student
System.out.println(obj);//Student{id=0, name='null'} - 当前的Object进行了向下转型给了反射获取到的类Student
}
@Test
public 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方法)
@Test
public void test3(){
Student s = new Student();
s.setId(1);
//s.setName();不能赋值,方法私有
System.out.println(s);//Student{id=1, name='null'}
}
}
反射操作成员方法:
操作public方法:
流程:
- 获取实例对象
- 获取方法,需要明确形参列表
确定实例对象,并执行方法,传参
@Test
public 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");
}
操作私有方法:
步骤:
获取实例
- 获取方法
- 强制设置运行访问为私有访问(暴力)
执行
@Test
public 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.创建Class
String className = "Student";
Class cla = Class.forName(className);
//2.调用静态方法
Method m_getCount = cla.getMethod("getCount", int.class);
//3.根据类型传参 - invoke方法表示映射,这里因为不需要实例,所以可以传参null
Object returnValue = m_getCount.invoke(null,2);//(对象,参数)
} }
<a name="e2sy6"></a>
### 操作public字段
**步骤:**
1. **获取实例对象**
1. **获取字段**
1. **给字段赋值**
1. **获取字段值**
```java
@Test
public 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);
}
操作私有字段
步骤:
- 获取实例对象
- 获取字段
- 给字段赋值
- 获取字段值
@Test
public 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);
}