A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 文盲庄稼汉 中级黑马   /  2014-8-27 19:52  /  1955 人查看  /  12 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

刚刚发表的有点乱,先重新发表一次........
一、反射的基石--Class类
1、Java程序中的各个java类属于同一事物,描述这些类事物的java类名就是Class。
2、对比提问:从多的人用一个什么类表示?从多的java类用一个什么类表示?
    人类---Person
    java类--Class
    注意这里Class是大写的,不是关键字class。
3、对比提问:
    1)Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,
    2)Class类代表java类,它的各个实现对象又分别对应什么呢?
对应各个类在内存中的字节码,例如Person类的字节码,ArrayList类的字节码,等待。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,
不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?
4、得到字节码对象的三种方法
    1)类名.class,例如System.class
    2)对象.getClass(),例如new Date().getClass()
    3)Class.forName("完整类名"),例如 Class.forName("java.util.Data");
反射时主要用第三种。它是静态方法。
面试题:Class.forName()的的作用是什么?
获取一个类的字节码对象,如果该类的字节码已经在内存中存在,就可以直接调用,
如果还没有存在,就调用类加载器进行加载,然后获取该类的字节码对象。
5、九个预定义的Class对象:
    参看 Class.isPrimitive方法的帮助文档
    八个基本类型和void,分别是:boolean、byte、char、short、int、long、float、double和void。
    int.class == Integer.TYPE
6、数组类型的Class实例对象用的方法是:
Class.isArray()
7、总之,只要是在源程序中出现的类型,都有各自的Class实例对象,
    例如int[],void。
实例:获取String类的字节码的三种方法
  1. class Demo17{
  2. public static void main(String[] args) throws Exception{
  3. String str1 = "abc";
  4. Class cls1 = str1.getClass();
  5. Class cls2 = String.class;
  6. Class cls3 = Class.forName("java.lang.String");

  7. System.out.println(cls1 == cls2);               //true
  8. System.out.println(cls1 == cls3);               //true
  9.         
  10. //是否是原始类型
  11. System.out.println(cls1.isPrimitive());         //false
  12. System.out.println(int.class.isPrimitive());    //true
  13. System.out.println(int.class == Integer.class); //false
  14. System.out.println(int.class == Integer.TYPE);  //true
  15. }   
  16. }
复制代码
反射的概念
反射就是把java类中的各种成分映射成相应的java类。
也可以理解成反射就是程序自己能够检测自身信息,就像人会通过镜子来查看自己的身体。
例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也是用一个个java类来表示。
就像骑车是一个类,骑车中的发动机,变速箱等等也是一个个类,表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,他们是Field、Method、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象胡有什么用?怎么使用?这这是学习和应用反射的要点
实例:
  1. class Demo18{
  2.     public static void sop(Object obj){System.out.println(obj);}
  3. public static void main(String[] args) throws Exception {
  4. String s1 = "1234";
  5. Class c1 = s1.getClass();
  6. Class c2 = String.class;
  7. Class c3 = Class.forName("java.lang.String");
  8. sop(c1==c2);                    //c1与c2是否是同一个对象true
  9. sop(c1==c3);                    //c1与c3是否是同一个对象true
  10. sop(String.class.isPrimitive());//String是否是基本类型false
  11. sop(int.class.isPrimitive());   //int是否是基本类型true
  12. sop(int.class==Integer.class);  //int与Integer的字节码是否是同一个对象false
  13. sop(int.class==Integer.TYPE);   //int与Integer.TYPE的字节码是否是同一个对象true
  14. sop(int[].class.isPrimitive()); //int[]是否是基本类型false
  15. sop(int[].class.isArray());     //int[]是否是数组类型true
  16. }
  17. }
复制代码
构造方法的反射
Constructor 类
1、Constructor类代表某个类中的一个构造方法。
2、得到某个类所有的构造方法:
例子:
Constructor constructor[] =
    Class.forName("java.lang.String").getConstructor(StringBuffer.class);
3、创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));
调用获得的方法时要用到上面相同类型的实例对象。
4、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[0];
ints.getClass();
需求:反射String类的 String(StringBuffer buffer) 这个构造方法
思路:
1、通过String类的字节码对象调用getConstructor方法获取这个类的构造方法。
2、具体要获得哪个构造方法,就给这个方法传递一个参数类型。这个参数类型是Class对象的一个数组。
3、用第一步返回的一个Constructor对象调用newInstance方法,创建StringBuffer的实例对象。
实例:反射构造方法
  1. import java.lang.reflect.Constructor;
  2. public class D19_ReflectConstructor {
  3. public static void main(String[] args) throws Exception {
  4.     Constructor c = String.class.getConstructor(StringBuffer.class);
  5.         String s = (String)c.newInstance(new StringBuffer("abc"));
  6.         System.out.println(s);
  7.     }
  8. }
复制代码
成员变量反射的综合实例
需求:反射某个类中所有的String类型的成员变量,并将该变量的值中指定的字符替换成新的字符。
分析:其实就是通过反射用用新字符串替换所有String类型的原来的字符串
思想:
1、定义StringDemo类,类里定义多种类型的成员变量,有的被public修饰。
2、另外定义一个类实现对StringDemo类的反射和其他操作,该类首先创建StringDemo的实例对象。
3、用getFields方法返回一个Field数组,用getFields方法是限制了只能反射被public修饰的成员字段。
4、变量该Field数组,取出每个字段,然后用该字段获取它的声明类型的Class对象与String.class比较。
5、如果是同一份字节码,就用set方法把该字段的值用新的值替换掉。
实例:通过反射把String类型的变量的值替换成新值
  1. import java.lang.reflect.Field;
  2. class StringDemo {
  3. public int x = 0;
  4. public String str1 = "wuguangxin";
  5. public String str2 = "howareyou";
  6. String str3 = "jiewin";
  7. }
  8. public class D21_ReflectFieldTest {
  9. public static void main(String[] args) throws Exception {
  10.     changeStringValue();
  11.     }
  12.     public static void changeStringValue() throws Exception{
  13. //创建对象
  14. StringDemo str = new StringDemo();
  15. //用getFields()方法返回一个所有声明的公共字段数组
  16. Field[] fields = str.getClass().getFields();
  17. //变量该数组,获取每一个字段进行
  18. System.out.println("把u替换成*");
  19. for (Field field : fields){
  20. //如果该字段的字节码和String的字节码相同,说明是同一份字节码。
  21. //字节码最适合用==比较,不建议用equals
  22. if(field.getType() == String.class){
  23. //获取原来的字段值
  24. String oldValue = (String)field.get(str);
  25. //把原来的值的指定字符替换成指定字符
  26. String newValue = oldValue.replace("u", "*");
  27. //设置该字段对应的变量的值为新的值
  28.         field.set(str, newValue);
  29. System.out.println(oldValue+" --> "+newValue);//测试
  30. }
  31. }
  32. }
  33. }
复制代码






12 个回复

倒序浏览
留个脚印,学到在回来看
回复 使用道具 举报
留名复习
回复 使用道具 举报
前几天刚看完反射,总结的不错 !!哈哈!
回复 使用道具 举报
看看 学习下...Thanks
回复 使用道具 举报
总结不错
回复 使用道具 举报
还没看  学习一下
回复 使用道具 举报
关注下,方便以后学习。
回复 使用道具 举报
alee 中级黑马 2014-8-28 22:07:11
9#
总结的真好,谢
回复 使用道具 举报
挺好的。
还没看到高新,不过毕老师的视频里已经讲过了呢,怎么高新里又讲一遍。。。
回复 使用道具 举报
这总结管理员都不给技术分 技术分何时才够?
回复 使用道具 举报
留名,方便以后学习
回复 使用道具 举报
pray 高级黑马 2014-8-29 10:36:08
13#
看看 学习下...Thanks
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马