黑马程序员:反射

---------------------- <a href="http://edu.csdn.net/heima" target="blank">android培训</a>、<a href="http://edu.csdn.net/heima" target="blank">java培训</a>、期待与您交流! ----------------------

反射的基石->Class类
 java程序中的个人java类属于同一类事物,描述这类事物的Java类名就是Class。
  java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于着属性的值是什么,
  则是由这个类的实例对象来确定,不同的实例对象有不同的属性值,java程序中的各个java类,
  它们是否属于同一类事物,是不是可以用一个类来描述这类事物呢?这个类的名字就是Class,
  要注意与小写class的区别,Class类描述了那些方面的信息呢?类的名字,类的访问属性,
  类所属于的包名,字段名称的列表,方法名称的别表,等等,学习反射,首先要明白Class这个类。
  只要是在源程序中出现的类型,都有各自的Class实例对象,例如:int[] void[] ;

  
 Class.forName() forName作用就是返回字节码,返回的方式有两种,第一种这个字节码曾经被加载过,
     已经存在于虚拟机里了,直接返回, 第二种:虚拟虚拟机里还没有这份字节码,
     则用类加载去加载,吧加载进来的字节码保存在虚拟机里,以后要得到这份字节码就
     不用再加载了。

     而得到字节码的方式有三种:
      第一:在源程序里直接写上类的名字点class。 类名.class  例如:prosen.class
      第二:对象.getClass(),  例如: new Deta().getClass();
      第三:Class.forNmae("类名"), 例如; Class.forNmae("java.util.Data");


反射:
 反射就是把Java类中的各种成分映射成相应的Java类,例如:一个java类中用一个Class类的
 对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包,等等信息也用一个个的
 java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类,表示java类的Class
 类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包括信息,
 这些信息就是用相应类的实例对象来表示,他们是Field,Method,Contructor,Package等等。

 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类中的方法可以得到
 这些实例对象后,得到这些实例化对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。


Constructor类:(反射构造函数)
 Constructor类代表某个类中的一个构造方法。
 得到某个类所有的构造方法:
  例子:Constructor[] constructor =
     Class.forName("java.lang.String").getConstructor();

 得到某一个构造方法:
  例子: Constructor constructor =
     Class.forName("java.lang.String").getContructor();
    获得方法时,要用到类型。

 创建实例对象:
  通常方式: String str = new String(new StringBuffer("abc"));
  反射方式: String str = (String)constructor.newlnstance(new StringBuffer("abc"));
  调用获得方法时要用到上面相同类型的实例对象。


 Class.newInstance()方法:
  举例:String obj = (String)Class.forName("java.lang.String").newInstance();
  该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
  该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。


一个类有多个构造方法,用什么方式可以分清楚想得到其中的那个方法不呢?根据参数的个数和类型。
例如:Class.getMethod(name,Class...args); 中的args参数就代表所要获取的那个方法的各个参数
的类型的列表。
重点:参数类型用什么方式表示?用Class实例对象。
例如:int.class,(int []).class
   int [] ints = new int[];
   ints.getClass();


Constructor对象代表一个构造方法,那么Constructor对象上会有什么方法呢?
得到名字,得到所属类型,产生实例对象。


Field类:(反射成员变量)
  Field类代表某个类中的一个成员变量。
  演示用eclipse自动生成Java类的构造方法。
  
  问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?
  类只有一个,而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?
  所以字段fieldx代表的x的定义,而不是具体的x变量。

 实例代码:
  ReflectPoint point  = new ReflectPoint(1,7);
  Filed y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
  Syste.out.println(y.get(point));
 
  //Fieldx = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");//变量为私有时不可用。
  Fieldx = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");// 私有时时候。
  私有时可以取出 x 的字节码, 但是不可以访问该变量, 就要使用到暴力反射了setAccessible(true)暴力反射。

Method类:(反射成员方法)
 Method类代表某个类中的一个成员方法。
 获得类中的某一个方法:
  例子:Method charAt = Class.forNmae("java.lang.String").getMethod("charAt",int.class);

 调用方法:
  通常方式:System.out.println(str.charAt(1));
  反射方式:System.out.println(charAt.invoke(str,1));
   如果传递给Method对象invoke()方法的第一个参数为null,这有着什么样的意义?
   说明该Method对象对应的是静态方法!

 jdk1.4和jdk1.5方法的区别:
  JDK1.5:public Object invoke(Object obj,Object...args);
  JDK1.4: public Object invoke(Object obj,Obejce[] args),既按JDK1.4的语法,
  需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用
  方法中的一个参数,所以,调用charAt方法的代码也可以用JDK1.4改写为charAT.invoke(str1,Object[]{1});


大家应该通过思考和推理的方式来学习反射中的API,例如:Class.getMethod方法用于得到一个方法,该方法
要接受什么参数呢?显然要一个方法名,而一个同名的方法有多个重载形式,用什么方式可以区分清楚想得到
重载方法系列中的那个方法呢?根据参数的个数和类型。
例如: Class.getMethod(name,Class...args)中的args参数就代表所要获取的那个方法的各个参数的类型列表。
参数类型用Class对象来表示。

 

用发射方式执行某个类中的main方法;
 
 目标:
  写一个程序,这个程序根据用户提供的类名,去执行该类中的main方法。
 问题:
  启动java程序main方法的参数是一个字符串数组,即 public static void main(Sting[] args),
  通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按JDK1.5的语法,整个数组
  是一个参数,按JDK1.4的语法,数组中的每个元素对应一个参数,当吧一个字符串数组作为参数传递给
  invoke方法时,javac会到底按照那种语法进行处理呢?JDK1.5肯定要兼容1.4的语法,会按1.4的语法
  进行处理,即把数组打散成为若干个单独的参数,所以,在给main方法传递参数时,不能使用代码。
  
  mainMethod.invoke(null,new String[]{"xxx"}),javac只把它当作jdk1.4的语法进行理解,而不把它
  当作JDK1.5的语法解释,因此会出现参数类型不对的问题。

 解决办法:
  mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
  mainMethod.invoke(null,(Object)new String[]{"xxx"});,编译器会做特殊处理,编译时不把参数当作数组看
  ,也就不会数组打散成若干个参数了。


 我给你的数组,你不会当作参数,而是把其中的内容当作参数。
 Class clazz = Class.forName(arg[0]);
 Method mMain = clazz.getMethod("main",String[].class);
 mMain.invoke(null,new Object[]{new String[]{"aaa","bbb"}});
 mMain.invoke(null,(Object)new String[]{"aaa","bbb"});
  

数组的反射:
 具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。

 代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。

 基本数据类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;
 非基本数据类型的一维数组,既可以当作Object使用,有可以当作Object[]使用。

 Arrays.asList()方法处理int[]和String[]时的差异。
   asList 可以读取String数组中的每一个元素, 而不能读取int数组中的元素。
  
 Array工具类用于完成对数组的反射操作。
 

反射的作用->实现框架功能;
 框架与框架要解决的核心问题
  我做房子卖给用户住,有用户自己安装门和空调,我做的房子就是框架,用户需要使用我的框架,
  把门窗插入进我提供的框架中,框架与工具类有区别,工具类被用户的类调用,而框架则是调用
  用户提供的类。

 框架要解决的核心问题:
  我在写框架时,你这个用户可能还在上小学,还不会写程序,
  我写的框架程序怎么样能调用到你以后写的类呢?
  因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象,
  只能用Class.forName("xxx.xxx.xx.")要用反射方式来做。

  
  在编写配置文件时一定要记住用完成的路径,但完整的路径不是硬编码,而是运算出来的。
  如:InputStream ips = new FileInputStream("config.properties");不可以硬编(即使用绝对路径)


内省->了解JavaBean
 JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,
 而且方法名符合某种命名规则。

 如果要在两个模块之间传递多个信息,可以讲这些信息封装到一个JavaBean中,这种JavaBean的实例对象
 通常称之为值对象,(Value Object,简称VO),这些信息在类中用私有字段来存储,如果读取或设置这些
 字段的值,则需要通过一些相应的方法来访问,那么这些方法名称叫什么呢?JavaBean的属性是根据其中的
 setter和getter来确定的,而不是根据其中的成员变量,如果方法名为setId,中文意思即为设置id,至于你
 把它存到那个变量上,不用管,去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,
 则把其余部分的首字母改成小写。
 setId-->id;
 serCPU-->CPU;
 总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。


 一个符合javaBean特点的类,可以当作普通类一样进行使用,但把它当作javaBean来用肯定能带来一些额外好处,
 我们才会去了解和应用javaBean! 好处如下:
   在java EE开发中,经常要使用到javaBean很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,
   那你就没什么挑选的余地了。
   JDK中提供了对javaBean进行操作的一些API,这套API就称之为内省。如果要你自己去通过getX的方法去访问X,
   这么做有一定难度,用内省API操作javaBean比用普通类的方式更方便。

 

---------------------- <a href="http://edu.csdn.net/heima" target="blank">android培训</a>、<a href="http://edu.csdn.net/heima" target="blank">java培训</a>、期待与您交流! ----------------------


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值