黑马程序员-Java反射机制

来源:互联网 发布:游泳池的水干净吗 知乎 编辑:程序博客网 时间:2024/06/08 06:50
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

反射的概念

反射就是把java类中的各种成分映射成相应的java类。

一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。

 反射的基础:Class-->用来描述java中的类
 
     如何得到各个字节码对应的实例对象
         ->类名.class 或者 类名.TYPE
         ->对象.getClass()
         ->Class.forName("类名")
     总之,只要在源程序中出现的类型,都有各自的Class实例对象

String str1 = "abc";//三种获取字节码的方法Class cls1 = str1.getClass();Class cls2 = String.class;Class cls3 = Class.forName("java.lang.String");System.out.println(cls1 == cls2);System.out.println(cls2 == cls3);
运行结果:true  true

注意:

1. int.class = integer.TYPE

2. 数组类型的class实例对象Class.isArray()为true

3. 反射不是java5的新特性

反射的作用

反射机制最重要的内容——检查类的结构。

在java.lang.reflect包中有三个类Field、Method、Constructor分别用于描述类的域、方法和构造器。

这三个类共有方法:

getModifiers   //返回一个整形数值,用不同的位开关描述public和static这样的修饰符使用状况

getName  //用来返回项目的名称                 


构造方法的反射应用

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.newInstance(new StringBuffer("abc"));

|--Class.newInstance()方法:String obj = (String)Class.forName("java.lang.String").newInstance(); //该方法内部先得到默认构造方法,然后该构造方法创建实例对象。


成员变量的反射

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

示例:通过Field调用成员变量

ReflectPiont.java

package com.itheima.reflect;public class ReflectPoint {       private int x;       public int y ;              public ReflectPoint(int x, int y) {             super();             this.x = x;             this.y = y;      }}
ReflectTest.java

package com.itheima.reflect;import java.lang.reflect.Constructor;import java.lang.reflect.Field;public class ReflectTest {       public static void main(String[] args) throws Exception {            ReflectPoint rp = new ReflectPoint(3, 5);            Field fieldY = rp.getClass().getField( "y");            System. out.println(fieldY.get(rp));            //结果:5      }}

注意:如果想直接通过getField方法获取私有对象,会出现如下错误:

Exception in thread "main" java.lang.NoSuchFieldException : x

解决方法:

Field fieldX = rp.getClass().getDeclaredField("x");            fieldX.setAccessible(true);

这种方法称之为暴力反射,使用setAccessible(true)使private类型的成员变量也可以被获取。


成员方法的反射

Method类用于描述类中的成员方法。

得到类中的某一个方法:

Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);

调用方法:

|--通常方法:System.out.println(str.charAt(1));

|--反射方法:System.out.println(charAt.invoke(str, 1));


注意:如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是静态方法!


数组与Object的关系及其反射类型

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

package com.itheima.reflect;import java.util.Arrays;public class ReflectTest {       public static void main(String[] args) throws Exception {            int [] a1 = new int[3];            int [] a2 = new int[4];            int [][] a3 = new int[2][3];            String[] a4 = new String[3];            System.out.println(a1.getClass() == a2.getClass());            //结果:true            System.out.println(a1.getClass() == a4.getClass());            //结果:false            System.out.println(a1.getClass() == a3.getClass());            //结果:false       }}

2. 代表数组的class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。

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

4. Array.asList()方法处理int[]和String[]时的差异

public class ReflectTest {       public static void main(String[] args) throws Exception {            int [] a5 = new int[]{1,2,3};            String[] a6 = new String[]{"a" ,"b" ,"c" };            //直接使用System.out.println无法打印出数组的内容            System. out .println(a5);            //结果:[I@18a992f            System. out .println(a6);            //结果:[Ljava.lang.String;@4f1d0d                       //通过Arrays.asList方法打印出数组的内容            System. out .println(Arrays.asList(a5));            //结果:[[I@18a992f]            //原因是因为JDK1.4中为Arrays.asList(Object[] a),JDK1.5中为Arrays.asList(T... a)。            //a5是int[]类型,JDK1.4中的asList方法处理不了,JDK1.5可以处理。但是JDK1.5将 int数组整体作为一个参数进行处理。            //因此最终结果就是将 int[]进行了封装,结果类型也就成了[[I。            System. out .println(Arrays.asList(a6));            //结果:[a, b, c]       }}

5. Array工具类用于完成数组的反射操作。

public class ReflectTest {       public static void main(String[] args) throws Exception {            String[] a1 = new String[]{"a" ,"b" ,"c" };            String a2 = "xyz";                       printObject(a1);            printObject(a2);       }             public static void printObject(Object obj){         Class clazz = obj.getClass();         if(clazz.isArray()){               int len = Array.getLength(obj);               for(int i = 0; i < len; i++){                     System. out.println(Array.get(obj, i));               }         } else{               System. out.println(obj);         }       }}

6. ArrayList和HashSet的比较及Hashcode分析。

ArrayList:

           Collection collections = new ArrayList();           ReflectPoint pt1 = new ReflectPoint(3, 3);           ReflectPoint pt2 = new ReflectPoint(5, 5);           ReflectPoint pt3 = new ReflectPoint(3, 3);                     collections.add(pt1);           collections.add(pt2);           collections.add(pt3);           collections.add(pt1);                     System. out.println(collections.size());           //结果:4           Collection collections = new ArrayList();           ReflectPoint pt1 = new ReflectPoint(3, 3);           ReflectPoint pt2 = new ReflectPoint(5, 5);           ReflectPoint pt3 = new ReflectPoint(3, 3);                     collections.add(pt1);           collections.add(pt2);           collections.add(pt3);           collections.add(pt1);                     System. out.println(collections.size());           //结果:4
HashSet:

           Collection collections = new HashSet();           ReflectPoint pt1 = new ReflectPoint(3, 3);           ReflectPoint pt2 = new ReflectPoint(5, 5);           ReflectPoint pt3 = new ReflectPoint(3, 3);                     collections.add(pt1);           collections.add(pt2);           collections.add(pt3);           collections.add(pt1);                     System. out.println(collections.size());           //结果:3
分析:

由以上两示例可以看到当集合为ArrayList时,其实质是一个数组,因此放入4个元素后,集合size为4。
当集合为HashSet时,需要通过比较hashcode值以及equals方法是否返回true决定是否放入。如果hashcode值相等并且equals方法返回true,那么就不会放入。因此,集合size为3。
如果想让size为2,也就是pt1与pt3作为同一个元素存入HashSet集合,那就需要覆盖ReflectPoint类的hashCode方法以及equals方法。

hashCode()和equals()覆盖:

       @Override       public int hashCode() {             final int prime = 31;             int result = 1;            result = prime * result + x;            result = prime * result + y;             return result;      }       @Override       public boolean equals(Object obj) {             if (this == obj)                   return true ;             if (obj == null)                   return false ;             if (getClass() != obj.getClass())                   return false ;            ReflectPoint other = (ReflectPoint) obj;             if (x != other.x)                   return false ;             if (y != other.y)                   return false ;             return true ;      }

此时,运行ReflectTest.java结果为2。

注意:

当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。


框架的概念及用反射技术开发框架的原理

1. 框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。

2. 框架程序怎样调用以后写的类呢?很多时候程序无法知道被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用反射方式来做。

ReflectTest.java

public class ReflectTest {       public static void main(String[] args) throws Exception {                 InputStream is = new FileInputStream("config.properties" );         Properties props = new Properties();         props.load(is);         is.close();                 String className = (String)props.get( "className");         Collection collections = (Collection)Class.forName(className).newInstance();                 ReflectPoint pt1 = new ReflectPoint(3, 3);         ReflectPoint pt2 = new ReflectPoint(5, 5);         ReflectPoint pt3 = new ReflectPoint(3, 3);                   collections.add(pt1);         collections.add(pt2);         collections.add(pt3);         collections.add(pt1);                   System. out.println(collections.size());       }}

config.properties文件直接放在根目录下:

|--config.properties

className = java.util.ArrayList    //结果:4

|--config.properties

className = java.util.HashSet    //结果:3


用类加载器的方式管理资源和配置文件

         //方式一:采用类加载器进行加载,使用相对路径的方式         //InputStream is = ReflectTest.class.getClassLoader().getResourceAsStream("com/itheima/day1/config.properties");                 //方式二:利用Class方式进行加载,使用相对路径的方式         //InputStream is = ReflectTest.class.getResourceAsStream("config.properties");                 //方式三:利用Class方式进行加载,使用绝对路径的方式         InputStream is = ReflectTest.class .getResourceAsStream("/com/itheima/day1/config.properties");



------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果6splus开不了机怎么办 顺丰快递寄件填错收件人地址怎么办 收快递电话换了怎么办 顺丰快递没人收怎么办 网购东西没收到怎么办 中通快递没收到怎么办 快递员不给验货怎么办 顺丰验货不要了怎么办 闲鱼买家掉包了怎么办 闲鱼正在退款中怎么办 拒收货物卖家拒绝退款怎么办 货物没问题淘宝卖家拒收怎么办 头发稀少长的慢怎么办 没满16岁怎么办银行卡 网上买东西手机号填错了怎么办 买东西电话号码填错了怎么办 淘宝联盟扣54分怎么办 联盟被扣54分怎么办 ofo押金退了余额怎么办 网购还没收货就已签收怎么办 理财公司倒闭分公司法人怎么办 公司让离职不想走怎么办 公司让离职自己不想走怎么办 小孩子有购物狂病怎么办 拉杆箱的轮子卡怎么办 想你了怎么办的英文 那现在怎么办 英文怎写 平安证券账号忘了怎么办 发现发票是假的怎么办 公司收到假发票入账了怎么办 手表皮带有汗味怎么办 利客来购物卡丢了怎么办 乐天玛特倒闭卡怎么办 lv皮带买长了怎么办 密袋鼠咬了人怎么办 lv皮带如果长了怎么办 天赐农场公众号进不去了怎么办 苹果删了订阅号怎么办 蚂蚁借呗没有自动扣款怎么办 有对方qq号名字怎么办 腾讯模拟器刺激现场注册上限怎么办