Java反射机制是肥肠重要的概念,它的原理以及如何使用,一起来探讨吧!

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

上面说的是反射的官方概念,其意思也就是,正常实例化对象的方式是:1、首先引入需要的包 2、new实例化 3、取得实例化对象 。而反射机制是“反”过来,通过实例化对象,可以获得此对象的属性,方法,所属类包的名称。反射是被视为动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。可以降低程序的耦合度,很多框架都运用了反射。

上面提到了反射是动态语言的关键,那么,上面是“动态语言”呢?

动态语言是指程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。C++,Java,C#都不是动态语言。尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。

Java的反射机制有什么功能?

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理

反射机制的相关类

类名

用途

Class

代表类的实体,在运行的Java应用程序中表示类和接口

Field

代表类的成员变量

Method

代表类的方法

Constructor

代表类的构造方法

Class类

1、创建Person类的对象

//Person.class 代表Person类
Class c = Person.class;
//创建Person类的实例p,相当于不使用反射创建的实例:Person p = new Person();
Person p = (Person)c.newInstance();

2、通过运行时类的对象,调用其getClass()方法,返回其运行时类。

Person per = new Person();
Class clazz = per.getClass();
System.out.println(clazz);

3、获取Class类的四种方式:

//1、调用运行时类本身的 .class 属性
Class c1 = Person.class;
//打印TestReflection.Person
System.out.println(clazz.getName());

Class c2= String.class;
//打印java.lang.String
System.out.println(c2.getName());


//2、 通过运行时类的对象获取
Person person = new Person();
Class c3 = person.getClass();
//打印TestReflection.Person
System.out.println(c3.getName());


//3、通过 class 的静态方法获取
String className = "TestReflection.Person";
Class c4 = Class.forName(className);
//打印TestReflection.Person
System.out.println(c4.getName());


//4、类的加载器
String className = "TestReflection.Person";
ClassLoader classLoader = this.getClass().getClassLoader();
Class c5 = classLoader.loadClass(className);
//打印TestReflection.Person
System.out.println(c5.getName());

Field类

1、获取Person类的访问控制符为public的指定成员变量

//Person.class 代表Person类
Class c = Person.class;

//创建Person类的实例p,相当于不使用反射创建的实例:Person p = new Person();
Person p = (Person)c.newInstance();

//获取类Person的public属性 name
Field f1 = c.getField("name");

//设定 Person类的对象 p 的 name 属性为 "Nikita",当Person的name属性的访问控制符为 public 时才可设定属性值。
f1.set(p,"Nikita");

//打印Nikita
System.out.println(p.name);

2、获取Person类的访问控制符为private的指定成员变量

//获取声明的Person类的private属性 age
Field f2 = c.getDeclaredField("age");
//使用反射机制访问私有变量时必须调用 setAccessible方法设置属性为true,否则会报 IllegalAccessException异常
f2.setAccessible(true);
//设置Person类的对象p的age属性值为 34
f2.set(p,34);
//打印 34
System.out.println(p.getAge());

3、获取Person类的所有 public属性

Class cla = Person.class;
//getFields():获取运行时类中及其父类中所有public属性
Field[] fields = cla.getFields();
for(int i =0;i<fields.length;i++) {
	//打印:public java.lang.String TestReflection.Person.name
    System.out.println(fields[i]);
}

4、获取 Person类的所有属性(包括private)

Class cla = Person.class;
//getDeclaredFields():获取运行时类本身的所有属性(包括private)
Field[] fields1 = cla.getDeclaredFields();
for(Field f:fields1){
    System.out.println(f.getName());
}

Method类

1、获取Person类的 getAge()方法

Class c = Person.class;
Person p = (Person)c.newInstance();
//获取Person类的 getAge方法
Method m1 = c.getMethod("getAge");
//Person类的对象p调用获取的 getAge 方法,如果此方法有参数,invoke第二个参数是 调用getAge方法需要的参数。
m1.invoke(p);

2、获取Person类的 display()方法

Class c = Person.class;
Person p = (Person)c.newInstance();
//获取 Person 类的 display方法,第二个参数为 display方法的参数类型
Method m2 = c.getMethod("display", String.class);
//调用display方法,参数为"CHN is very good!"
m2.invoke(p,"CHN is very good!");

3、getMethods():获取运行时类及其父类中所有声明为 public 的方法

Class ccc = Person.class;
Method[] method1 = ccc.getMethods();
for(Method m :method1) {
    System.out.println(m);
}

4、getDeclareMethods():获取运行时类的所有方法(包括 private)

Class ccc = Person.class;
Method[] method2 = ccc.getDeclareMethods();
for(Method m :method2) {
    System.out.println(m);
}

Constructor类

获取类中所有构造函数

String className = "TestReflection.Person";
Class c = Class.forName(className);
Constructor[] cons = c.getDeclaredConstructors();
    for(Constructor con : cons){
        System.out.println(con);
    }
}

获取类的完整结构

包括:注解、权限修饰符、返回值类型、方法名、形参列表、异常类型

public  void test3() throws Exception{
       //获取类中方法的完整结构
       Class c = Person.class;
       Method[] method = c.getDeclaredMethods();
       for(Method m : method) {
           //1、注解
           Annotation[] ann = m.getAnnotations();
           for(Annotation a:ann){
               System.out.print(a);
           }

           //2、权限修饰符
           String str = Modifier.toString(m.getModifiers());
           System.out.print(str+" ");

           //3、返回值类型
           Class returnType = m.getReturnType();
           System.out.println(returnType.getName()+" ");

           //4、方法名
           System.out.println(m.getName());

           //5、形参列表
           System.out.print("(");
           Class[] params = m.getParameterTypes();
           for(int i = 0;i<params.length;i++){
               System.out.print(params[i].getName()+" args-"+i+" ");
           }
           System.out.println(")");

           //6、异常类型
           Class [] exps = m.getExceptionTypes();
           if(exps.length != 0){
               System.out.print("throws ");
           }
           for(int i = 0;i < exps.length;i++) {
               System.out.print(exps[i].getName() + "");
           }
       }
    }