.反射简述
2.Class是什么?
3.通过反射获得Field,Constructor,Method
4.反射的应用
====================== 华丽丽的分割线 ======================
1.反射简述
类用于描述一类具有相同属性和方法的东西,那么,Java中的类又能否有相应的类去描述?
答案是肯定的,反射(reflect)就是用来把Java类中的各种成分映射成各种相应的Java类.
Java反射涉及的类分别为:Field、Constructor、Method、Class。
Field 类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor 类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和 Field 类不同,Field 类封装了反射类的属性,而 Constructor 类则封装了反射类的构造方法。
Method 类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法。这个类不难理解,它是用来封装反射类方法的一个类。
Class 类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
====================== 华丽丽的分割线 ======================
2.Class是什么?
Class:简单而言,就是用来描述Java类(与接口)的类.它的实例用来表示正在运行的Java应用程序中的类和接口。
如何获得字节码?
Class cls = Xxx.class;
Class cls = xx.getClass();
Class.forname(类名); // 返回字节码:若内存中有加载该类,则他找到该类的字节码并返回,若无,则找到该类的路径,加载后返回.
要区别一个概念,这里获得的是类的字节码,与具体的对象无关。
View Code
1
public
class
ClassTest {
2
3
public
static
void
main(String[] args){
4
String str1
=
"
abc
"
;
5
String str2
=
"
123
"
;
6
System.out.println(
"
str1.getClass() 等于 str2.getClass()?
"
+
(str1.getClass()
==
str2.getClass());
7
}
8
}
9
/*
Output:
10
* str1.getClass()等于str2.getClass()? true
11
*/
如前所说,他是用来描述正在运行的Java类。这里这里的getClass()获得的是String类型的字节码,故当然相等.
====================== 华丽丽的分割线 ======================
3.通过反射获得Field,Constructor,Method
通过反射获得类得各种成分
View Code
1
public
class
ReflectTest{
2
3
public
int
a
=
47
;
4
5
private
String str
=
"
hello
"
;
6
7
public
ReflectTest(){}
8
9
public
ReflectTest(String str){
10
this
.str
=
str;
11
}
12
13
public
String getStr(String str){
14
return
this
.str
+
"
,
"
+
str;
15
}
16
17
public
String getStr(){
18
return
str;
19
}
20
21
public
static
void
main(String[] args){
22
System.out.println(
"
This is GenericsTest
"
+
args[
1
]);
23
}
24
25
}
这里有一个类,用于待会通过反射来获得它的成分,这个类中有属性(公有与私有,基础类型与非基础类型),两个构造方法,两个方法(多态)。
3.1. 通过反射获得Field:
View Code
1
import
java.lang.reflect.Field;
2
3
public
class
ReflectField {
4
5
public
static
void
main(String[] args)
throws
Exception {
6
Class clazz
=
Class.forName(
"
ReflectTest
"
);
7
System.out.println(clazz.getName());
8
9
//
method two:
10
//
Class clazz1 = GenericsTest.class;
11
12
//
method three:
13
//
GenericsTest gt = new GenericsTest();
14
//
Class clazz2 = gt.getClass();
15
16
Field fieldA
=
clazz.getField(
"
a
"
);
17
//
Can not:Field fieldA = clazz.getField("str");
18
//
Because str's modifiers is private.
19
System.out.println(
"
属性名:
"
+
fieldA.getName()
+
"
; 类型:
"
20
+
fieldA.getType()
+
"
; 权限修饰符:
"
21
+
fieldA.getGenericType()
+
"
; 值:
"
+
fieldA.get(
new
ReflectTest()));
22
23
//
既然反射是将类的各种成分映射成相应的类,那么私有的属性理应也可获取(暴力反射):
24
ReflectTest rt
=
new
ReflectTest();
25
Field fieldStr
=
clazz.getDeclaredField(
"
str
"
);
26
fieldStr.setAccessible(
true
);
27
System.out.println(fieldStr.get(rt));
28
fieldStr.set(rt,
"
abc
"
);
29
System.out.println(fieldStr.get(rt));
30
}
31
32
}
在这个类中,演示了如何获得属性,要注意的是,私有属性的获得是需要通过暴力反射。
3.2. 通过反射获得构造方法:
View Code
1
import
java.lang.reflect.Constructor;
2
3
4
public
class
ReflectConstructor {
5
6
public
static
void
main(String[] args)
throws
Exception {
7
Class clazz
=
Class.forName(
"
ReflectTest
"
);
8
9
//
获取无参的构造方法
10
Constructor
<
ReflectTest
>
constructor
=
clazz.getConstructor();
11
ReflectTest rt
=
constructor.newInstance();
12
System.out.println(rt.getStr());
13
14
//
获取有参的构造方法,需指明参数类型
15
constructor
=
clazz.getConstructor(String.
class
);
16
rt
=
constructor.newInstance(
"
world
"
);
17
System.out.println(rt.getStr());
18
19
//
可以看出,先通过获取ReflectTest的字节码,然后得到它的构造方法,再调用该构造方法生成对象
20
//
对于无参的构造方法,Class类中提供一个方法可以直接生成该类的对象
21
rt
=
(ReflectTest)clazz.newInstance();
22
System.out.println(rt.getStr());
23
}
24
25
}
3.3. 通过反射获得方法:
View Code
1
import
java.lang.reflect.Method;
2
3
4
public
class
ReflectMethod {
5
6
public
static
void
main(String[] args)
throws
Exception{
7
ReflectTest rt
=
new
ReflectTest();
8
ReflectTest rt2
=
new
ReflectTest();
9
Method method
=
ReflectTest.
class
.getMethod(
"
getStr
"
,String.
class
);
10
String message
=
(String)method.invoke(rt,
"
world!
"
);
11
System.out.println(message);
12
}
13
}
要补充的是,对于无参的方法,不用写参数;而对于静态方法时,则为:method.invoke(null,参数名...);
因为静态方法是不需要对象的。。。
====================== 华丽丽的分割线 ======================
4.反射的应用
反射的应用:框架。就好比建筑一样,我们先建好框架,等待门窗安进来,而在建房时无需知道门与窗长得什么样。
下面通过一个常用的实例来模拟一个小框架,即通过获取properties文件中的类名,来创建对象(框架的基本原理)
#config.properties
className=ReflectTest
在properties中,由于我做这个实例的时候直接丢到默认包,所以路径就直接写,蛋若有包名,则需写全
View Code
1
import
java.io.InputStream;
2
import
java.util.Properties;
3
4
5
public
class
ReflectApp {
6
7
public
static
void
main(String[] args)
throws
Exception {
8
//
从当前类所对应的包中找到config.properties文件.若在前面加上 "/",则从项目的根目录开始.
9
InputStream inStream
=
ReflectApp.
class
.getResourceAsStream(
"
config.properties
"
);
10
11
//
method two:
12
//
该方法需从根目录开始,也就是得指明包,这里是默认包,所以直接写
13
//
InputStream inStream = ReflectApp.class.getClassLoader().getResourceAsStream("config.properties");
14
Properties props
=
new
Properties();
15
props.load(inStream);
16
inStream.close();
17
String className
=
props.getProperty(
"
className
"
);
18
System.out.println(
"
创建一个对象:
"
+
Class.forName(className).newInstance());
19
}
20
21
}
这就是反射的基本应用,其实在做‘有个饭桶’的时候就用到了,只是当时知其然而不知其所以然。。。现在学框架,懂了这个后回头看,便清晰容易多了。。。
<script type="text/javascript"></script>