Java——反射(Reflect)

1、什么是反射机制?

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

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。

2、Java反射机制的作用

(1)在运行时判断任意一个对象所属的类。

(2)在运行时判断任意一个类所具有的成员变量和方法。

(3)在运行时任意调用一个对象的方法。

(4)在运行时构造任意一个类的对象。

3、Java反射的应用

在Java程序中许多对象在运行时都会出现两种类型:编译时类型运行时类型

编译时的类型由声明该对象时使用的类型决定,运行时的类型由实际赋给对象的类型决定。

如:Person p =new Student();

编译时类型为Person,而运行时为Student

除此之外,程序在运行时还可能接收到外部传入的一个对象,该对象的编译时类型为Object,但程序又需要调用该对象运行时类型的方法。为了这些问题程序需要在运行时发现对象和类的真实信息。然而,如果编译时根本无法预知该对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,此时就必须使用反射。

4、在哪里用到反射机制

很多框架都用到反射机制,如hibernate、struts、spring,反射最经典的应用是spring框架。

jdbc中,有一行获取数据库驱动对象实例的代码,这就是反射:

1
Class.forName('com.MySQL.jdbc.Driver.class').newInstance();

5、反射机制的优缺点

优点:可以动态的创建对象和编译,最大限度发挥了java的灵活性。 比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。

缺点:对性能有影响。使用反射基本上一种解释操作,告诉JVM我们要做什么并且满足我们的要求,这类操作总是慢于直接执行java代码。

6、Java反射API

反射API用来生成在当前JAVA虚拟机中的类、接口或者对象的信息。

  • Class类:反射的核心类,可以获取类的属性,方法等内容信息。

  • Field类:Java.lang.reflect.表示类的属性,可以获取和设置类的中属性值。

  • Method类:Java.lang.reflect。表示类的方法,它可以用来获取类中方法的信息或者执行方法。

  • Construcor类:Java.lang.reflect。表示类的构造方法。

7、通过反射获取类的三种方法

1
2
3
4
5
6
7
8
9
10
11
//1、第一种方式-->Class.forName("类名字符串");
//注:类名字符串是"包名+类名" 返回Class的对象。(这种是最常用的方法)
Class c1=Class.forName("csdn.Student");
//2、第二种方式-->先创建对象,再用对象调用getClass()方法,即实例对象.getClass().返回运行时类。
//任何一个java对象都有getClass()方法
Student s=new Student();
Class c2 = s.getClass();
//3、第三种方式-->类名.class。返回Class的对象。(每个类都有class属性)
Class c3=Student.class;

8、通过反射可以获取到的主要描述信息

  • 获得属性

获得属性

  • 获得方法

获得方法

  • 获得构造方法

获得构造方法

  • 获得其他信息

获得其他信息

9、关于反射的小demo

父类:Person类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package reflect;
public class Person {
public String name;// 姓名
public int age;// 年龄
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String showInfo() {
return "name=" + name + ", age=" + age;
}
}

子类:Student类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package reflect;
public class Student extends Person implements Study {
public String className;// 班级
private String address;// 住址
public Student() {
super();
}
public Student(String name, int age, String className, String address) {
super(name, age);
this.className = className;
this.address = address;
}
public Student(String className) {
this.className = className;
}
public String toString() {
return "姓名:" + name + ",年龄:" + age + ",班级:" + className + ",住址:"+ address;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}

接口:Study

1
2
3
4
5
package reflect;
public interface Study {
//仅为了演示获得接口,就没有写抽象方法
}

获得属性:

1
2
3
4
5
6
7
8
9
10
11
12
Class stu = Class.forName("reflect.Student");
// 获取对象的所有公有属性。
Field[] fields = stu.getFields();
for (Field f : fields) {
System.out.println(f);
}
System.out.println("---------------------");
// 获取对象所有属性,但不包含继承的。
Field[] declaredFields = stu.getDeclaredFields();
for (Field ff : declaredFields) {
System.out.println(ff);
}

运行结果:

public java.lang.String reflect.Student.className
public java.lang.String reflect.Person.name
public int reflect.Person.age
-——————–
public java.lang.String reflect.Student.className
private java.lang.String reflect.Student.address

获得方法:

1
2
3
4
5
6
7
8
9
10
11
12
Class stu = Class.forName("reflect.Student");
// 获取对象的所有公共方法
Method[] methods = stu.getMethods();
for (Method m : methods) {
System.out.println(m);
}
System.out.println("---------------------");
// 获取对象所有方法,但不包含继承的
Method[] declaredMethods = stu.getDeclaredMethods();
for (Method ms : declaredMethods) {
System.out.println(ms);
}

运行结果:

public java.lang.String reflect.Student.toString()
public java.lang.String reflect.Student.getAddress()
public void reflect.Student.setAddress(java.lang.String)
public java.lang.String reflect.Person.showInfo()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
-——————–
public java.lang.String reflect.Student.toString()
public java.lang.String reflect.Student.getAddress()
public void reflect.Student.setAddress(java.lang.String)

获得其他:

1
2
3
4
5
6
7
Class stu = Class.forName("reflect.Student");
System.out.println(stu.getName());//获取对象全限定名称
System.out.println(stu.getPackage());// 获取包名
Class[] interfaces = stu.getInterfaces();//获取该类实现的所有接口
for(Class in:interfaces){
System.out.println(in);
}

reflect.Student

package reflect

interface reflect.Study

通过反射实例化对象,调用对象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class TestReflect {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
try {
Class c = Class.forName("reflect.Student");
Student stu = (Student) c.newInstance();
// 第一种方法,实例化默认构造方法,调用set赋值
stu.setAddress("深圳南山");
System.out.println(stu);
// 第二种方法 取得全部的构造函数 使用构造函数赋值
Constructor<Student> constructor = c.getConstructor(String.class,
int.class, String.class, String.class);
Student s = (Student) constructor.newInstance("李四", 18, "七班", "深圳");
System.out.println(s);
Method show = c.getMethod("showInfo");//获取showInfo()方法
System.out.println(show.invoke(s));//调用showInfo()方法
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果为:

姓名:null,年龄:0,班级:null,住址:深圳南山
姓名:李四,年龄:18,班级:七班,住址:深圳
name=李四, age=18

您的支持将鼓励我继续创作~