黑马程序员——反射

来源:互联网 发布:linux删除swap文件 编辑:程序博客网 时间:2024/05/24 07:15


-------android培训java培训、期待与您交流! -----------



反射的基石--->Class类
    java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class
    对比提问:众多的人用一个什么类表示?众多的java类用一个什么类表示?
        人--->Person
        java类--->Class
    对比提问:Person类代表人,它的实例对象就是张三、李四这样一个个具体的人,
    Class类代表Java类,它的各个实例对象又分别对应什么呢?
        对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的
        字节码等等
        一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容
        就是类的字节码,不同类得字节码是不同的,所以他们在内存中的内容是不同
        的,这一各个的空间可分别用一个个的对象来表示,这些对象显然具有相同的
        类型,这个类型是什么呢?


    如何得到各个字节码对应的实例对象(Class类型)
        类名.class  例如:System.class;
        对象.getClass()  例如:new Date().getClass();
        Class.forName("类名")  例如:Class.forName("java.util.Data");
    九个预定义Class实例对象
  参看Class.isPrimitive方法的帮助
  int.class == Integer.TYPE
 数组类型的Class实例对象
  Class.isArray()
 总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如:int[],void.

Java类用于描述一类事物的共性,给类事物有什么属性,没有什么属性,至于这个
属性的值是什么,则是由这个类得实例对象来确定的,不同的实例对象有不同的属性
值,Java程序中的各个Java类,它们是否属于同一类事物,是不是可以用一个类来
描述这类事物呢?这个类的名字就是Class,要注意与小写class关键字的区别,Class
类描述了哪些方面的信息呢?类的名字,类的访问属性,类所属于的包名,字段名称
的列表、方法名称的列表,等等,学习反射,首先就要明白Class这个类

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

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

Constructor类
 Constructor类代表某个类中的一个构造方法
 得到某个类所有的构造方法:
  例 Constructor[] constructors=Class.forName("java.lang.String").getConstructors();
 得到某一个构造方法:
  例 Constructor[] constructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);
  //获得方法时要用到类型
 创建实例对象:
  通常方式: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();
 该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
 该方法内部的具体代码是怎样写的呢?用到了缓冲机制来保存默认构造方法的实例对象
Field类
 Field类代表某个类中的一个成员变量
 演示用eclipse自动生成Java类的构造方法
 问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,
 而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?所以字段fieldX代表的是
 X的定义,而不是具体的x变量。

String str1 = "abc";
  Class cls1 = str1.getClass();
  Class cls2 = String.class;
  Class cls3 = Class.forName("java.lang.String");
  System.out.println(cls1==cls2);//true
  System.out.println(cls1==cls3);//true
  //说明cls1 cls2 cl3 指向同一个字节码

System.out.println(cls1.isPrimitive());//false 判断是否是基本数据类型
  System.out,println(int.class.isPrimitive())//true 是基本数据类型

  System.out.println(int.class==Integer.class)//false
  //int是基本数据类型,Integer是基本数据类型包装类,它包装了int,
  //他们俩的字节码不是一个,而每个包装类型都包含它所包装的类型的字节码
  
  System.out.println(int.class==Integer.TYPE);//true
  //Integer里定义的常量TYPE,就是获取所包装的基本数据类型的字节码的
  
  System.out.println(int[].class.isPrimitive());//false 数组类型不是基本数据类型
  System.out.println(int[].class.isArray());//true  isArray()判断此字节码是不是数组

//new String(new StringBuffer("abc"));
  Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
  String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));
  System.out.println(str2.charAt(2));//打印角标为2的字符

/*
 获取字节码文件的三种方式:
 1,Object类中的getClass方法。
    想要用这种方式,必须要明确具体的类,并创建对象。麻烦
 */
 public static void getClassObject_1()
 {
  Person p = new Person();
  Class clazz = p.getClass();

  Person p1 = new Person();
  Class clazz1 = p1.getClass();

  System.out.println(clazz==clazz1);
 }
 /*
 2,如何数据类型都具备一个静态的属性.class来获取其对应的Class对象
    相对简单,但是还是要明确用到类中的静态成员,还是不够扩展
 */
 public static void getClassObject_2()
 {
  Class clazz = Person.class;
  Class clazz1 = Person.class;
  System.out.println(clazz==clazz1);
 }
 /*
 3,只要通过给定的类的字符串名称就可以获取该类,更为扩展
    可以用Class类中的方法完成,该方法就是forName
    这种方式只要有名称即可,开发时以这种方式为主
 */
 public static void getClassObject_3()throws ClassNotFoundException
 {
  String className = "Person";//此处类名一定要明确所在包,完整的字符串是“包名.类名”
  Class clazz = Class.forName(className);//抛出类灭有找到异常
  System.out.println("className="+clazz);
 }
//1,通过空参数构造函数创建对象
 public static void createNewObject()throws Exception
 {
  //早期:new对象的时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,
  //并创建该类的字节码文件对象,并接着创建该字节码文件的对应的Person对象
  Person p = new Person();

  //现在:
  //给定一个类的字符串名称
  String name  = "Person";
  //找寻该名称的类文件,并加载进内存,产生Class对象
  Class clazz = Class.forName(name);
  //如何产生该字节码文件的类的对象呢?
  Object obj = clazz.newInstance();
 }
 //2,通过有参数的构造函数创建对象
 public static void createNewObject_2() throws Exception
 {
  /*
  当获取指定名称对应类中的所体现的对象时
  而该对象初始化不使用空参数构造该怎么办呢
  既然是通过指定的构造函数进行对象的初始化
  所以应该先获取到该构造函数,通过字节码文件对象即可完成
  该方法是:getConstructor(paramterTypes);
  */
  //早期:
  //Person p = new Person("小强",39);
  //现在
  String name = "Person";
  //找寻该名称类文件,并加载进内存,产生Class对象
  Class clazz = Class.forName(name);
  //获取到指定的构造函数对象
  Constructor constructor = clazz.getConstructor(String.class, int.class);
  //通过该构造器对象的newInstance方法进行对象的初始化
  Object obj = constructor.newInstance("小明",38);
 }
//获取字节码文件中的字段
 public static void getFieldDemo()throws Exception
 {
  Class clazz = Class.forName("Person");
  //clazz.getField("字段名");//只能获取本类的共有字段
  Field field = clazz.getDeclaredField("age");//获取本类字段,包括私有
  
  //因为age是私有的,想要获取其值就要下面那样
  //对私有字段的访问取消权限检查,称为暴力访问
  field.setAccessible(true);
  
  //拿到了字段之后,要用对象来操作字段
  Object obj = clazz.newInstance();
  //通过类的对象(obj)设置字段值
  field.set(obj,89);
  //通过类的对象(obj)获取字段值,返回Object
  Object o = field.get(obj);
  System.out.println(o);
 }
//获取指定Class中的所有公共函数
 public static void getMethodDemo()throws Exception
 {
  Class clazz = Class.forName("Person");
  //clazz.getMethods();//获取共有的所有方法
  Method[] methods = clazz.getDeclaredMethods();//只获取本类中的所有方法
  for(Method method : methods)
  {
   System.out.println(method);
  }
 }
 //调用无参数的一般方法
 public static void getMethodDemo_2()throws Exception
 {
  Class clazz = Class.forName("Person");
  //指定方法名和参数列表,show方法参数为空
  Method method = clazz.getMethod("show",null);
  //方法运行需要对象
  //Object obj = clazz.newInstance();
  Constructor constructor = clazz.getConstructor(String.class,int.class);
  Object obj = constructor.newInstance("小明",37);
  //运行方法时指定所属对象,与参数列表
  method.invoke(obj,null);
 }
 //调用有参数的一般方法
 public static void getMethodDemo_3()throws Exception
 {
  Class clazz = Class.forName("Person");
  Method method = clazz.getMethod("paramMethod",String.class,int.class);
  Object obj = clazz.newInstance();
  method.invoke(obj,"小强",89);
 }


-------android培训java培训、期待与您交流! ---------


0 0
原创粉丝点击