Java基础加强-反射机制

时间:2023-02-14 20:51:34

反射的基石 -> Class 类(字节码)

/*只要是在源程序中出现的类型,都要各自的Class实例对象,例如:int,int[],void*/

如何得到各个字节码对应的实例对象(Class类型)

1.类名.class  

2.对象.getClass

3.Class.forName("类名");(1.先忘内存中找,是否有这个字节码  有的话,就是用,没有的话 就使用类装载器的方式,得到字节码)

/*这三种方式得到的字节码  都是同一份  是一样的*/

九个预定义Class实例对象(八种基本数据类型 + void )

1.Class.isPrimitive 判断是否为预定义的实例对象

2.int.class == Integer.TYPE  (Integer.TYPE 得到该被包装类型的字节码)

3.int.class != Integer.class  (这是两种不同的类型,字节码也不同)



反射

/*反射就是把Java类中的各种成分(成员变量,方法,构造方法,包等)映射成相应的java类。*/

1.得到某个类的构造方法  Constructor

Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class)

Class.newInstance()方法  调用默认无参构造方法创建对象(用到了缓存机制来保存默认构造方法的实例对象)



2.成员变量的反射  Field

Field name = Class.forName("xxx.xxx.Person").getField("name");  //name不是某个对象(person)上的变量,而是某个类(Person)上的,要用它去取某个对象上对应的值

field.get(person);//需指定是哪个对象的成员变量


3.成员方法的反射  Method

  String str1 = "abc"

  Mehod methodCharAt = String.class.getMethod("charAt",int.class);   //得到某个类的成员方法

  System.out.println(methodCharAt.invoke(str1,1));   /*结果:b*/     //调用哪个对象的该方法,传递什么参数

  如果invoke第一个参数传递为 null ,说明调用该类的一个静态方法

  
  /*

   * 人在黑板上画圆,涉及三个对象,画圆需要圆心和半径,但是是私有的,画圆的方法

   * 分配给人不合适。
   * 
   * 司机踩刹车,司机只是给列车发出指令,刹车的动作还需要列车去完成。
   * 

   * 面试经常考面向对象的设计,比如人关门,人只是去推门。

   * 

   * 这就是专家模式:谁拥有数据(private),谁就是专家,方法就分配给谁

   */
   

4.用反射方法执行某个类中的main方法

  main方法所需的参数是一个字符串数组,当反射调用这个main方法时,invoke传递参数时不能直接给一个字符串数组参数,因为编译的时候会将该字符串数组拆开,变成多个参数,

    而main方法只要一个参数,故报错   解决办法:将传递的字符串数组封装成一个Object对象 或者 一个Object[] 对象

    

5.数组的反射

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

1.所有的数组

int[][]a1 = new int[3][3];

Object[] o1 = a1;     /*正确的,int[]  属于Object*/

2.八大基本数据类型不继承于Object

int[] a2 = new int[3];

Object[] o2 = a2;   /*错误的,int不属于Object*/


注:Arrays.asList()方法,在jdk 1.4 中,由于 /*没有可变参数*/,接收的参数时Object[] ,在jdk 5.0 中 接收的参数是一个可变参数

故,当System.out.println(Arrays.asList(String[])); 会打印出String数组中的元素的值  因为这里是 /*jdk1.4 去编译*/,

当System.out.println(Arrays.asList(int[]));  因为 /*int不属于Object*/,所以 /*jdk1.4 无法编译 而是5.0 去编译(只会解析一个参数)*/,此时无法打印出元素,而是打印对象
 

6.ArrayList(有序可重复)和HashSet(无序不可重复)

存数据到ArrayList中时,一个对象一个空间,即使如果这两个数据相互equals,同样是按顺序放到ArrayList中  

而HashSet,是一整块混乱的空间,如果存数据时,两个数据equals,后面的那个数据不会存进去


Set集合想要保证元素不重复,可两个元素是否重复应该依据什么来判断呢?( /*先调用新元素HashCode方法,得到物理位置,如果该位置没有元素,那新元素就放到这里,如果有,再equals*/)

这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。

初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。  

当集合要添加新的元素时, /*先调用这个元素的hashCode方法*/,就一下子能定位到它应该放置的物理位置上。

如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址 


注:java中的内存泄漏,比如某些东西用不到了,想从内存中移除它,释放内存,

当一个对象被存储进HashSet集合中以后,就不能修改这个对象中那些参与计算哈希值的字段了,否则, /*对象修改后的哈希值与最初存储进HashSet集合中时的哈希值

就不同了*/,导致无法从HashSet集合中单独删除当前对象,从而造成 /*内存泄漏*/


7.反射的作用->实现框架功能

框架要解决的核心问题,我在框架时,你这个用户可能还在上小学 还不会写程序,我写的框架程序怎样才能调用到你以后写的类呢,(不知道会写出什么类)

因为在写程序时,无法知道直接知道要被调用的类名,所以,在程序中,无法直接new某个类的实例对象,而要用到反射来做 (也需要读取配置文件)