反射

  • Post author:
  • Post category:其他



一:什么是反射。

反射的概念:主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。

java

中的反射:



Java


程序开发语言的特征之一,它允许运行中的


Java


程序对自身进行检查,或者说





自审





,并能直接操作程序的内部属性和方法


总结:

简而言之

Java


的反射能在程序运行的时候,获取正在运行类中的属性和方法。并且还能

访问、检测和修改他们的能力。

二:反射的基础

Class


类。

Java

程序中的各个


java


类属于同一类事物,描述这类事物的


java


类名就是


Class

.

如何得到

Class


的对象呢?有三种方法可以的获取:
1



调用

Object


类的


getClass()


方法来得到


Class


对象,这也是最常见的产生


Class


对象的方法



例如:
MyObject x;
Class c1 = x.getClass();

2




使用

Class


类的中静态


forName()


方法获得与字符串对应的


Class


对象。


例如:


Class c2=Class.forName(“MyObject”),Employee

必须是接口或者类的名字。

3




获取

Class


类型对象的第三个方法非常简单。如果


T


是一个


Java


类型,那么


T.class




代表了匹配的类对象。

例如
Class cl1 = Manager.class;
Class cl2 = int.class;
Class cl3 = Double[].class;

注意:


Class


对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的


int.class


是一个


Class


类型的对象。由于历史原因,数组类型的


getName


方法会返回奇怪的名字。

Class

类的常用方法
1




getName()
一个

Class


对象描述了一个特定类的属性,


Class


类中最常用的方法


getName




String

的形式返回此


Class


对象所表示的实体(类、接口、数组类、基本类型或


void




名称。

2




newInstance()
Class

还有一个有用的方法可以为类创建一个实例,这个方法叫做


newInstance()




例如:
x.getClass.newInstance()

,创建了一个同


x


一样类型的新实例。


newInstance()


方法调

用默认构造器(无参数构造器)初始化新建对象。

3




getClassLoader()
返回该类的类加载器。

Class

的一些使用技巧
1




forName





newInstance


结合起来使用,可以根据存储在字符串中的类名创建对象。例

Object obj = Class.forName(s).newInstance();

2

、虚拟机为每种类型管理一个独一无二的


Class


对象。因此可以使用


==


操作符来比较类

对象。例如:
if(e.getClass() == Employee.class)…

三:什么是字节码


字节码是一种中间码,它比机械码更抽象。它经常被看作是包含一个执行程序的



二进制文件



,更像一个对象模型。在java中,



字节码






CPU


构架(JVM)


的具有可移植性的机械语言。

四:写

java


反射类一般的两步骤:


第一步:

获取类的字节码;获取方法有四种:

第一种:运用

getClass()

注:每个

class


都有此函数

第二种:运用

Class.getSuperclass()

通过子类求出父类的字节码

第三种:运用

Class.forName()


(最常被使用)

。通过用

Class


类中的方法

第四种:运用

primitive wrapper classes





TYPE


语法

,这个有局限性只能用于 九个预定义的对象:八个基本数据对象

+  void

举例:

String str1 = “abc”;

第一种:

Class cls1 = str1.getClass();


或者


Class cls2 = String.class;

第二种:Class c2 = cls1.getSuperclass();

第三种:

Class cls3 = Class.forName(“java.lang.String”);

第四种:Class c1 = Boolean.TYPE;


第二步:

使用

java





api


,常用的操作类有。

Field

类:简单的理解可以把它看成一个封装反射类的属性的类。


//构造一个含构造方法的变量



  1. public




    class


    ReflectPoint {



  2. private




    int


    x;



  3. public




    int


    y;



  4. public


    ReflectPoint(


    int


    x,


    int


    y) {



  5. super


    ();



  6. this


    .x = x;



  7. this


    .y = y;


  8. }

  9. }




得到某个类中的某个

public


成员变量:

例:

Field  filedY = pt1. getClass.getField(

“y”);

打印某个类中的某个

public


成员变量:

System.out.println(fieldY.get(pt1));

得到某个类中的某个

private


成员变量:

Field  filedX = pt1. getClass.getDeclaredfield(“x”);

打印某个类中的某个

private


成员变量:

fieldX.setAccessible(true);

System.out.println(fieldx.get(pt1));

Constructor

类:


Constructor


类则封装了反射类的构造方法。

得到某个类所有的构造方法:

例:

Constructor[] constructor = Class.forName(

“java lang String”).getCoustructor();

得到某一个的构造方法:

例:

Constructor constructor =

Class.forName(“java lang String”).getCoustructor(StringBuffer.class);

创建实例对象。

通常方式:

String str = new String(new StringBuffer(“abc”));

反射方式:

String str = (String)constructor.newInstance(new StringBuffer(“abc”));

Method

类:它是用来封装反射类方法的一个类。

//方法与对象时没有关系的。参数(方法的名字,参数类型)

String Str1 = “abc”;

获取某个对象的方法。


Method methodCharAt = String.


class


.getMethod(

“charAt”

,


int


.


class


);

调用某个对象方法中的方法。

//invoke意思是调用,方法对象中的方法。(对象名,传入的参数)

System.out.println(methodCharAt.invoke(Str1, 1));

//如果invoke(null, 1)第一个参数为null,则这个方法是静态方法。

五:数组与

Object


之间注意事项。

1.数组是基础类型(

int,byte,

short,long, char, double,float ,boolean )

的数组就不能存入


Object


数组内;

例:

int[] a1 = new int[]{1,2,3};

Object[] obj = a1;//

是错误的。

原因:

Object[]


内部要装的是


Object


类型的元素,而


int[] a1


内装的是


int


类型的数组


(


基本类型


)


,所以错误。

2.数组不是基本类型时,数组存入

Object


数组时要拆包。

例:

int[] a1 = new int[]{1,2,3};

String[] a4 = new String[]{“a”,”b”,”c”};

sop(Arrays.asList(a1));//

打印的是


[[I@3d4b7453]


sop(Arrays.asList(a4));//


打印的是


[a, b, c]


原因:

jdk1.4


中的


asList


接收的是


Object


的数组,因为是


int


类型,所以和


Object[]


数组对不上, 所以跳到


jdk1.5


版本中


T… a


可变参数的


Object,


但这


Object


当做是一个参数

五:数组的反射

1.

创建数组打印的类,所以要获取字节码,数组长度。



  1. public




    static




    void


    printObject(Object obj){


  2. Class<?

    extends


    Object> clazz = obj.getClass();



  3. if


    (clazz.isArray()){



    //假如是数组





  4. int


    len =Array.getLength(obj);



  5. for


    (


    int


    i =


    0


    ; i < len; i++){


  6. System.out.println(Array.get(obj, i));

  7. }

  8. }

    else


    {


  9. System.out.println(obj);

  10. }

  11. }

2.

就是对数组就会拆包,对不是数组就打印。



  1. printObject(a4);


  2. printObject(

    “xcv”


    );


  3. printObject(a1);

打印结果:

a

b

c

xcv

1

2

3

六:反射实现框架功能:

框架(

Framework





:

是整个或部分系统的可重用设计,表现为一组抽象

构件

及构件实例间交互的方法

;


另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用

方面而后者是从目的方面给出的定义。

框架与工具的区别:

工具被用户的类调用,而框架则是调用用户提供的类。

框架解决的核心问题:

1.框架要顾及以后写的类。

2.框架不能

new


实例对象,而是要用反射类获取。

框架举例:



  1. package


    fanshe2;



  2. //用反射做框架





  3. import


    java.io.FileInputStream;



  4. import


    java.io.InputStream;



  5. import


    java.util.Collection;



  6. import


    java.util.Properties;



  7. public




    class


    ReflectTest3 {



  8. public




    static




    void


    main(String[] args)


    throws


    Exception{



  9. // TODO Auto-generated method stub




  10. InputStream ips = ReflectTest3.

    class


    .getClassLoader().getResourceAsStream(


    “config2.properties”


    );


  11. Properties props =

    new


    Properties();


  12. props.load(ips);

  13. ips.close();

    //要马上关闭资源,因为这样系统资源会泄露。





  14. String className = props.getProperty(

    “className”


    );


  15. Collection collections = (Collection)Class.forName(className).newInstance();

  16. ReflectPoint pt1=

    new


    ReflectPoint(


    3


    ,


    3


    );


  17. ReflectPoint pt2=

    new


    ReflectPoint(


    5


    ,


    5


    );


  18. ReflectPoint pt3=

    new


    ReflectPoint(


    3


    ,


    3


    );


  19. collections.add(pt1);

  20. collections.add(pt2);

  21. collections.add(pt3);

  22. collections.add(pt1);

  23. System.out.println(collections.size());

  24. }

  25. }

在反射中配置文件的设置方法:

//


配置文件名叫


config.properties

//

配置文件方式一:


——————————————————————————————-

//config2.properties

为相对路径,相对于当前工作目录

//InputStream ips = new FileInputStream(“config2.properties”);

//

绝对路径例:


(“d:\\config2.properties”);

//

真正实际用途是配置出来的。就是用完整的路径,但完整的不是硬编码,而是运算出来的。


getReal.path();

//

配置文件方式二:用类加载器


—————————————————————————-

//InputStream ips = ReflectTest3.class.getClassLoader().getResourceAsStream(“config2.properties”);

//

如果


(“config2.properties”)


这样写,则去


classPath


的根目录下逐个找


“config2.properties”


该文件。

//

如果


(“fanshe2/config2.properties”)

//

类加载器方法的缺点只能读取文件,不能写文件。方式一还能写文件用


OutputStream.

//

配置文件方式三:用类方法:


——————————————————————————-

InputStream ips = ReflectTest3.class.getResourceAsStream(“config2.properties”);

//

如果配置文件不再自己的包内,则直接写成:

//InputStream ips = ReflectTest3.class.getResourceAsStream(“fanshe22/config2.properties”);

//

如果所在的包名加入了


/


,则要完整的包名因为他是绝对路径了。

//InputStream ips = ReflectTest3.class.getResourceAsStream(”

完整的包路径


/


所在的包名


/config2.properties”);



版权声明:本文为yuan_dailin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。