反射基础
反射基本概念
反射在程序运行过程中,动态的创建对象。
只要知道该类的名称,就可以使用它的字节码对象创建该类的一个对象,对于这个类中的任何一个对象和属性,我们都可以访问或者使用它。
反射的基石
——字节码对象
.java 文件通过 javac 命令编译后产生 .class 字节码文件,最后执行字节码文件
jvm把字节文件加载到内存中去,字节码文件就变成了字节码文件对象
字节码文件对象
字节码文件对象的类型是Class---->类型----->引用数据类型
获得类或者对象的字节码文件对象
- 通过Object类的getClass()方法
- 类型Class属性
- Class类的forName(类的全路径名)
Class Person{
// 创建一个Person类
}
Class Student{
// 创建一个Student类
}
public class ReflectDemo {
public static void main(String[] args) throws Exception{
// 为方便处理,此处将异常抛出
// 1. 通过父类(Object)中的getClass()方法获得字节码对象
Class personClass1=new Person().getClass();
// 2. 通过class 属性获得
Class studentClass1=Student.class;
Class personClass2=Person.class;
// 3. 通过forName()方法获得
Class studentClass2=Class.forName("Reflect.ReflectDemo"); // 参数为全路径名,Reflect是我的包名,RelectDemo是我的类名
System.out.println(personClass1.equals(personClass2));
System.out.println(studentClass1.equals(studentClass2));
}
}
输出
ture
ture
思考:同一个类的对象或者同一个类得到的字节码文件对象是否是同一个?
答:是同一个,创建类对象时,根据类的字节码文件创建,在程序运行时,只会加载一次字节码文件,所以同一个类的不同对象或者同一个类得到的字节码对象是同一个。
字节码文件的加载时机
注意:一个类的字节码文件只会加载一次
- new 一个类的时候
- 访问一个类的静态成员的是时候
- 调用一个类静态方法的时候
- 通过反射的方式创建一个类的字节码对象的时候
- 创建一个子类的对象的时候(使用父类对象指向子类对象)
- java命令执行一个字节码文件的时候
字节码文件对象的组成
类 字节码文件对象 类型
构造方法---------------------> 构造方法对象 (Constructor)
成员方法---------------------> 成员方法对象 (Method)
成员变量---------------------> 成员变量对象 (Field)
构造方法对象
package Reflect;
import java.lang.reflect.Constructor;
/**
* @author Steven
* @create 2020-06-06 21:02
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception{
// 为方便处理,此处将异常抛出
// 1. 通过父类(Object)中的getClass()方法获得字节码对象
Class personClass1=new Person().getClass();
// 2. 通过class 属性获得
Class studentClass1=Student.class;
Class personClass2=Person.class;
// 3. 通过forName()方法获得
Class studentClass2=Class.forName("Reflect.Student");
System.out.println(personClass1.equals(personClass2));
System.out.println(studentClass1.equals(studentClass2));
// 获得Person类的所有构造方法对象
Constructor[] constructors=personClass1.getConstructors();
for (Constructor c:constructors
) {
System.out.println(c);
/*======此处将会输出:=======
public Reflect.Person()
public Reflect.Person(java.lang.String)
public Reflect.Person(int)
public Reflect.Person(java.lang.String,int)
*/
}
Constructor constructor=personClass1.getConstructor(String.class);
System.out.println(constructor);
/*======此处会输出=========
*public Reflect.Person(java.lang.String)
*/
// 运用构造方法对象创建对象
Object o=constructor.newInstance("Steven");
System.out.println(o);
Person p1= (Person) constructor.newInstance("Steven");
System.out.println(p1);
/*======此处会输出=========
姓名: Steven
年龄: 18
姓名: Steven
年龄: 18
*/
}
}
class Person{
String name;
int age=18;
// 定义构造方法的4个重载方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(int age) {
this.age = age;
}
public Person(String name) {
this.name = name;
}
public Person() {
}
@Override
public String toString() {
return "姓名: "+this.name+"\n年龄: "+this.age;
}
}
class Student{
}
取得构造器的常用API
public Constructor getConstructor(Class<?>… parameterTypes); // 得到某一个构造方法的构造方法对象
public Constructor<?>[] getConstructors(); //得到该字节码文件对象的所有公有的(public)构造方法
注:以上方法只能得到公共的构造方法;若想得到私有的构造方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes);
public Constructor<?>[] getDeclaredConstructors();
import java.lang.reflect.Constructor;
/**
* @author Steven
* @create 2020-06-07 0:04
*/
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
// 将异常抛出
//完整的运用构造器创建对象,JDK中常见
// Hello hello = new Hello(); 构造方法私有化,不能访问
// 使用反射方式强制实例化对象
Class hello = Hello.class;
// Constructor constructor=hello.getConstructor(); constructor 只能得到公共的构造方法 public
Constructor constructor = hello.getDeclaredConstructor();
// 会报IllegalAccessException异常,非法访问错误,可以设置强制访问 注:此时已经拿到构造器对象
constructor.setAccessible(true); // 将构造器访问权限设置为true
Object o = constructor.newInstance();
System.out.println(o);
// 便携方法创建
Class t=T.class;
Object j=t.newInstance();
System.out.println(j);
// 便携方法的缺点:
// 不能访问非公有的构造方法和不含无参构造方法的类
}
}
class Hello {
private Hello() {
}
@Override
public String toString() {
return "Hello world";
}
}
class T{
@Override
public String toString() {
return "hello~~~Steven";
}
}
/*
* 此输出:
* Hello world
* hello~~~Steven
* */
成员方法对象和成员变量对象可参照构造方法对象学习
后续更新中……