Java反射机制

反射是Java最为重要的特性,几乎所有的开发框架以及应用技术都是基于反射技术的应用,本文主要讲解反射机制的作用,以及如何利用反射实现类结构的操作

认识反射

在正常的类操作中,一定是先要确定使用的类,在利用new关键字产生实例化对象后使用。但如果要通过对象取得此对象所在类的信息,就可以通过Object类中的getClass()方法实现

1
2
Date date = new Date();
System.out.println(date.getClass());

Class类对象实例化

当使用getClass()方法时,返回的类型是java.lang.Class,这是反射操作的源头类,即所有的反射操作都通过此类开始,而最关键的是这个类有以下3中实例化方式

调用Object类的getClass()方法

此类操作必须有实例化对象

1
2
3
Date date = new Date();
Class<?> cls = date.getClass(); // 通过实例化对象取得Class对象
System.out.println(cls.getName()); // 获得所在类名称

使用“类.class”取得

此时可以不需要通过指定类的实例化对象取得

1
2
3
Date date = new Date();
Class cls2 = java.util.Date.class; // 通过类名称获取Class类对象
System.out.println(cls2.getName()); // 获取类名

调用Class类提供的方法

此方法使用Class类中的forName()方法,这样只要提供要反射操作的类的具体名称就可以取得反射操作类对象,但前提是此类确实存在,否则会抛出ClassNotFoundException异常

1
2
Class<?> cls3 = Class.forName("java.util.Date");
System.out.println(cls3.getName());

反射实例化对象

反射操作中类或接口都是利用Class来进行包装的,同时利用Class类可以表示任意类、枚举、接口、数组等引用类型的操作。
Class类中最重要的方法就是newInstance()方法,通过此方法可以利用反射实现Class类包装类型的对象实例化操作,即不用关键词new也可以进行对象实例化操作。

利用反射实例化对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Book {
public Book() {
System.out.println("----Book类的无参构造方法");
}
@Override
public String toString() {
return "名师讲坛--java开发经典";
}
}

// 利用反射实例化对象
Class<?> cls4 = Class.forName("JavaCommonClassLibrary.Book");
Object obj = cls4.newInstance(); // 实例化返回的都是Object对象
Book book = (Book)obj;
System.out.println(book);

利用反射实现工厂设计模式

使用new关键字实例化对象需要明确指出类的构造方法,所以new是造成耦合的最大元凶
之前曾经讲过工厂设计模式,但当时的工厂设计模式存在一个缺陷:每次增加新的接口子类时都需要修改修改工厂类,这就是new带来的问题,现在利用反射就可以解决此缺陷

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
33
34
35
36
37
38
// 利用反射实现工厂设计模式

interface Fruit{
public void eat();
}

class Apple implements Fruit{
@Override
public void eat() {
System.out.println("吃苹果!");
}
}

class Orange implements Fruit{
@Override
public void eat() {
System.out.println("吃橘子!");
}
}

class Factory{
public static Fruit getInstance(String className) {
Fruit f = null;
try {
f = (Fruit)Class.forName(className).newInstance();
}catch(Exception e) {}
return f;
}
}

public class ReflexFactoryLearning {
public static void main(String[] args) {
Fruit fa = Factory.getInstance("JavaCommonClassLibrary.Apple");
Fruit fb = Factory.getInstance("JavaCommonClassLibrary.Orange");
fa.eat();
fb.eat();
}
}

使用反射调用构造

使用Class类的newInstance()实现对象实例化存在限制,就是类中必须提供无参构造方法
要调用类中的有参构造方法,必须通过java.lang.reflect.Constructor来实现有参的反射实例化操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Book2 {
private String title;
private double price;
public Book2(String title, double price) {
this.price = price;
this.title = title;
}
@Override
public String toString() {
return "书名:"+this.title+",价格:"+this.price;
}
}

// 明确调用类中的有参构造
Class<?> cls5 = Class.forName("JavaCommonClassLibrary.Book2");
Constructor<?> con = cls5.getConstructor(String.class, double.class); // 明确找到Book2中的某个带参构造
Object obj2 = con.newInstance("Java开发实战经典", 79.8);
System.out.println(obj2);

先利用Class类对象取得特定构造方法,然后利用Constructor类中的newInstance()方法传递指定参数,就可以调用有参构造了。

使用反射调用方法

以往都是通过“对象.方法()”的形式调用方法,现在可以利用反射实现类方法的调用。可以利用Class类和Method类完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Book3 {
private String title;
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return this.title;
}
}

public static String initcap(String str) {
return str.substring(0, 1).toUpperCase()+str.substring(1);
}

// 反射调用方法
String fieldName = "title";
Class<?> cls6 = Class.forName("JavaCommonClassLibrary.Book3");
Object obj3 = cls6.newInstance();
Method setMet = cls6.getMethod("set"+initcap(fieldName), String.class);
Method getMet = cls6.getMethod("get"+initcap(fieldName));
setMet.invoke(obj3, "Java源码分析实录"); // 使用invoke调用目标方法
System.out.println(getMet.invoke(obj3));

反射调用私有成员

反射可以进行成员的操作,可以通过Class类和Field类完成

1
2
3
4
5
6
7
8
9
10
11
class Book4 {
private String title;
}

// 反射调用私有成员
Class<?> cls7 = Class.forName("JavaCommonClassLibrary.Book4");
Object obj4 = cls7.newInstance();
Field titleField = cls7.getDeclaredField("title");
titleField.setAccessible(true);
titleField.set(obj4, "Java绝密宝典");
System.out.println(titleField.get(obj4));

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 认识反射
  2. 2. Class类对象实例化
    1. 2.1. 调用Object类的getClass()方法
    2. 2.2. 使用“类.class”取得
    3. 2.3. 调用Class类提供的方法
  3. 3. 反射实例化对象
    1. 3.1. 利用反射实例化对象
    2. 3.2. 利用反射实现工厂设计模式
  4. 4. 使用反射调用构造
  5. 5. 使用反射调用方法
  6. 6. 反射调用私有成员