JAVA - reflection ( 反射 )
-----------------------------------------------------------------------------------------------------------------------------------
什么是反射 ?
其实就是通过Class 类实例, 返回该类相关的成员,函数,加载器,父类,接口,包等类信息。
事例:反射就好像镜子,你背对着我,我看不见你,假设你前方有一面镜子,虽然我看不见你,但是可以通过镜子看见你。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在 java.lang 包下,有一个 Class 类 。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
其实,每一个类被加载之后,系统就会为该类生成一个对应的 Class 对象,所以不用我们实例化 Class对象。
那么问题来了,如何取得 Class 对象 ?
通过3种方式获取: 1. Class.forName(String className)
2. 类名.class
3. 实例化对象调用 getClass 方法
下面演示3种方式:
class ClassTest
{
public static void main(String[] args) throws Exception {
//第一种方式:
Class c1 = Class.forName("ClassTest"); //注意:这种方式会引发ClassNotFoundException异常。
//第二种方式:
Class c2 = ClassTest.class;
//第三种方式:
ClassTest ct = new ClassTest();
Class c3 = ct.getClass();
System.out.println("第 1 种方式: "+c1.getName());
System.out.println("第 2 种方式: "+c2.getName());
System.out.println("第 3 种方式: "+c3.getName());
/*
printOut:
第 1 种方式: ClassTest
第 2 种方式: ClassTest
第 3 种方式: ClassTest
*/
}
}
从输出结果发现, 所有类的对象其实都是Class的实例。 (果然是万物皆对象,类其实也是一种对象 )
下面演示Class示例:
import java.lang.reflect.*;
class Person
{
private String name;
public int age;
public String content;
String ccc;
protected String qqq;
Person(){
System.out.println("执行了空参数的构造方法");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name, int age, String content) {
this(name, age);
this.content = content;
}
public String toString() {
return "姓名"+name+" 年龄:"+age;
}
public void method_1() {
System.out.println("it is my public method one");
}
public void method_1(String str) {
System.out.println("it is my public method one");
}
private void method_2(String str, int age) {
System.out.println("it is my private method one");
}
}
class ClassTest
{
public static void main(String[] args) throws Exception {
Person p = new Person("zhangsan", 18);
Class cls = p.getClass();
Person p1 = (Person) cls.newInstance(); //该方法调用对象中空参数构造方法
//如果该对象不具备空参数的构造方法
//则会引发异常 java.lang.InstantiationException
/* Constructor 类 【构造方法】 */
//获取所有被public修饰的构造方法
Constructor[] c1 = cls.getConstructors();
//获取所有构造方法
Constructor[] c2 = cls.getDeclaredConstructors();
//获取指定构造方法,只能是public
Constructor c3 = cls.getConstructor(String.class, int.class);
//获取任意指定构造方法
Constructor c4 = cls.getDeclaredConstructor(String.class, int.class, String.class);
/* Field 类 【成员】 */
//获取指定成员,注意:只能是被public修饰的成员
Field f1 = cls.getField("age");
//获取对象中所有被public修饰的成员
Field[] f2 = cls.getFields();
//获取任意指定成员
Field f3 = cls.getDeclaredField("name");
//获取对象所有成员
Field[] f4 = cls.getDeclaredFields();
/* Method 类 【方法】 */
//获取指定方法,注意:只能是被public修饰的成员
Method m1 = cls.getMethod("method_1"); //注意,第一参数后面可以跟0..n个参数。必须要有一个参数。
//获取对象中所有被public修饰的方法
Method[] m3 = cls.getMethods();
//获取任意指定方法,注意,第一参数后面可以跟0..n个参数。必须要有一个参数。
Method m4 = cls.getDeclaredMethod("method_2",String.class,int.class);
//获取对象所有方法
Method[] m5 = cls.getDeclaredMethods();
}
}
上面抽取了部分的方法,还有很多方法,例如包,接口,类加载器等等就略过了,拿的是比较常用的举例。
下面演示下反射的应用示例:
import java.lang.reflect.*;
class Demo
{
public String s1, s2, s3;
Demo(String s1, String s2, String s3)
{
this.s1 = s1;
this.s2 = s2;
this.s3 = s3;
}
public String toString()
{
return s1+"..."+s2+"..."+s3;
}
public static void main(String[] args) throws Exception
{
method_1();
method_2();
method_3();
}
/* 通过反射 调用构造函数 */
public static void method_1() throws Exception
{
Constructor constructor = String.class.getConstructor(StringBuffer.class);
String value = (String) constructor.newInstance(new StringBuffer("abc"));
System.out.println(value);
}
/* 通过反射 调用对象方法 */
public static void method_2() throws Exception {
String str = "abcde";
Method m = String.class.getMethod("charAt", int.class);
System.out.println(m.invoke(str, 2));
}
/* 通过反射 调用对象成员 */
public static void method_3() throws Exception {
Demo d = new Demo("abc", "abb", "bbc");
Class cls = d.getClass();
Field[] f = cls.getFields();
for(Field field : f)
{
if(field.getType() == String.class)
{
String oldValue = (String) field.get(d);
String newValue = oldValue.replace('b','a');
field.set(d, newValue);
}
}
System.out.println(d);
}
}