反射:框架设计的灵魂
测试的数据:
*
框架:半成品软件。可以在框架的基础上进⾏软件开发,简化编码
*
反射:将类的各个组成部分封装为其他对象,这就是反射机制
*
好处:
1.
可以在程序运⾏过程中,操作这些对象。
2.
可以解耦,提⾼程序的可扩展性。后期学习的
ssh
框架等框架都会⽤来
*
获取
Class
对象的⽅式:
1. Class.forName("
全类名
")
:将字节码⽂件加载进内存,返回
Class
对象
*
多⽤于配置⽂件,将类名定义在配置⽂件中。读取⽂件,加载类
2.
类名
.class
:通过类名的属性
class
获取
*
多⽤于参数的传递
,android
3.
对象
.getClass()
:
getClass()
⽅法在
Object
类中定义着。
*
多⽤于对象的获取字节码的⽅式
*
结论:
同⼀个字节码⽂件
(*.class)
在⼀次程序运⾏过程中,只会被加载⼀次,不论通过哪⼀种⽅式获取的
Class
对象
都是同⼀个。
package
domain
;
public class
Person
{
private
String
name
;
private
int
age
;
public
String
a
;
protected
String
b
;
String
c
;
private
String
d
;
public
Person
() {
}
public
Person
(
String
name
,
int
age
) {
this
.
name
=
name
;
this
.
age
=
age
;
}
public
String
getName
() {
return
name
;
}
public
void
setName
(
String
name
) {
this
.
name
=
name
;
}
public
int
getAge
() {
return
age
;
}
public
void
setAge
(
int
age
) {
this
.
age
=
age
;
}
@Override
public
String
toString
() {
return
"Person{"
+
"name='"
+
name
+
'\''
+
", age="
+
age
+
", a='"
+
a
+
'\''
+
", b='"
+
b
+
'\''
+
", c='"
+
c
+
'\''
+
", d='"
+
d
+
'\''
+
'}'
;
}
public
void
eat
(){
System
.
out
.
println
(
"eat..."
);
}
public
void
eat
(
String
food
){
System
.
out
.
println
(
"eat..."
+
food
);
}
}
package
domain
;
public class
Student
{
public
void
sleep
(){
System
.
out
.
println
(
"sleep..."
);
}
}
* Class
对象功能:
*
获取功能:
1.
获取成员变量们
* Field[] getFields()
:获取所有
public
修饰的成员变量
* Field getField(String name)
获取指定名称的
public
修饰的成员变量
//1.Class.forName("
全类名
")
Class cls1
=
Class
.
forName
(
"domain.Person"
);
System
.
out
.
println
(
cls1
);
//2.
类名
.class
Class cls2
=
Person
.
class
;
System
.
out
.
println
(
cls2
);
//3.
对象
.getClass()
Person p
=
new
Person
();
Class cls3
=
p
.
getClass
();
System
.
out
.
println
(
cls3
);
//==
⽐较三个对象
System
.
out
.
println
(
cls1
==
cls2
);
//true
System
.
out
.
println
(
cls1
==
cls3
);
//true
//
不同的字节码的
Class
对象不同
Class c
=
Student
.
class
;
System
.
out
.
println
(
c
==
cls1
);
//false
* Field[] getDeclaredFields()
获取所有的成员变量,不考虑修饰符
* Field getDeclaredField(String name)
2.
获取构造⽅法们
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(
类
<?>... parameterTypes)
* Constructor<T> getDeclaredConstructor(
类
<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()
3.
获取成员⽅法们:
* Method[] getMethods()
* Method getMethod(String name,
类
<?>... parameterTypes)
* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name,
类
<?>... parameterTypes)
4.
获取全类名
* String getName()
获取所有
public
修饰的成员变量
操作某⼀个字段:
a
获取所有的成员变量,不考虑修饰符
获取构造⽅法:
//0.
获取
Person
的
Class
对象
Class personClass
=
Person
.
class
;
//1.Field[] getFields()
获取所有
public
修饰的成员变量
Field
[]
fields
=
personClass
.
getFields
();
for
(
Field field
:
fields
) {
System
.
out
.
println
(
field
);
}
//2.Field getField(String name)
Field a
=
personClass
.
getField
(
"a"
);
//
获取成员变量
a
的值
Person p
=
new
Person
();
Object
value
=
a
.
get
(
p
);
System
.
out
.
println
(
value
);
//
设置
a
的值
a
.
set
(
p
,
"
张三
"
);
System
.
out
.
println
(
p
);
//0.
获取
Person
的
Class
对象
Class personClass
=
Person
.
class
;
Person p
=
new
Person
();
//Field[] getDeclaredFields()
:获取所有的成员变量,不考虑修饰符
Field
[]
declaredFields
=
personClass
.
getDeclaredFields
();
for
(
Field declaredField
:
declaredFields
) {
System
.
out
.
println
(
declaredField
);
}
//Field getDeclaredField(String name)
Field d
=
personClass
.
getDeclaredField
(
"d"
);
//
忽略访问权限修饰符的安全检查
d
.
setAccessible
(
true
);
//
暴⼒反射
,
注意私有的要加这个
Object
value2
=
d
.
get
(
p
);
System
.
out
.
println
(
value2
);
初始化空的构造
获取指定名称的⽅法并执⾏
//0.
获取
Person
的
Class
对象
Class personClass
=
Person
.
class
;
//Constructor<T> getConstructor(
类
<?>... parameterTypes)
//
获取参数是
String,int
的构造⽅法
Constructor constructor
=
personClass
.
getConstructor
(
String
.
class
,
int
.
class
);
System
.
out
.
println
(
constructor
);
//
创建对象
Object
person
=
constructor
.
newInstance
(
"
张三
"
,
23
);
System
.
out
.
println
(
person
);
//0.
获取
Person
的
Class
对象
Class personClass
=
Person
.
class
;
Constructor constructor1
=
personClass
.
getConstructor
();
System
.
out
.
println
(
constructor1
);
//
创建对象
Object
person1
=
constructor1
.
newInstance
();
System
.
out
.
println
(
person1
);
Object
o
=
personClass
.
newInstance
();
System
.
out
.
println
(
o
);
//constructor1.setAccessible(true);
//0.
获取
Person
的
Class
对象
Class personClass
=
Person
.
class
;
//
获取指定名称的⽅法
Method eat_method
=
personClass
.
getMethod
(
"eat"
);
Person p
=
new
Person
();
//
执⾏⽅法
eat_method
.
invoke
(
p
);
Method eat_method2
=
personClass
.
getMethod
(
"eat"
,
String
.
class
);
//
执⾏⽅法
eat_method2
.
invoke
(
p
,
"
饭
"
);
获取所有
public
修饰的⽅法
获取类名
//0.
获取
Person
的
Class
对象
Class personClass
=
Person
.
class
;
Method
[]
methods
=
personClass
.
getMethods
();
for
(
Method method
:
methods
) {
System
.
out
.
println
(
method
);
String
name
=
method
.
getName
();
System
.
out
.
println
(
name
);
//method.setAccessible(true);
}
String
className
=
personClass
.
getName
();
System
.
out
.
println
(
className
);
* Field
:成员变量
*
操作:
1.
设置值
* void set(Object obj, Object value)
2.
获取值
* get(Object obj)
3.
忽略访问权限修饰符的安全检查
* setAccessible(true):
暴⼒反射
* Constructor:
构造⽅法
*
创建对象:
* T newInstance(Object... initargs)
*
如果使⽤空参数构造⽅法创建对象,操作可以简化:
Class
对象的
newInstance
⽅法
* Method
:⽅法对象
*
执⾏⽅法:
* Object invoke(Object obj, Object... args)
*
获取⽅法名称:
* String getName:
获取⽅法名
*
案例:
*
需求:写⼀个
"
框架
"
,不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执⾏其中任意⽅法
*
实现:
1.
配置⽂件
2.
反射
*
步骤:
1.
将需要创建的对象的全类名和需要执⾏的⽅法定义在配置⽂件中
2.
在程序中加载读取配置⽂件
3.
使⽤反射技术来加载类⽂件进内存
4.
创建对象
5.
执⾏⽅法
//
可以创建任意类的对象,可以执⾏任意⽅法
/*
前提:不能改变该类的任何代码。可以创建任意类的对象,可以执⾏任意⽅法
*/
/* Person p = new Person();
p.eat();*/
/*
Student stu = new Student();
stu.sleep();*/
//
读取配置信息
BufferedReader bufferedReader
=
new
BufferedReader
(
new
InputStreamReader
(
new
FileInputStream
(
"test.config"
)));
String
content
=
bufferedReader
.
readLine
();
//Person:eat
//3.
加载该类进内存
Class cls
=
Class
.
forName
(
content
.
split
(
":"
)[
0
]);
//4.
创建对象
Object
obj
=
cls
.
newInstance
();
//5.
获取⽅法对象
Method method
=
cls
.
getMethod
(
content
.
split
(
":"
)[
1
]);
//6.
执⾏⽅法
method
.
invoke
(
obj
);