本人小白一枚,欢迎大家一起讨论学习,如有错误,还望大家指教。
简述:反射是框架设计的灵魂(框架相当于半成本软件,可以在框架的基础上进行软件开发,从而简化编码,框架的出现大大的减轻了我们的工作)。
反射的好处:
1、可以在程序运行过程中,操作反射对象。
2、大大减低代码的耦合,提高程序的可扩展性。
我们知道,Java代码在计算机大体经历三个阶段(如下图1
),反射的使用前提必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)。
反射就是将类的各个组成部分封装成为各个对象。例如:一个类有:成员变量、方法、构造器、包等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。我们可以看看下图的类的加载过程:Class对象的由来是将.class文件读入内存,并为之创建一个Class对象(反射的原理在Class类对象阶段)。
我们可以自己私下查看api类简单了解下Class类(所在包:java.lang)。
获取Class对象的三种方式:
Class.forName("全类名")
:将字节码文件加载进内存返回Class对象。多用于配置文件,将类名定义在配置文件中,通过读取文件来加载类。
类名.class
:通过类名的属性class获取,多用于参数传递,这种方式需要导入包,依赖性比较强。
对象.getClass()
:此方法从Object类中继承而来多用于对象获取字节码的方式,此方法不常用(对象都有了还要反射!)
public static void main(String[] args) throws ClassNotFoundException {
// 获取Class对象的三种方式,第一种方法会抛出ClassNotFoundException异常
Class clazz1 = Class.forName("Person");
Class clazz2 = new Person().getClass();
Class clazz3 = Person.class;
System.out.println(clazz1 == clazz2);
System.out.println(clazz3 == clazz2);
}
true
true
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会加载一次,不论通过哪一种方式获取Class对象都是同一个。
/**
* 该类包括四个成员变量:默认id,私有name,公有age,保护address
* 该类包括三个构造器:私有无参,公有双参,公有三参
* 该类包括三个方法:私有无参method(),公有单参method(),重写toString()方法
*/
public class Person {
String id;
private String name;
public int age;
protected String address;
private Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
private void method() {
System.out.println("私有方法");
}
public void method(String name) {
System.out.println("有参数公有方法" + name);
}
@Override
public String toString() {
return "Person{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
获取Class对象中的成员变量
Field[] getFields()
:获取所有公有的成员变量。
Field getField(String name)
:获取指定名称的公有成员变量。
Field[] getDeclaredFields()
:获取所有的成员变量(包括私有)。
Field getDeclaredField(String name)
:获取指定名称的成员变量(包括私有)。
void set(Object obj, Object value)
:设置成员变量的值。
Object get(Object obj)
:获取该成员变量的值。
String getName()
:获取该成员变量的名称。
@Test
public void test() throws Exception {
Class clazz = Class.forName("Person");
// 获取所有成员变量(包括私有)
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields) {
System.out.println(field);
}
System.out.println("----------------------------");
// 获取指定名称的成员变量,并重新赋值name
Field nameField = clazz.getDeclaredField("name");
Person person = new Person("灰灰渣", 20);
// 暴力反射
nameField.setAccessible(true);
Object name = nameField.get(person);
System.out.println(name);
nameField.set(person, "社会梁");
System.out.println(person);
}
java.lang.String Person.id
private java.lang.String Person.name
public int Person.age
protected java.lang.String Person.address
----------------------------
灰灰渣
Person{id=‘null’, name=‘社会梁’, age=20, address=‘null’}
获取Class对象中的构造器
Constructor<?>[] getConstructors()
:获取所有public修饰的构造器。
Constructor<T> getConstructor(类<?>... parameterTypes)
:获取指定参数且public修饰的构造器。
Constructor<?>[] getDeclaredConstructors()
:获取所有方法,包括私有的构造器(private修饰的)
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
:获取指定参数的构造器包括私有的构造器。
constructor.newInstance(参数列表)
:通过该构造器,创建对象。
构造器对象.setAccessible(boolean)
:暴力反射,忽略访问权限修饰符的安全检查。
String getName()
:获取该构造器的名称。
@Test
public void test() throws Exception {
Class clazz = Class.forName("Person");
// 获取所有构造器(包含私有的)
Constructor[] constructors = clazz.getDeclaredConstructors();
for(Constructor constructor : constructors) {
System.out.println(constructor);
}
// 获取无参构造器
Constructor constructor0 = clazz.getDeclaredConstructor();
// 如果不设置,会发生IllegalAccessException异常
constructor0.setAccessible(true);
System.out.println("无参私有构造器----------------------");
System.out.println(constructor0.newInstance());
// 获取三个参数的构造函数
Constructor constructor3 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
System.out.println("三参公有构造器----------------------");
System.out.println(constructor3.newInstance("灰灰渣", 20, "青青草原"));
}
public Person(java.lang.String,int,java.lang.String)
public Person(java.lang.String,int)
private Person()
无参私有构造器----------------------
Person{name=‘null’, age=0, address=‘null’}
三参公有构造器----------------------
Person{name=‘灰灰渣’, age=20, address=‘青青草原’}
获取Class对象中的方法
Method[] getMethods()
:获取非私有的方法。
Method getMethod(String name, 类<?>... parameterTypes)
:获取指定名称公有的方法。
Method[] getDeclaredMethods()
:获取所有方法(包括私有)。
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
:获取指定名称方法。
方法对象.setAccessible(boolean b)
:暴力反射,忽略访问权限修饰符的安全检查。
Object invoke(Object obj, Object... args)
:执行方法。
String getName()
:获得方法名。
@Test
public void test() throws Exception {
Class clazz = Class.forName("Person");
// 获取所有方法(包括私有)
Method[] methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println(method);
}
Person person = new Person("灰灰渣", 20);
// 获取无参method方法
Method method0 = clazz.getDeclaredMethod("method");
// 暴力反射,忽略修饰符
method0.setAccessible(true);
method0.invoke(person);
// 获取单参method方法
Method method1 = clazz.getDeclaredMethod("method", String.class);
method1.invoke(person, "渣渣灰");
}
public java.lang.String Person.toString()
public void Person.method(java.lang.String)
private void Person.method()
私有方法
有参数公有方法渣渣灰