黑马程序员-------java提高之反射

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

1 反射的基石 Class

java是一门面向对象的语言,java如何对java类class进行描述呢?java为描述类对象(类的字节码对象.class 文件)提供了一个特殊的类Class类

用于描述一个类的属性(field),类名(name),方法(method),构造函数(constructor)等相关信息。一个类的字节码对象时唯一的。


如何获得一个类型为类 所属的类呢?即是如何去获得一个内的字节码对象呢?

有三种方式:

Person p1 = new Person();
Person p2 = new Person();

方式一:
person.getClass();//对象.getClass();

方式二:
Class.forName("java.lang.String");// 1 字节码存在已经加载进虚拟机了就直接获得
                                                             // 2 字节码未加载进虚拟机,则使用类加载器去加载该类的字节码                                                          
方式三:
类名.class 如:Person.class;

方式2最灵活; 很多框架就是基于第二种方式,通过动态的获取一个String参数来获取一个类的字节码对象。


多获得的字节码对象我们可以进行一些简单的操作。如判断是否是Array类型的类。是否是基本类型的类

如:

String  str = "abc";
Class cls1 = String.class;
Class cls2 = str.getClass();
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2);
System.out.println(cls1 == cls3);//都对应同一份字节码
        
System.out.println(cls1.isPrimitive());//判断是否是基本类型
System.out.println(int.class.isPrimitive());//判断是否是基本类型
System.out.println(int.class == Integer.class);//判断基本类型和器包装类对象的Class实例是否相同
System.out.println(int.class == Integer.TYPE);//包装类获取被包装类的Class对象实例
System.out.println(int[].class.isPrimitive());//只要是类型都有Class对象实例


2什么叫反射?

反射就是将一个类中的各个成员映射成对应的java类。


 1  对类构造函数的反射

 类的构造函数对应:Constructor类

 如何通过类的字节码反射出该类的构造函数对象呢?
   

例如:
   Constructor  String.class.getConstructor();//返回具体某一个具体的(Constructor)构造函数对象
   Constructor[] String.class.getConstructors();//返回所有的构造函数对象
    一个类可能包含多个构造函数,如何指定 获取具体哪一个构造函数呢?
   : 可通过构造函数的参数类型字节码进行区分不同构造函数。
   Constructor construct = String.class.getConstructor(StringBuffer.class);
    得到了一个类的构造方法对象可以做什么呢?
    可创建该类对象的实例:
   construct.newInstance(new StringBffer(abc));//等价于:如new String(new StringBuffer("abc"));

2 对成员变量的反射

  类的成员变量对应:Field类

  1 通过类字节码获取类变量名。
  2 通过变量名区别不同的变量
  3 getFiled(name)方法只能获得该类对外暴露的成员变量(public)
 4 对private修饰的成员变量getDeclaerdFiled(name)获取。
 5 对私有设定可达才能进行该变量的访问操作setAccessible(true);
 6 因为获取的是类变量 必须为该变量指定具体的类对象才能获得具体的值

 如:

   public class Pointer {
       public int x;
    private int y;
      public Pointer(int x, int y) {
        this.x = x;
        this.y = y;
    }
     }
 
Pointer p1 = new Pointer(4, 6);
Field  filed = p1.getClass().getField("x");//1 通过变量名获取具体的类变量    2获得是类的变量不是某个具体对象上的变量
System.out.println(filed.get(p1)); //3 通过为该类变量指明具体的对象 获得具体对象上该变量的值
Field  filed2 = p1.getClass().getDeclaredField("y");//对私有类成员变量的反射
filed2.setAccessible(true);// 暴力反射  让类中被Private修饰的成员可达,破坏封装性
System.out.println(filed2.get(p1))

-------------------------------------------------

5  成员方法的反射

    1 通过函数名,和参数类型来获取某个具体的方法
    如:
    String str = "abc";
    Method method = String.class.getMethod("charAt",int.class);//获取 String类的charAt(int index);方法  注意:参数类型是一个可变参数
    method.invoke(str,1);// b   2通过获得方法对象的invoke(对象,实参)方法,来调用获得方法  注意当方法为静态方法时:可将第一个参数设为NULL invoke(null,实参列表);

   需注意:对参数类型为数组的函数进行反射,得到Method对象,调用invoke();方法时;

可能会出现参数个数不匹配的异常。这是因为JDK1.5对JDK1.4的兼容引起的

对参数类型为数组类型的函数的反射
  Class  A
   { 
      public void arraySort(String[] arr)
    { 
        String sum =null;
        for(String a:arr)
          {
            sum += a;
           }
        System.out.print(sum);
     }
    }

   Class B
    {
      public static void main(String[]arg)
    {
        A a = new A();
	Method m = a.getClass().getMethod("arraySort",String[].class);
	m.invoke(a,new String[]{"abc","das","dasda"});//java虚拟机会拆包认为传递的是三个参数,解决办法:1 new Object[]{new String[]{"abc","das","dasda"}}
                                                                       
       2 (Object)new String[]{"abc","das","dasda"}
       原因:invoke(Object,Object...)// 当传来new String[]{"abc","das","dasda"}为兼容jdk1.4(没有可变参数,要传递多个参数是通过数组的形式)会认为传来的是三个参数
       

     }
   }
 
3   反射机制到底有啥用呢?

当我们在开发一些应用时:为提高程序的灵活性,可在配置文件中设置一些配置信息,然后程序通过反射机制  Class.forName();来调用具体的方法。如Spring配置文件

底层实现就是基于反射完成的。可以完成类的动态装配。执行对配置文件进行修改而不必修改源文件就能完成不一样的功能。

  也可以通过反射来获取一个类的字节码---->类加载器----->加载资源和配置文件

如:
reflactTest.class.getClassLoader().getResourceAsStrea("javalearn15\classProperties.properties");

----------------------------------------------------------------------------------------

4 javaBean

  1内省:IntroSpector ---->JavaBean------>特殊的Java类(方法的取名有一定的规则:get或set开头)

如:int getAge();
        void setAge(int age);
      j avaBean的属性是根据方法来的


Age--->如果第二字母是小写,则把第一个字母变成小写---age;


javaBean的内省操作

正是由于javaBean定义属性方法特殊的命名规则为javaBean 的反射操作提供了一些统一的操作流程,步奏。
针对这些统一的步奏,可抽象提取出一些工具(如BeanUtils)类来简化javaBean的反射操作
如:
Person p = new Person(121, "张三");
     //使用属性名通过反射来设置张三的年纪
     String property = "age";//javaBean的属性特点--->设置属性的方法名为  setAge(int age);
利用基本的反射原理做
     //age--->Age--->setAge(int age)得有个转换过程
      String methodname = "set"+property.replace('a', 'A');
      Method method = p.getClass().getMethod(methodname, int.class);
      method.invoke(p, 23);
利用一些工具类做
 PropertyDescriptor pds = new PropertyDescriptor(property, p.getClass());
 pds.getWriteMethod().invoke(p,21);
 System.out.println(p.getAge());
注释:建议采用UtilBeans工具类操作

--------------------------------------------------------------------------------------------------------------------------------------

ArrayLisr 和hashSet的比较以及hashcode分析

Arraylist 底层结构是数组,当插入新的元素时直接在数组后面进行存储操作,因此ArrayList中可以存相同的元素。在基本数组类型结构的容器中对象的hashcode没用

1 一个对象hashcode 只有在将对象存储进哈希表结构的容器(如hasbSet,hashmap)时才有用

hashcode 图解





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值