黑马程序员--反射的理解

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、          反射的意义

1、  动态获取类中信息,就是java反射。可以理解为对类的解剖。

2、  JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。

3、  注意:Class是一个类,而不是关键字class,因为这个类是一个对java中所有类进行描述的一个类,也就是说java把java中的类看作了同一个事物,就使用了Class这个类名定义了一个专门用于描述java类的特殊类。

二、          反射的作用

1、  如果想要对指定名称的字节码文件进行加载并获取其中的内容并调用,这时就使用到了反射技术。

2、  所谓的框架就是对外提供一些接口,也就是功能扩展的标准,由实现类按照这个接口标准去实现。框架内部如果需要操纵这些实现类的对象完成某些操作,那么只需要把这些实现类的全名(包名+类名)写在某个配置文件中,框架代码只需要读取这个配置文件,就可以获取这个实现类的字节码文件,然后利用反射技术创建这个实现类的对象并且调用相应的方法完成一些操作。

3、  获取Class对象的三种方法

方式一:

       通过对象的getClass方法进行获取。

       如:Class clazz=newPerson().getClass();//Person是一个类名

       麻烦之处:每次都需要具体的类和该类的对象,以及调用getClass方法。

方式二:

       任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应Class对象。

       如:Classclazz=Person.class;//Person是一个类名

       比第一种较为简单,不用创建对象,不用调用getClass方法,但是还是要使用具体的类,和该类中的一个静态属性class完成。

方式三:

       这种方式较为简单,只要知道类的名称即可。不需要使用该类,也不需要去调用具体的属性和行为。就可以获取到Class对象了。

       如:Classclazz=Class.forName("包名.Person");//Person是一个类名

       这种方式仅知道类名就可以获取到该类字节码对象的方式,更有利于扩展。

示例:

import cn.itcast.bean.Person;
 
//要想要对字节码文件进行解剖,必须要有字节码文件对象。
public class ReflectDemo
{
       public static void main(String[] args) throwsClassNotFoundException {
               getClassObject_1();
              System.out.println("--------------------");
               getClassObject_2();
              System.out.println("--------------------");
               getClassObject_3();
       }
 
   /*
       * 获取字节码对象的方式:
       * 方式一: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);
       }
 
       /*
       * 方式二:任何数据类型都具备一个静态的属性.class来获取其对应的Class对象。
       * 相对简单,但是还是要明确用到类中的静态成员。
       * 还是不够扩展。
       */
       public static void getClassObject_2(){
               
               Class clazz = Person.class;
               Class clazz1 = Person.class;
 
               System.out.println(clazz == clazz1);
       }
 
       /*
       * 方式三:只要通过给定的类的字符串名称就可以获取该类,更为扩展。
       * 可以用Class类中的方法完成。
       * 该方法就是forName。
        *这种方法只要有名称即可,更为方便,扩展性更强。
       */
       public static void getClassObject_3() throwsClassNotFoundException {
               
               //可以把类的字符串名称写到配置文件中,然后读取出来。
               String className ="cn.itcast.bean.Person";
               Class clazz = Class.forName(className);
 
               System.out.println(clazz);
       }
}


三、           反射涉及的四个类

1、Class类

!、所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。

!!、什么叫字节码?

当源程序中用到类时,首先要从硬盘把这个类的那些二进制代码,一个类编译成class放在硬盘上以后,就是一些二进制代码,要把这些二进制代码加载到内存中里面来,再用这些字节码去复制出一个一个对象来。

!!!、Class和class的区别

        1)class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。

        2)Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。Class是Java程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。

2、Constructor类

!、概述

       如果指定的类中没有空参数的构造函数,或者要创建的类对象需要通过指定的构造函数进行初始化。这时怎么办呢?这时就不能使用Class类中的newInstance方法了。既然要通过指定的构造函数进行对象的初始化。就必须先获取这个构造函数——Constructor。Constructor代表某个类的构造方法。

!!、获取构造方法:

       1)得到这个类的所有构造方法:如得到上面示例中Person类的所有构造方法

             Constructor[] cons = Class.forName(“cn.itheima.Person”).getConstructors();

       2)获取某一个构造方法:

             Constructor con=Person.class.getConstructor(String.class,int.class);

!!!、创建实例对象:

        1)通常方式:Personp = new Person(“lisi”,30);

        2)反射方式:Personp= (Person)con.newInstance(“lisi”,30);

3、Field类

!、Field类代表某个类中一个成员变量

!!、方法

       FieldgetField(String s);//只能获取公有和父类中公有

       Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有

       setAccessible(ture);

       //如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。

       set(Object obj, Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值。

        Objectget(Object obj);//返回指定对象上Field表示的字段的值。

4、Method类

!、概述:Method类代表某个类中的一个成员方法。调用某个对象身上的方法,要先得到方法,再针对某个对象调用。

!!、方法

             Method[] getMethods();//只获取公共和父类中的方法。

             Method[] getDeclaredMethods();//获取本类中包含私有。

                     Method   getMethod("方法名",参数.class(如果是空参可以写null));

                     Object invoke(Object obj ,参数);//调用方法

            如果方法是静态,invoke方法中的对象参数可以为null。

四、          数组的反射

1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。数组字节码的名字:有[和数组对应类型的缩写,如int[]数组的名称为:[I

2、Object[]与String[]没有父子关系,Object与String有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转换成new String[]{“aaa”,”bb”}; Object x =“abc”能强制转换成String x =“abc”。

3、如何得到某个数组中的某个元素的类型,

       例:

              int a = new int[3];Object[] obj=new Object[]{”ABC”,1};

        无法得到某个数组的具体类型,只能得到其中某个元素的类型,

       如:

               Obj[0].getClass().getName()得到的是java.lang.String。

4、Array工具类用于完成对数组的反射操作。

       Array.getLength(Object obj);//获取数组的长度

       Array.get(Object obj,int x);//获取数组中的元素

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

示例:

package cn.itheima.Demo;  
  
import java.lang.reflect.Array;  
import java.util.Arrays;  
  
public class ArrayReflect {  
    public static void main(String[] args) {  
        int [] a1 = new int[]{1,2,3};  
        int [] a2 = new int[4];  
        int[][] a3 = new int[2][3];  
        String [] a4 = new String[]{"a","b","c"};  
        System.out.println(a1.getClass().equals(a2.getClass()));//true  
    System.out.println(a1.getClass().equals(a3.getClass()));//false  
    System.out.println(a1.getClass().equals(a4.getClass()));//false  
    System.out.println(a1.getClass().getName());//[I  
    System.out.println(a4.getClass().getName());//[Ljava.lang.String;  
    System.out.println(a1.getClass().getSuperclass());//class java.lang.Object  
    System.out.println(a4.getClass().getSuperclass());//class java.lang.Object  
          
        Object obj1=a1;  
        Object obj2=a3;  
        Object obj3=a4;  
          
//      Object[] obj11=a1;//这样是不行的,因为a1中的元素是int类型,基本数据类型不是Object  
        Object[] obj13=a3;  
        Object[] obj14=a4;//这样可以,因为String数组中的元素属于Object  
          
        System.out.println(a1);//[I@4caaf64e  
        System.out.println(a4);//[Ljava.lang.String;@6c10a234  
        System.out.println(Arrays.asList(a1));//[I@4caaf64e  
        System.out.println(Arrays.asList(a4));//[a, b, c]  
          
        /* Arrays.asList()方法处理int[]和String[]时的差异。 
         * 打印Arrays.asList(a1);还是跟直接打印a1是一样的 
            打印Arrays.asList(a4);就会把a3的元素打印出来。 
            这是因为此方法在JDK1.4版本中,接收的Object类型的数组, 
            而a3可以作为Object数组传入。但是a1不可以作为Object数组传入,所以只能按照JDK1.5版本来处理。 
            在JDK1.5版本中,传入的是一个可变参数,所以a1就被当作是一个object,也就是一个参数, 
            而不是数组传入,所以打印的结果还是跟直接打印a1一样。 
         */  
          
        //Array工具类用于完成对数组的反射操作。如打印任意数值  
        printObject(a1);  
        printObject(a4);  
        printObject("abc");  
          
    }  
    //打印任意数值  
    private static void printObject(Object obj) {  
        Class clazz=obj.getClass();  
        //如果传入的是数组,则遍历  
        if(clazz.isArray()){  
            int len =Array.getLength(obj);//Array工具类获取数组长度方法  
            for(int x=0;x<len;x++){  
                System.out.println(Array.get(obj, x));//Array工具获取数组元素  
            }  
        }  
        else  
            System.out.println(obj);  
    }  
}  


 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值