反射

来源:互联网 发布:红旗linux官网 编辑:程序博客网 时间:2024/06/05 20:44

一:什么是反射。

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

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类的常用方法
    1getName() 
     一个Class对象描述了一个特定类的属性,Class类中最常用的方法getName以  String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void 名称。

    2newInstance()
     Class还有一个有用的方法可以为类创建一个实例,这个方法叫做newInstance() 例如:
     x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调 用默认构造器(无参数构造器)初始化新建对象。

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

Class的一些使用技巧
    1forNamenewInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例 如
     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 classesTYPE 语法,这个有局限性只能用于 九个预定义的对象:八个基本数据对象 +  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;

第二步:使用javaapi,常用的操作类有。

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

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

[java] view plaincopy
  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.创建数组打印的类,所以要获取字节码,数组长度。

[java] view plaincopy
  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.就是对数组就会拆包,对不是数组就打印。

[java] view plaincopy
  1. printObject(a4);  
  2. printObject("xcv");  
  3. printObject(a1);  

打印结果:

a

b

c

xcv

1

2

3

 

六:反射实现框架功能:

框架(Framework:

是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用

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

框架与工具的区别:

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

框架解决的核心问题:

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

2.框架不能new实例对象,而是要用反射类获取。

框架举例:

[java] view plaincopy
  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.    
  15. String className = props.getProperty("className");  
  16. Collection collections = (Collection)Class.forName(className).newInstance();  
  17. ReflectPoint pt1= new ReflectPoint(3,3);   
  18. ReflectPoint pt2= new ReflectPoint(5,5);   
  19. ReflectPoint pt3= new ReflectPoint(3,3);  
  20. collections.add(pt1);  
  21. collections.add(pt2);  
  22. collections.add(pt3);  
  23. collections.add(pt1);  
  24. System.out.println(collections.size());  
  25. }  
  26. }  

在反射中配置文件的设置方法://配置文件名叫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");




0 0
原创粉丝点击