logo头像

一路过来,不过游牧自己。。

反射你懂么?


话说在看了《java编程思想》之后,一直觉着书里对于反射的描述实在太深奥,云里雾里,所以今天决定要总结总结,他是干嘛的,有哪些用处,都会一一道来!

一、反射定义

在运行状态中,对任意的一个类,都能知道这个类的所有属性和方法,对任意一个对象,都能调用它的任意方法和属性(包括私有!),这种动态获取信息以及动态调用对象的功能称之为反射机制!
反射拿的是class文件对象,去使用该文件中放入的成员变量,构造方法,成员方法!
以前我们创建对象的方式都是类似:
Person p=new Person();
但是仙子啊获取一个对象的方式变成获取class文件对象!
一个class类包含:
成员变量 Field
构造方法 constructor
成员方法 Method

获取class文件的对象的方式有三种:
A: Object类的getclass方法
B: 数据类型的静态属性class
C: Class 类中的静态方法

二、获取对象的三种方式

(1) Object类的getclass方法

1
2
3
4
5
6
  Person p=new Person();
Class c=p.getClass();
Person p1=new Person();
Class c1=p1.getClass();
System.out.println(p==p1);
System.out.println(c==c1);

看结果:

1
2
false
true

为什么呢? 我们知道,==比的是地址值,p和p1是两个完全不同的对象,所以结构肯定是false
但是对于Class来说,他们都是只有一个class文件,所以c与c1都相等

(2)数据类型的静态属性class

1
2
Class c3=Person.class;
System.out.println(c3==c);

结果还是true

(3) Class 类中的静态方法

1
2
Class c4=Class.forName("Person");
System.out.println(c4==c3);

但是这里要注意的是forName后面的参数要求的是一个全路径,就是要带包名的那种!结果还是true

三、反射作用

1、获取构造方法

代码如下:

1
2
3
4
5
Class c4=Class.forName("Person");
Constructor[] cons=c4.getConstructors();
for(Constructor con:cons){
System.out.println(con);
}

这里的Constructors获取的是所有的公共构造方法!

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
ublic class Person {
private String name ;
private int age;
private String sex;

public Person() {
super();
}
public Person(String name){

this.name = name;
}

Person(String name, int age) {
super();
this.name = name;
this.age = age;
}

private Person(String name, int age,String sex) {
this.name = name;
this.age = age;
this.sex=sex;
}

}

这是person类的一个写法
在运行之后,结果是:

1
2
public Person()
public Person(java.lang.String)

我们可以看到,两个public类型的构造函数都被输出了!所以此方法就是获取的公共的构造方法
但是如果要获取所有的构造方法呢?包括private类型的?

1
2
3
4
5
Class c4=Class.forName("Person");
Constructor[] cons1=c4.getDeclaredConstructors();
for(Constructor con:cons1){
System.out.println(con);
}

这里用了getDeclaredConstructors,所以可以得到所有的构造函数!
结果是:

1
2
3
4
public Person()
public Person(java.lang.String)
Person(java.lang.String,int)
private Person(java.lang.String,int,java.lang.String)

这样就获得了所有的构造方法

2、获取单个构造方法

有时候,我们不仅仅只是想要获得所有的构造方法,还要想获得单个构造方法:
(1)获取单个无参构造方法:

1
2
3
Class c4=Class.forName("Person");
Constructor con=c4.getConstructor();
System.out.println(con);

结果:

1
public Person()

利用这个构造函数来创建一个对象:

1
Object obj=con.newInstance();

获取有参的构造函数并实例化对象:

1
2
3
4
Class c4=Class.forName("Person");
Constructor con=c4.getConstructor(String.class);
Object obj=con.newInstance("fang");
System.out.println(obj);

输出为:

1
Person [name=fang, age=0, sex=null]

这里重写了tostring方法

(2)获取私有的单个构造方法:

1
2
3
4
5
Class c4=Class.forName("Person");
Constructor con=c4.getDeclaredConstructor(String.class,int.class,String.class);
con.setAccessible(true);
Object obj=con.newInstance("fang",22,"nan");
System.out.println(obj);

这里有三个参数的构造方法是private的,所以我们要getDeclaredConstructor来获得,但是不要忘了有con.setAccessible(true);
这样就可以访问了,结果:

1
Person [name=fang, age=22, sex=nan]

3、获取成员变量:

我把Person类中的age字段改变为public,于是下面这行代码结果是:

1
2
3
4
5
Class c4=Class.forName("Person");
Field[] fields=c4.getFields();
for(Field filed:fields){
System.out.println(filed);
}

结果:

1
public int Person.age

只输出了一个age参数
那如果要获得所有的呢?用getDeclaredFields(),这样就获得所有的:

1
2
3
4
5
Class c4=Class.forName("Person");
Field[] fields=c4.getDeclaredFields();
for(Field filed:fields){
System.out.println(filed);
}

结果:

1
2
3
private java.lang.String Person.name
public int Person.age
private java.lang.String Person.sex

那如果想获取单个变量呢:

1
2
3
4
5
Class c4=Class.forName("Person");
Object obj=c4.newInstance();
Field Agefield=c4.getField("age");
Agefield.set(obj, 22);
System.out.println(obj);

这样就可以获得一个对象的public的age字段!
输出的结果:

1
Person [name=null, age=22, sex=null]

如果是私有的呢?

1
2
3
4
5
6
Class c4=Class.forName("Person");
Object obj=c4.newInstance();
Field Agefield=c4.getDeclaredField("name");
Agefield.setAccessible(true);
Agefield.set(obj, "方");
System.out.println(obj);

结果就是:

1
Person [name=方, age=0, sex=null]

4、反射获得成员方法

(1)获得所有方法

首先获得所有的public的方法:

1
2
3
4
5
Class c4=Class.forName("Person");
Method[] methods=c4.getMethods();
for(Method method:methods){
System.out.println(method);
}

输出结果很多,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public java.lang.String Person.toString()
public java.lang.String Person.getName()
public void Person.setName(java.lang.String)
public int Person.getAge()
public void Person.setAge(int)
public java.lang.String Person.getSex()
public void Person.setSex(java.lang.String)
public void Person.show()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
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 native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public boolean java.lang.Object.equals(java.lang.Object)
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

很多都是从父类继承下来的,所以很多
获得私有方法呢?

1
2
3
4
5
Class c4=Class.forName("Person");
Method[] methods=c4.getDeclaredMethods();
for(Method method:methods){
System.out.println(method);
}

结果就是如下了

1
2
3
4
5
6
7
8
9
public java.lang.String Person.toString()
public java.lang.String Person.getName()
public void Person.setName(java.lang.String)
public int Person.getAge()
public void Person.setAge(int)
public java.lang.String Person.getSex()
public void Person.setSex(java.lang.String)
public void Person.show()
private java.lang.String Person.getA()

(2)获得单个方法:

A、首先是不带参和返回参数的:

代码如下:

1
2
3
4
5
Class c4=Class.forName("Person");
Constructor con=c4.getConstructor();
Object obj=con.newInstance();
Method m1=c4.getMethod("show");
m1.invoke(obj);

最主要的就是这个invoke方法!
结果就是执行show方法

B、带参和有返回值的:

1
2
3
4
5
6
7
Class c4=Class.forName("Person");
Constructor con=c4.getConstructor();
Object obj=con.newInstance();
Method m1=c4.getDeclaredMethod("getA",String.class);
m1.setAccessible(true);
Object str=m1.invoke(obj,"fang");
System.out.println(str);

如上所示,就可以用invoke来调用私有方法!
这样就基本将反射弄完了,反射在项目框架中很有作用,是动态代理的基本原理,所以,好好感受是没错的!

多走路,多思考,越努力,越幸运!
———————————————YoungerFary

微信打赏

赞赏是不耍流氓的鼓励