配色: 字号:
java反射深入剖析(推荐)
2016-10-11 | 阅:  转:  |  分享 
  
java反射深入剖析(推荐)

本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解。

下面开始正文。

【案例1】通过一个对象获得完整的包名和类名

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15 packageReflect;

/

通过一个对象获得完整的包名和类名

/

classDemo{

//othercodes...

}

classhello{

publicstaticvoidmain(String[]args){

Demodemo=newDemo();

System.out.println(demo.getClass().getName());

}

} 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 packageReflect;

classDemo{

//othercodes...

}

classhello{

publicstaticvoidmain(String[]args){

Classdemo1=null;

Classdemo2=null;

Classdemo3=null;

try{

//一般尽量采用这种形式

demo1=Class.forName("Reflect.Demo");

}catch(Exceptione){

e.printStackTrace();

}

demo2=newDemo().getClass();

demo3=Demo.class;

System.out.println("类名称"+demo1.getName());

System.out.println("类名称"+demo2.getName());

System.out.println("类名称"+demo3.getName());

}

} 【运行结果】:类名称Reflect.Demo类名称Reflect.Demo类名称Reflect.Demo

【案例3】通过Class实例化其他类的对象

通过无参构造实例化对象

1

2

3

4 publicPerson(Stringname,intage){

this.age=age;

this.name=name;

} 然后继续运行上面的程序,会出现:



所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数【案例】通过Class调用其他类中的构造函数(也可以通过这种方式通过Class创建其他类的对象)

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 packageReflect;

importjava.lang.reflect.Constructor;

classPerson{

publicPerson(){

}

publicPerson(Stringname){

this.name=name;

}

publicPerson(intage){

this.age=age;

}

publicPerson(Stringname,intage){

this.age=age;

this.name=name;

}

publicStringgetName(){

returnname;

}

publicintgetAge(){

returnage;

}

@Override

publicStringtoString(){

return"["+this.name+""+this.age+"]";

}

privateStringname;

privateintage;

}

classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

Personper1=null;

Personper2=null;

Personper3=null;

Personper4=null;

//取得全部的构造函数

Constructorcons[]=demo.getConstructors();

try{

per1=(Person)cons[0].newInstance();

per2=(Person)cons[1].newInstance("Rollen");

per3=(Person)cons[2].newInstance(20);

per4=(Person)cons[3].newInstance("Rollen",20);

}catch(Exceptione){

e.printStackTrace();

}

System.out.println(per1);

System.out.println(per2);

System.out.println(per3);

System.out.println(per4);

}

} 【运行结果】:

[null0][Rollen0][null20][Rollen20]

【案例】

返回一个类实现的接口:

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 packageReflect;

interfaceChina{

publicstaticfinalStringname="Rollen";

publicstaticintage=20;

publicvoidsayChina();

publicvoidsayHello(Stringname,intage);

}

classPersonimplementsChina{

publicPerson(){

}

publicPerson(Stringsex){

this.sex=sex;

}

publicStringgetSex(){

returnsex;

}

publicvoidsetSex(Stringsex){

this.sex=sex;

}

@Override

publicvoidsayChina(www.visa158.com){

System.out.println("hello,china");

}

@Override

publicvoidsayHello(Stringname,intage){

System.out.println(name+""+age);

}

privateStringsex;

}

classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

//保存所有的接口

Classintes[]=demo.getInterfaces();

for(inti=0;i
System.out.println("实现的接口"+intes[i].getName());

}

}

} 【运行结果】:

实现的接口Reflect.China

(注意,以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)

【案例】:取得其他类中的父类

1

2

3

4

5

6

7

8

9

10

11

12

13 classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

//取得父类

Classtemp=demo.getSuperclass();

System.out.println("继承的父类为:"+temp.getName());

}

} 1

2

3

4

5

6

7

8

9

10

11

12

13

14 classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

Constructorcons[]=demo.getConstructors();

for(inti=0;i
System.out.println("构造方法:"+cons[i]);

}

}

} 【运行结果】:

构造方法:publicReflect.Person()构造方法:publicReflect.Person(java.lang.String)

但是细心的读者会发现,上面的构造函数没有public或者private这一类的修饰符

下面这个例子我们就来获取修饰符

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 classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

Constructorcons[]=demo.getConstructors();

for(inti=0;i
Classp[]=cons[i].getParameterTypes();

System.out.print("构造方法:");

intmo=cons[i].getModifiers();

System.out.print(Modifier.toString(mo)+"");

System.out.print(cons[i].getName());

System.out.print("(");

for(intj=0;j
System.out.print(p[j].getName()+"arg"+i);

if(j
System.out.print(",");

}

}

System.out.println("){}");

}

}

} 【运行结果】:

构造方法:publicReflect.Person(){}构造方法:publicReflect.Person(java.lang.Stringarg1){}

有时候一个方法可能还有异常,呵呵。下面看看:

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 classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

Methodmethod[]=demo.getMethods();

for(inti=0;i
ClassreturnType=method[i].getReturnType();

Classpara[]=method[i].getParameterTypes();

inttemp=method[i].getModifiers();

System.out.print(Modifier.toString(temp)+"");

System.out.print(returnType.getName()+"");

System.out.print(method[i].getName()+"");

System.out.print("(");

for(intj=0;j
System.out.print(para[j].getName()+""+"arg"+j);

if(j
System.out.print(",");

}

}

Classexce[]=method[i].getExceptionTypes();

if(exce.length>0){

System.out.print(")throws");

for(intk=0;k
System.out.print(exce[k].getName()+"");

if(k
System.out.print(",");

}

}

}else{

System.out.print(")");

}

System.out.println();

}

}

} 【运行结果】:



【案例】接下来让我们取得其他类的全部属性吧,最后我讲这些整理在一起,也就是通过class取得一个类的全部框架

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 classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

System.out.println("===============本类属性========================");

//取得本类的全部属性

Field[]field=demo.getDeclaredFields();

for(inti=0;i
//权限修饰符

intmo=field[i].getModifiers();

Stringpriv=Modifier.toString(mo);

//属性类型

Classtype=field[i].getType();

System.out.println(priv+""+type.getName()+""

+field[i].getName()+";");

}

System.out.println("===============实现的接口或者父类的属性========================");

//取得实现的接口或者父类的属性

Field[]filed1=demo.getFields();

for(intj=0;j
//权限修饰符

intmo=filed1[j].getModifiers();

Stringpriv=Modifier.toString(mo);

//属性类型

Classtype=filed1[j].getType();

System.out.println(priv+""+type.getName()+""

+filed1[j].getName()+";");

}

}

} 【运行结果】:

===============本类属性========================privatejava.lang.Stringsex;===============实现的接口或者父类的属性========================publicstaticfinaljava.lang.Stringname;publicstaticfinalintage;

【案例】其实还可以通过反射调用其他类中的方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21 classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

try{

//调用Person类中的sayChina方法

Methodmethod=demo.getMethod("sayChina");

method.invoke(demo.newInstance());

//调用Person的sayHello方法

method=demo.getMethod("sayHello",String.class,int.class);

method.invoke(demo.newInstance(),"Rollen",20);

}catch(Exceptione){

e.printStackTrace();

}

}

} 【运行结果】:

hello,chinaRollen20

【案例】调用其他类的set和get方法

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 classhello{

publicstaticvoidmain(String[]args){

Classdemo=null;

Objectobj=null;

try{

demo=Class.forName("Reflect.Person");

}catch(Exceptione){

e.printStackTrace();

}

try{

obj=demo.newInstance();

}catch(Exceptione){

e.printStackTrace();

}

setter(obj,"Sex","男",String.class);

getter(obj,"Sex");

}

/

@paramobj

操作的对象

@paramatt

操作的属性

/

publicstaticvoidgetter(Objectobj,Stringatt){

try{

Methodmethod=obj.getClass().getMethod("get"+att);

System.out.println(method.invoke(obj));

}catch(Exceptione){

e.printStackTrace();

}

}

/

@paramobj

操作的对象

@paramatt

操作的属性

@paramvalue

设置的值

@paramtype

参数的属性

/

publicstaticvoidsetter(Objectobj,Stringatt,Objectvalue,

Classtype){

try{

Methodmethod=obj.getClass().getMethod("set"+att,type);

method.invoke(obj,value);

}catch(Exceptione){

e.printStackTrace();

}

}

}//endclass 【运行结果】:



【案例】通过反射操作属性

1

2

3

4

5

6

7

8

9

10

11

12

13

14 classhello{

publicstaticvoidmain(String[]args)throwsException{

Classdemo=null;

Objectobj=null;

demo=Class.forName("Reflect.Person");

obj=demo.newInstance(www.hunanwang.net);

Fieldfield=demo.getDeclaredField("sex");

field.setAccessible(true);

field.set(obj,"男");

System.out.println(field.get(obj));

}

}//endclass 1

2

3

4

5

6

7

8

9

10

11

12 importjava.lang.reflect.;

classhello{

publicstaticvoidmain(String[]args){

int[]temp={1,2,3,4,5};

Classdemo=temp.getClass().getComponentType();

System.out.println("数组类型:"+demo.getName());

System.out.println("数组长度"+Array.getLength(temp));

System.out.println("数组的第一个元素:"+Array.get(temp,0));

Array.set(temp,0,100);

System.out.println("修改之后数组第一个元素为:"+Array.get(temp,0));

}

} 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 classhello{

publicstaticvoidmain(String[]args){

int[]temp={1,2,3,4,5,6,7,8,9};

int[]newTemp=(int[])arrayInc(temp,15);

print(newTemp);

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

String[]atr={"a","b","c"};

String[]str1=(String[])arrayInc(atr,8);

print(str1);

}

/

修改数组大小

/

publicstaticObjectarrayInc(Objectobj,intlen){

Classarr=obj.getClass().getComponentType();

ObjectnewArr=Array.newInstance(arr,len);

intco=Array.getLength(obj);

System.arraycopy(obj,0,newArr,0,co);

returnnewArr;

}

/

打印

/

publicstaticvoidprint(Objectobj){

Classc=obj.getClass();

if(!c.isArray()){

return;

}

System.out.println("数组长度为:"+Array.getLength(obj));

for(inti=0;i
System.out.print(Array.get(obj,i)+"");

}

}

} 【运行结果】:

数组长度为:15123456789000000=====================数组长度为:8abcnullnullnullnullnull

动态代理

【案例】首先来看看如何获得类加载器:

1

2

3

4

5

6

7

8

9 classtest{

}

classhello{

publicstaticvoidmain(String[]args){

testt=newtest();

System.out.println("类加载器"+t.getClass().getClassLoader().getClass().getName());

}

} 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 packageReflect;

importjava.lang.reflect.;

//定义项目接口

interfaceSubject{

publicStringsay(Stringname,intage);

}

//定义真实项目

classRealSubjectimplementsSubject{

@Override

publicStringsay(Stringname,intage){

returnname+""+age;

}

}

classMyInvocationHandlerimplementsInvocationHandler{

privateObjectobj=null;

publicObjectbind(Objectobj){

this.obj=obj;

returnProxy.newProxyInstance(obj.getClass().getClassLoader(),obj

.getClass().getInterfaces(),this);

}

@Override

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)

throwsThrowable{

Objecttemp=method.invoke(this.obj,args);

returntemp;

}

}

classhello{

publicstaticvoidmain(String[]args){

MyInvocationHandlerdemo=newMyInvocationHandler();

Subjectsub=(Subject)demo.bind(newRealSubject());

Stringinfo=sub.say("Rollen",20);

System.out.println(info);

}

} 【运行结果】:Rollen20

类的生命周期

在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。

类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。但是同一个类只会被类装载器装载以前

链接就是把二进制数据组装为可以运行的状态。链接分为校验,准备,解析这3个阶段

校验一般用来确认此二进制文件是否适合当前的JVM(版本),

准备就是为静态成员分配内存空间,。并设置默认值

解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)

完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。

当没有任何引用指向Class对象时就会被卸载,结束类的生命周期

将反射用于工厂模式

先来看看,如果不用反射的时候,的工厂模式吧:

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 /

@authorRollen-Holt设计模式之工厂模式

/

interfacefruit{

publicabstractvoideat();

}

classAppleimplementsfruit{

publicvoideat(){

System.out.println("Apple");

}

}

classOrangeimplementsfruit{

publicvoideat(){

System.out.println("Orange");

}

}

//构造工厂类

//也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了

classFactory{

publicstaticfruitgetInstance(StringfruitName){

fruitf=null;

if("Apple".equals(fruitName)){

f=newApple();

}

if("Orange".equals(fruitName)){

f=newOrange();

}

returnf;

}

}

classhello{

publicstaticvoidmain(String[]a){

fruitf=Factory.getInstance("Orange");

f.eat();

}

} 这样,当我们在添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改的就会很多。

现在我们看看利用反射机制:

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 packageReflect;

interfacefruit{

publicabstractvoideat();

}

classAppleimplementsfruit{

publicvoideat(){

System.out.println("Apple");

}

}

classOrangeimplementsfruit{

publicvoideat(){

System.out.println("Orange");

}

}

classFactory{

publicstaticfruitgetInstance(StringClassName){

fruitf=null;

try{

f=(fruit)Class.forName(ClassName).newInstance();

}catch(Exceptione){

e.printStackTrace();

}

returnf;

}

}

classhello{

publicstaticvoidmain(String[]a){

fruitf=Factory.getInstance("Reflect.Apple");

if(f!=null){

f.eat();

}

}

} 现在就算我们添加任意多个子类的时候,工厂类就不需要修改。

上面的爱吗虽然可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。

下面我们来看看:结合属性文件的工厂模式

首先创建一个fruit.properties的资源文件,

内容为:

1

2 apple=Reflect.Apple

orange=Reflect.Orange 然后编写主类代码:

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 packageReflect;

importjava.io.;

importjava.util.;

interfacefruit{

publicabstractvoideat();

}

classAppleimplementsfruit{

publicvoideat(){

System.out.println("Apple");

}

}

classOrangeimplementsfruit{

publicvoideat(){

System.out.println("Orange");

}

}

//操作属性文件类

classinit{

publicstaticPropertiesgetPro()throwsFileNotFoundException,IOException{

Propertiespro=newProperties();

Filef=newFile("fruit.properties");

if(f.exists()){

pro.load(newFileInputStream(f));

}else{

pro.setProperty("apple","Reflect.Apple");

pro.setProperty("orange","Reflect.Orange");

pro.store(newFileOutputStream(f),"FRUITCLASS");

}

returnpro;

}

}

classFactory{

publicstaticfruitgetInstance(StringClassName){

fruitf=null;

try{

f=(fruit)Class.forName(ClassName).newInstance();

}catch(Exceptione){

e.printStackTrace();

}

returnf;

}

}

classhello{

publicstaticvoidmain(String[]a)throwsFileNotFoundException,IOException{

Propertiespro=init.getPro();

fruitf=Factory.getInstance(pro.getProperty("apple"));

if(f!=null){

f.eat();

}

}

} 【运行结果】:Apple























献花(0)
+1
(本文系白狐一梦首藏)