反射

来源:互联网 发布:淘宝水印字体怎么设置 编辑:程序博客网 时间:2024/06/06 02:12

反射:其实说白了,也就是得到类本身,并解剖出类的各个组成部分,比如:这个类中的构造方法,成员变量,成员方法等。就相当于数学中的反函数一样,比如y=2x+1,现在反过来让你求x的表达式一样。<-------这是我自己的理解

 

 

 

 

Class类

 

1、Class类用于描述一类事物的共性,,该类食物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的。Class类的实例表示正在运行的Java应用程序中的类和接口。枚举是一种类,注释是一种接口,每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都应该共享该Class对象

2、字节码:用到一个类时,首先从硬盘上加载这个类,把这个类的二进制码编译成一个class放到硬盘上,把这些二进制码加载到内存中来,然后就可以用这些二进码来创建对象。

3、这个类的字节码已经加载到内存中来了,现在如果想得到字节码就不用加载了,直接找到返回;如果虚拟机中还没有字节码,就用类加载器去加载,加载进来以后就把字节码缓存起来,返回刚才加载进来的字节码,作用是返回字节码,返回的方式有两种,一种就是这种字节码曾经被加载过,已经呆在java虚拟机里面了,直接返回,还有一种就是java虚拟机里还没有这个字节码,用类加载器去加载,把加载进来的字节码缓存在虚拟机里,以后要得到这些字节码就不用加载了。

4、得到字节码的三种方式:

假如有一个类为Person并且 Person p=new Person();

a)     Class cls1=Person.class;

b)     Class cls2=p.getClass();

c)     Class cls3=Class.forName(“java.util.Person”);

5、Class对象:基本的Java类型(boolean, byte, char, short, int, long,float, double)和关键字void

6、Class没有公共构造方法,Class对象是在加载类时有java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。

 

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

      反射中的Constructor的类

             Constructor提供关于类的单个构造方法的信息以及对他的访问权限,代表某个类中的一个构造方法,允许在将实参与带有底层构造方法的形参的newInstance()匹配时进行转换,但是如果发生收缩转换,则抛异常。

      得到某个类的所有构造方法:

             Constructor[]constructor=Class.forName(“java.lang.String”).getConstructors();

      得到某一个构造方法,或得方法时要用到类型

             Constructorconstructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

      

      创建实例对象:调用或得的的方法时要用到上面相同类型的实例对象

      通常方式:String str=new String(new StringBuffer(“abc”));

      反射方式:String str=(String)constructor.newInstance(newStringBuffer(“abc”));

      

 

      Field类

             代表某个类中的成员变量

import java.lang.reflect.Field;

import java.lang.reflect.Method;

 

public class ReflectTest {

 

   public static void main(String[]args)throws Exception {

      String str1="abc";

      Class cls1=String.class;

      Class cls2=str1.getClass();

      Class cls3=null;

      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());

      

      ReflectPoint r=new ReflectPoint(3,5);

      Field fieldY=null;

      fieldY=r.getClass().getField("y");

      System.out.println(fieldY.get(r));

      

      Field fieldX=null;

      fieldX=r.getClass().getDeclaredField("x");

      fieldX.setAccessible(true);

      System.out.println(fieldX.get(r));

      changeStringValue(r);

      System.out.println(r);

      

      Method methodCharAt=String.class.getMethod("charAt",int.class);

      System.out.println(methodCharAt.invoke(str1, 1));

      

      //TestArguments.main(new String[]{"111","222","333"});

      String startingClassName=args[0];

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

      //mainMethod.invoke(null,new Object[]{newString[]{"111","222","333"}} );

      mainMethod.invoke(null,(Object)newString[]{"111","222","333"} );

    }

 

   private static void changeStringValue(Objectobj)throws Exception {

      // TODO Auto-generated method stub

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

      for(Field field: fields){

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

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

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

             field.set(obj,newValue);

             System.out.println(newValue);

          }

      }

          

    }

 

}

class TestArguments{

   public static void main(String[] args){

      for(String arg: args)

      {

          System.out.println(arg);

      }

    }

}

 

Method类

   代表某个类中的一个成员方法

得到类中的某一个方法:

    MethodcharAt=Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);

 

调用方法:

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

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

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

 

Jdk1.4和Jdk1.5的invoke方法的区别:

    Jdk1.5:public Object invoke(Object obj,Object…args)

   Jdk1.4:  public Object invoke(Object obj,Object[]args),即按Jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为charAt.invoke(“str1”,newObject[]{1})形式。

 

 

 

对接收数组参数的成员方法进行反射:

   一个程序能够根据用户提供的类名,去执行该类中的main方法。

但是问题是:

   启动java程序的main方法的参数是一个字符串数组,即public static void main(String[]args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按Jdk.5的语法,整个数组是一个参数,而按Jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac到底会按照那种语法进行处理呢?Jdk1.5当然要兼容Jdk1.4的语法,会按Jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数,所以,在给main方法传递参数时,不能使用代码

MainMethod.invoke(null,newString[]{“xxx”}),javac只把它当做Jdk1.4的语法进行理解,而不把它当做Jdk1.5的语法解释,因此会出现参数不对的问题。

 

解决方法:

   mainMethod.invoke(null,new Object[]{new String[]{“xxx”}});

   mainMethod.invoke(null,(Object)newString[]{“xxx”});编译器会作特殊处理,编译时不把参数当做数组看待,也就不会把数组打散成若干个参数了。

 

 

Hashcode方法的作用:set集合不允许重复,如果想查找一个集合中是否包含某个对象,通常是逐一的取出每个元素与要查找的对象进行比较,当发现某个元素与正要查找的对象进行equals

方法比较的结构相等时,则停止继续查找并返回肯定的信息,否则,返回否定的信息,如果一个集合中有很多个元素,譬如有一万个元素,并且没有包含要查找的对象时,则意味着你的程序需要从集合中取出一万个元素进行逐一的比较才能得到结论,有人发明列一种哈希算法来提高从几何中查找元素的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希吗分组,每组分别对应某个区域,根据一个对象的哈希吗就可以确定对象应该存储在哪个区域,然后就可以直接去哪个区域查找就OK了,这样就提高了查找的性能。要想Hashcode有价值的话前提条件是必须存储在Hash集合当中,只有存储集合是Hans集合时,Hashcode值才有价值,两个对象虽然equals相等了,但是你算出的Hashcode值是按照内存地址计算的,这样两个本来应该相同的对象分别被存到了不同的区域,当去找这个对象是我在一个区域里找,不去另外一个区域找,那么就找不到为了让相等的对象也肯定被放到相同的区域,如果两个对象equals相等的话,你应该也让他们的hashcode也相等,如果我的对象不要存到Hash集合中,那么就不需要计算hashcode值了,当一个对象被存储进HashSet集合中以后,即不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使contains方法是用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也将导致无法从hashSet集合中单独删除当前对象,从而造成内存泄露。

 

 

Properties对象等价于一个HashMap对象,可以把自己内存中的键值对存到硬盘的文件上,也可以在初始化的时候从硬盘上把自己的文件加载进来

 

 

反射的作用:就是实现框架的功能,

 

框架与框架要解决的核心问题

   我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把们和窗插进我提供的框架中,框架与工具类是有区别的,工具类被用户的类调用,而框架则是调用用户提供的类。

 

框架要解决的核心问题:

   我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢,我写的框架程序怎样能调用到你以后写的类(门窗呢)

   因为我在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用反射的方式来做。

 

综合案例:

 

   import java.io.FileInputStream;

import java.io.InputStream;

import java.util.Collection;

import java.util.Properties;

public class ReflectTest2 {

   public static void main(String[]args)throws Exception{

      //Collection collections=new ArrayList();//打印结构为4

      

      

 

      

      InputStream props=newFileInputStream("config.properties");

      Properties pop=new Properties();

      pop.load(props);

      props.close();

      String className=pop.getProperty("className");

      Collectioncollections=(Collection)Class.forName(className).newInstance();

      //Collection collections=new HashSet();//打印结果为3

      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());

      

    }

}

 

public class ReflectPoint {

 

      private int x;

      public int y;

      public String ptr1="ball";

      public String ptr2="basketball";

      public String ptr3="itcast";

      public ReflectPoint(int x, int y) {

          super();

          this.x = x;

          this.y = y;

      }

      @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;

      }

      @Override

      public String toString() {

          // TODO Auto-generated method stub

          return ptr1+":"+ptr2+":"+ptr3;

      }

      

      

      

}

 

 

 

0 0