Java基础-反射应用

反射基本应用

反射进行对象实例化

在JDK1.8及以前的实例化:

1
2
@Deprecated(since="9")
public T newInstance() throws InstantiationException, IllegalAccessException

在JDK1.9+的实例化:

1
clazz.getDeclaredConstructor().newInstance()

示例代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package model;
/**
* @Author: kittydaddy
* @Description: 课程对象
* @Date: 2020-04-28 22:01
*/
public class Course {
public Course(){
System.out.println("***课程类被初始化了***");
}
@Override
public String toString() {
return "这是一门总课程列表";
}
}
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
package demo;
/**
* @Author: kittydaddy
* @Description: 创建对象例子
* @Date: 2020-04-28 22:04
*/
public class CreateInstanceDemo {
public static void main(String[] args) throws Exception {
System.out.println(oldBefore18());
System.out.println(newAfter19());
}
/**
* JDK1.8以及1.8以前
* @return
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static String oldBefore18() throws Exception {
Class courseClass = Class.forName("model.Course");
return courseClass.newInstance().toString();
}
/**
* JDK1.9以及1.9之后
* @return
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static String newAfter19() throws Exception {
Class courseClass = Class.forName("model.Course");
return courseClass.getDeclaredConstructor().newInstance().toString();
}
}

运行结果如下:

1
2
3
4
***课程类被初始化了***
这是一门总课程列表
***课程类被初始化了***
这是一门总课程列表

可想而知是被初始化了两次,由于本人用的是JDK11,所以在写JDK1.8包含这以前的代码的时候有作废的标记,由于复制出来的原因,标记无法展示出来,大家可以复制本人代码尝试一下即可。

反射进行类操作

一个类的基本组成是结构是:父类、父接口、包、属性以及方法(构造方法、普通方法),接下来的一个例子用反射的方式去获取相关类成分属性。

1
2
3
4
//课程接口
public interface ICourseService {
void learn();
}
1
2
3
4
//Java课程接口
public interface IJavaCourseService {
boolean pay();
}
1
2
3
//父类抽象类
public abstract class AbstractBase {
}
1
2
3
4
5
6
7
8
9
10
11
//学生对象
public class Student extends AbstractBase implements IJavaCourseService, ICourseService {
public void learn() {
if(this.pay()){
System.out.println("学员有权限学习该Java课程");
}
}
public boolean pay() {
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* @Author: kittydaddy
* @Description: 类相关属性操作例子
* @Date: 2020-05-06 15:00
*/
public class StudentPropertyOperateDemo {
public static void main(String[] args){

Class studentClass = Student.class;//获取学生的类对象
Package sPackage = studentClass.getPackage();//获取指定类的包定义
System.out.println("获取包名称: " + sPackage.getName());

Classsuper Student> superClass = studentClass.getSuperclass();//获取子类的父类名称
System.out.println("Person获取父类: " + superClass.getName()) ;
System.out.println("superclass获取父类: " + superClass.getSuperclass().getName());

Class[] interfaces = studentClass.getInterfaces();//获取所有父类接口信息

for (int i = 0; i < interfaces.length; i++) {
System.out.println("获取父接口" + (i + 1) + ": " + interfaces[i].getName());
}

}
}

运行结果

1
2
3
4
5
获取包名称: model
Person获取父类: service.AbstractBase
superclass获取父类: java.lang.Object
获取父接口1: service.IJavaCourseService
获取父接口2: service.ICourseService

以上为简单的获取类属性相关例子,再此不细致去尝试每个方法,有兴趣可自行尝试。

反射调用构造方法

接下来介绍反射如何操作构造方法。

采用同样的类,我们给Person这个类新增两个构造器,一个是有参构造器一个是无参构造器,并且重写了toString方法方便其输出对象时候打印格式化。

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* @Author: maoba
* @Description: 学生对象
* @Date: 2020-04-30 17:32
*/
public class Student extends AbstractBase implements IJavaCourseService, ICourseService {
public Student(){

}

public Student(String name,Integer age){
this.name = name;
this.age = age;
}

private String name;

private Integer age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
public void learn() {
if(this.pay()){
System.out.println("学员有权限学习该Java课程");
}
}

public void learn(String courseType){
if(this.pay()){
System.out.println("学员有权限学习该Java课程"+courseType);
}
}

public boolean pay() {
return true;
}

@Override
public String toString() {
return "name["+name+"]"+"age["+age+"]";
}
}

主要获取方式代码如下:

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
/**
* @Author: mao ba
* @Description: 构造方法反射demo
* @Date: 2020-05-07 22:32
*/
public class ConstructorDemo {
public static void main(String[] args) throws Exception {
Class studentClass = Student.class;
//获取当前类所有的构造器
Constructor[] constructors = studentClass.getDeclaredConstructors();

for (Constructor constructor : constructors){
System.out.println("方法1获取所有构造器-"+constructor);
}

Constructor[] constructorList = studentClass.getConstructors();
for (Constructor constructor : constructorList){
System.out.println("方法2获取构所有造器-"+constructor);
}

//获取带有参数的构造方法
Constructor studentConstructor = studentClass.getConstructor(String.class,Integer.class);
System.out.println("获取指定参数构造器-"+studentConstructor);

//利用构造器实例化数据
Student student = studentConstructor.newInstance("张三",12);
System.out.println("实例化结果-"+student);
}
}

运行结果输出:

1
2
3
4
5
6
方法1获取所有构造器-public model.Student()
方法1获取所有构造器-public model.Student(java.lang.String,java.lang.Integer)
方法2获取构所有造器-public model.Student()
方法2获取构所有造器-public model.Student(java.lang.String,java.lang.Integer)
获取指定参数构造器-public model.Student(java.lang.String,java.lang.Integer)
实例化结果-name[张三]age[12]

反射调用普通方法

Student的代码不重复输出了,依旧采用上述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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package demo;

import model.Student;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
* @Author: maoba
* @Description: 获取执行普通方法
* @Date: 2020-05-08 22:58
*/
public class MethodDemo {
public static void main(String[] args) throws Exception{
Class studentClass = Student.class;
//获取本地方法以及其父类中方法
Method[] methods = studentClass.getMethods();
for(Method method : methods){
System.out.println(method);
}

System.out.println("------------------------");
//获取本地方法不包含父类方法
Method[] nativeMethods = studentClass.getDeclaredMethods();
for(Method method : nativeMethods){
System.out.println(method);
}

System.out.println("------------------------");

for(Method method:nativeMethods){

String modifier = Modifier.toString(method.getModifiers());//获取访问修饰符,例如public,private等等
String returnType = method.getReturnType().getName();//获取返回值的类型
String methodName = method.getName();//方法名称
Class[] parameterTypes = method.getParameterTypes();//获取当前方法的参数类型
StringBuffer buffer = new StringBuffer();
buffer.append("(");
for(int i = 0;i
buffer.append(parameterTypes[i].getName()).append(" ");
buffer.append("arg"+i);
}
buffer.append(")");

System.out.println(modifier +" " +returnType +" "+ methodName +" "+buffer.toString());
}


System.out.println("------------------------");

//通过invoke的方式调用本地的方法,利用get,set方法为例子
String methodSetName = "setName";
String nameValue = "张三";
//实例话无参对象
Object object = studentClass.getDeclaredConstructor().newInstance();
//获取setName这个防范
Method setMethod = studentClass.getDeclaredMethod(methodSetName,String.class);
//执行方法,设置当前对象的名称
setMethod.invoke(object,nameValue);

String methodGetName = "getName";
Method getMethod = studentClass.getDeclaredMethod(methodGetName);
System.out.println(getMethod.invoke(object));
}
}

最终输出结果:

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
public java.lang.String model.Student.toString()
public java.lang.String model.Student.getName()
public void model.Student.setName(java.lang.String)
public void model.Student.learn(java.lang.String)
public void model.Student.learn()
public boolean model.Student.pay()
public java.lang.Integer model.Student.getAge()
public void model.Student.setAge(java.lang.Integer)
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) 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 model.Student.toString()
public java.lang.String model.Student.getName()
public void model.Student.setName(java.lang.String)
public void model.Student.learn(java.lang.String)
public void model.Student.learn()
public boolean model.Student.pay()
public java.lang.Integer model.Student.getAge()
public void model.Student.setAge(java.lang.Integer)
------------------------
public java.lang.String toString ()
public java.lang.String getName ()
public void setName (java.lang.String arg0)
public void learn (java.lang.String arg0)
public void learn ()
public boolean pay ()
public java.lang.Integer getAge ()
public void setAge (java.lang.Integer arg0)
------------------------
张三

反射调用成员

我们往Student以及其父类AbstractBase类中分别加上一个公有的属性。改动之后,两个类的代码如下。

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* @Author: mao ba
* @Description: 学生对象
* @Date: 2020-04-30 17:32
*/
public class Student extends AbstractBase implements IJavaCourseService, ICourseService {
public Student(){

}
public Student(String name,Integer age){
this.name = name;
this.age = age;
}

private String name;

private Integer age;

public String learnCourseName;

public String getLearnCourseName() {
return learnCourseName;
}

public void setLearnCourseName(String learnCourseName) {
this.learnCourseName = learnCourseName;
}

public void learn() {
if(this.pay()){
System.out.println("学员有权限学习该Java课程");
}
}

public void learn(String courseType){
if(this.pay()){
System.out.println("学员有权限学习该Java课程"+courseType);
}
}

public boolean pay() {
return true;
}

@Override
public String toString() {
return "name["+name+"]"+"age["+age+"]";
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

对应的父类的类代码如下

1
2
3
4
5
public abstract class AbstractBase {
public AbstractBase(){}
public AbstractBase(String name){}
public String BaseCourseName;
}

获取相对应的成员变量的例子

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
/**
* @Author: maoba
* @Description: 反射获取变量成员
* @Date: 2020-05-10 14:33
*/
public class GetFieldDemo {
public static void main(String[] args) throws Exception{
Class stuClass = Student.class;
//获取本地类以及父类的公有成员
Field[] fields = stuClass.getFields();

for (Field field : fields) {
System.out.println(field);
}
System.out.println("---------------");
//获取本地类所有的成员,包括私有成员变量
Field[] fields1 = stuClass.getDeclaredFields();

for (Field field : fields1) {
System.out.println(field);
}
System.out.println("---------------");
//调用私有成员变量
Field field = stuClass.getDeclaredField("name");
Object obj = stuClass.getDeclaredConstructor().newInstance();
field.setAccessible(true);//为了能够解除该封装
field.set(obj,"张三");
System.out.println(field.get(obj));//获取属性的名称
}
}

最终输出结果:

1
2
3
4
5
6
7
8
public java.lang.String model.Student.learnCourseName
public java.lang.String service.AbstractBase.BaseCourseName
---------------
private java.lang.String model.Student.name
private java.lang.Integer model.Student.age
public java.lang.String model.Student.learnCourseName
---------------
张三

以上demo简单介绍了一下相关的api的用法,大家感兴趣的话可以自行尝试更多方法。这些都是相关的基础,后面我们研究一下相关的设计模式,在研究设计模式的时候,我会给大家用上相关的反射去实现对应的设计模式。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×