黑马程序员——java反射

---------------------- android培训java培训、期待与您交流! ----------------------
反射就是把Java类中各种成分,映射成相应的java类。

关键字:Class 代表一类事物。点击打开链接 点击打开链接 点击打开链接 点击打开链接 点击打开链接

getName();getPackage();  getMethod()   getInterfaces() .....

 

语法:Class cls1 = 字节码;

三种方式得到字节码:

(1)类名.class  例如 System.class

(2)对象.getClass 例如 new Date().getClass

(3)Class.forName("类名") ;  例子 Class.forName(" java.util.Date");

九个预定义对象: 八个基本类型+ void

 

方法:isPrimitive()来判断是否是基本类型。

 

int.class ==Integer.TYPE   true

 

数组类型Class实例对象 isArray()判断是否是数组。

 

在源程序中出现的类型都有各自的Class实例对象,例如 int[ ] ...

 

Filed, Method,constructor  package

constructor 代表某个类中的一个构造方法

getConstructors 得到所有的构造方法

getConstructor 得到一个构造方法  

例子:

Constructor  constructors[  ]  = ClassforName("java.lang.String").getConstructors();

Constructor constructor = ClassforName("java.lang.String").getConstructor(StringBuffer.class);

 

 

 

简单的描述来区分new关键字和newInstance()方法的区别: 

newInstance: 弱类型。低效率。只能调用无参构造。     

new: 强类型。相对高效。能调用任何public构造。 

创建实例对象:

通常方式:

String str = new String (new StringBuffer("abc"));

反射方式:

String str = (String)constructor.newInstance(new StringBuffer("abc"));

(1) //先获得构造方法

 Constructor constructor1 =  String.class.getConstructor(StringBuffer.class);
  
  //注意类型的强转
 (2) String str2 =(String) constructor1.newInstance(new StringBuffer("abc"));

调用获得的方法时,要用到上面相同类型的实例对象。

 

Class.newInstance()方法

例子:

String  obj = (String) Class.forName("java.lang.String").newInstance();

该方法内部先得到默认的构造函数,然后用该构造方法创建实例对象。

package cn.itcast.day1;

 

publicclass ReflectPoint {

 

    privateintx;

    publicinty;

    public ReflectPoint(int x,int y) {

       super();

       this.x = x;

       this.y = y;

    }

   

}

 

 

Filed  代表某个类中的成员变量,

字节码.getField("str");

打印成员变量具体的值,getField("str").get("对象");

获取声明的变量

getDeclaredField

暴利反射

fieldx.setAccessible(true);

 

 //得到所有的成员变量

 Field[] fields =   obj.getClass().getFields();

 

字节码的比较用“==”

 

    ReflectPoint rp1 = new ReflectPoint(3,5);

       //获得成员变量对应的类

       Field fieldy = rp1.getClass().getField("y");

       //打印具体对象的值

       System.out.println(fieldy.get(rp1));

       //x是私有的方法变为getDeclaredField();

       Field fieldx = rp1.getClass().getDeclaredField("x");

       //暴力反射

       fieldx.setAccessible(true);

      

       System.out.println(fieldx.get(rp1));

      

           privatestaticvoid changeStringValue(Object obj)throws Exception{

       //得到所有的成员变量

       Field[] fields =   obj.getClass().getFields();

       //遍历找到

       for(Field field :fields){

          //如果类型是String类型

          if(field.getType()==String.class){

             //得到值,

             String oldValue = (String)field.get(obj);

             //进行替换

             String newValue = oldValue.replace('b','a');

             //设置新的值

             field.set(obj, newValue);

          }

       }  

    }

Method类:

Method类代表某个类的方法成员。

得到类中的某一个方法:

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

 

字节码.getMethod(name, parameterTypes)

  Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);

 

invoke();

public Object  invoke (Object obj,  Object . . . args)

obj 调用底层方法的对象,

args用于方法调用的参数。

返回使用参数args 在obj上使用该对象所表示方法的结果

 

 

调用方式:

通常方式:System.out.println(str.charAt(1));

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

如果传递给Method对象的invoke()方法一个参数为null,这说明该Method对象对应一个静态方法。

 mainMethod().invoke(null ,  new Object [ ] { new String [ ] { " "," ". . . } });

 mainMethod( ).invoke(null , (Object) new String [  ] { " "," ". . . });

 

用反射的方式执行某个类中的main方法。     

        String startingClassName = args[0];

        Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);

        //main接收一个字符串数组,一个参数。需要进行处理。两种方式:

        mainMethod.invoke(new TestArguments(),new Object[] {new String[  ]{"111","222","333"}});

        //强转成一个对象

       mainMethod.invoke(null, (Object)new String[  ] {"1","2","3"});

 

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

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

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

基本类型的以为数组可以被当做Object类型使用,不能当做Object [  ]使用

非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[  ]类型使用。

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

 

 

先将数组转成List对象

       String [   ] a4 = new String[ ]{"a","b","c"};  
      System.out.println(Arrays.asList(a4));

       printObject(a4); a  b  c 

       printObject("xyz");  xyz

构造方法printObject打印数组。 

    private static voidprintObject(Object obj) {

       Class cla1 = obj.getClass();

       if(cla1.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);

       }     

    }

hashCode()是用来产生哈希码的,而哈希码是用来在散列存储结构中确定对象的存储地址的,

hashCode()方法使用来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的

区域段里面,Map在搜索一个对象的时候先通过hashCode()找到相应的区域段,然手再根据

equals()方法找到相应的对象。

两个相等对象的equals方法一定为true,但两个hashcode相等的对象不一定是相等的对象。

所以hashcode相等只能保证两个对象在一个Hash表里的同一条hash链上,继而通过equals方法才能确定

是不是同一个对象,如果结果为true,则认为是同一对象不再插入,否则认为是不同对象

继续插入。

 

只有类的实例对象要被采用哈希算法进行存储和检索是,这个类才需要按要求覆盖hashCode

方法。即使程序可能暂时不会用到当前类的hashCode方法,但是为它提供一个hashCode

方法也不会有什么不好,只是未雨绸缪。所以,通常要求hashCode方法和equals方法一并被

同时覆盖。

提示

(1)通常来说,一个类的两个实例对象用equals( )方法比较的结果相等时,他们的哈希码也

必须相等,但反之则不成立,即equals方法比较不相等的对象可以有相同的哈希码,或者说哈希

码相同的两个对象的equals方法比较的结果可以不等,例如,“BB”和“AA”的equals

方法比较结果肯定不相等,但他们的hashCode方法返回值却相等。

(2)当一个对象被存储进HashSet集合以后,就不能修改这个对象中那些参与计算哈希值的字段了

,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下

即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回

找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。

 

反射的作用:实现框架功能。

房子                             门                                   锁

(框架)                   (客户)                       (工具类)

工具类被用户的类调用,

框架则是调用用户提供的类。

 

例子:

(1)设置一个 . properties文件

(2)读取配置文件中类的名字

(3)利用上一步结果,创建新的实例,这样整个程序中不会有new()

 

//读取配置文件
  //InputStream is = new FileInputStream("config.properties");

 

类加载器,加载资源


  //InputStream is  = ReflectTest2.class.getClassLoader().getResourceAsStream("cn\\itcast\\day1\\config.properties");
  //InputStream is  = ReflectTest2.class.getResourceAsStream("Resourse\\config.properties");
  InputStream is  = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/Resourse/config.properties");
       //问:" \ "  和 " / " 在路径表示的时候有什么区别
  
  //创建Properties对象
  Properties prop = new Properties();
  //加载配置文件
  prop.load(is);
  is.close();
  //指定字符串classname为类名
  String classname = prop.getProperty("classname");
  //创建实例对象。无参构造方法,创建实例对象。
  Collection collections =(Collection) Class.forName(classname).newInstance();

在MyEclipse中如果源文件目录中有非. java文件 那么会自动复制到classpath下

 

未来学习的框架:配置文件都是放在classpath路径下

 

 

 

config.properties

name                                     value

classname                            java.util.HashSet         

 

 ---------------------- android培训java培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net/heima

发布了23 篇原创文章 · 获赞 4 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章