Java高新技术:反射

来源:互联网 发布:手机淘宝申请售后不了 编辑:程序博客网 时间:2024/05/21 18:37
Class类
   Class类是反射的基石,而java中各个java类也是属于同一类事物。而这类事物就是Class类
(平时定义类都是用class,注意这里小写和Class类的大写)
错误的赋值:Class cs=new Class();
正确的赋值:Class cs2=Date.class;
字节码:当一个类(二进制程序)被类加载器加载到内存中,会占用一部分内存空间,这部分空间的内容就叫做字节码;
不同的类字节码是不同的,所以在内存空间的内容是不同的,这一个个内存空间可分别用一个个对象来表示。
获取各个字节码对应的实例对象的三种方法:
(1)类名.class
(2)对象.getClass()
(3)Class.forName("类名"):返回字节码,java虚拟机还没有字节码,会用类加载器加载,把字节码缓存起来,该方法再返回该字节码

八个基本数据类型,分别对应八个Class对象,另外还有一个void.class

//获取各个字节码对应的实例对象三种方法String string="反射";Class cs1=String.class;Class cs2=string.getClass();Class cs3=Class.forName("java.lang.String");//三个类型对应的字节码是同一份System.out.println(cs1==cs2);//trueSystem.out.println(cs2==cs3);//true//isPrimitive()判断是否是基本类型System.out.println(cs1.isPrimitive());//falseSystem.out.println(int.class.isPrimitive());//trueSystem.out.println(int.class==Integer.class);//falseSystem.out.println(int.class==Integer.TYPE);//trueSystem.out.println(int[].class.isPrimitive());//数组不是原始类型System.out.println(int[].class.isArray());//true


反射概念理解

反射就是把Java类中的各种成分映射成相应的java类
例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示。就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
        一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。


Constructor类

Constructor类代表某一类的构造方法。
获取构造方法:
        1)得到这个类的所有构造方法:如得到上面示例中Person类的所有构造方法
              Constructor[] cons = Class.forName(“cn.itheima.Person”).getConstructors();
        2)获取某一个构造方法:
              Constructor con=Person.class.getConstructor(StringBuffer.class);
利用构造方法创建对象:newInstance()
    通常方式:String aString=new String(new StringBuffer("hello"));
    反射方式:String aString=(String)constructor.newInstance(new StringBuffer("hello"));

注:1.反射导致程序性能下降。
    2.注意强制类型转换,因为编译只是检查语法,并不执行,所以并不知道它是String类型的构造函数;
    3.对于无参构造函数可以直接利用Class.newInstance()方法;

//反射//constructorString.class.getConstructors();Constructor constructor=String.class.getConstructor(StringBuffer.class);String aString=(String)constructor.newInstance(new StringBuffer("hello"));System.out.println(aString);

Field类

Field代表成员变量;

从以下具体例子了解Field类相关知识,ReflecPoint类如下所示:

package com.sf.day1;public class ReflectPoint {private double a;public  double b;public String xString="best";public String yString="bad";public String zString="justsoso";public ReflectPoint(double a, double b, String xString, String yString,String zString) {super();this.a = a;this.b = b;this.xString = xString;this.yString = yString;this.zString = zString;}@Override public String toString(){return xString+" "+yString+""+zString;} }
注意下面代码中的afield和bfield知识类中的变量,而不是point里的变量,所以必须用Field类变量.get(对象)来获取对象中变量


//filedReflectPoint  point=new ReflectPoint(3.0, 4.5,"best","bad","justsoso");Field afield=point.getClass().getDeclaredField("a");//getDeclaredField获取该类中任意成员变量,包括私有Field bfield=point.getClass().getField("b");afield.setAccessible(true);//暴力反射,使得private类型的a可以被访问;System.out.println(afield.get(point));//通过对象afield的get方法获得具体的某对象成员变量的值System.out.println(bfield.get(point));

课堂练习:将对象中的所有String类型的成员变量对应的字符串内容中的字母b改成a

(前面注释的是没看老师写之前自己尝试着写,没实现的语句)
//filed练习//Field xField=point.getClass().getField("xString");//xField.get(point).toString().replace("b", "a");//System.out.println(xField.get(point));//练习Field[] fields=point.getClass().getFields();for(Field field:fields){if(field.getType()==String.class){String  oldString=(String)field.get(point);String newString=oldString.replace("b", "a");field.set(point, newString);}}System.out.println(point.toString());


Method类

Method代表成员方法

获取Method对象:.getMethod(“方法名”,方法参数类型的字节码)

注:需要方法参数类型这个参数是由于方法重载的存在。

实现此方法所用方法:invoke(对象,参数)

注意:如果是实现某一静态方法,则不需要对象来调用,此时对象位置为null

//MethodMethod method=string.getClass().getMethod("charAt", int.class);System.out.println(method.invoke(string, 1));//调用mainMethod method2=Class.forName(args[0]).getMethod("main", String[].class);method2.invoke(null, (Object)new String[]{"aaa","bbb","ccc"});}}class TestMainMethod{public static void main(String[] args) {for(String arg:args){System.out.println(arg);}

注:实现main的调用要在Run configurations里设置Arguments为com.sf.day1.TestMainMethod;即是此处的args[0];


数组的反射

nt[]数组的名称为:[I

Array工具类用于完成对数组的反射操作:

        Array.getLength(Object obj);//获取数组的长度

        Array.get(Object obj,int x);//获取数组中的元素

Arrays.asList  (List类型) 方法:直接展示改List中所有元素

package com.sf.day1;import java.lang.reflect.Array;import java.util.Arrays;public class ArrayRefl {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubint a[]={1,2};int b[]=new int[5];int c[][]=new int[3][4];String  d[]=new String[]{"To","Be","No","1"};System.out.println(a.getClass()==b.getClass());//true.注:用等号,没必要用equalsSystem.out.println(a.getClass().getName());//        [ISystem.out.println(c.getClass().getName());//        [[ISystem.out.println(c.getClass().getSuperclass().getName());//java.lang.ObjectSystem.out.println(d.getClass().getSuperclass().getName());//java.lang.ObjectObject obj1=a;Object obj2=b;Object obj3=c;Object obj4=d;//Object[] obj5=a;          //定义错误,a中元素为int类型,注意基本数据类型不是Object//Object[] obj5=b;Object[] obj6=c;             //可以,因为c中元素为一位数组,一维数组是ObjectObject[] obj7=d;System.out.println(a);//  [I@1db9742System.out.println(Arrays.asList(a));// [[I@1db9742]System.out.println(d);                //[Ljava.lang.String;@106d69cSystem.out.println(Arrays.asList(d));   //[To, Be, No, 1]printObj(a);printObj(d);printObj("hehe");}public static void printObj(Object obj) {// TODO Auto-generated method stubif(obj.getClass().isArray()){for(int i=0;i<Array.getLength(obj);i++)        {System.out.println(Array.get(obj, i));   //Array.get获取数组元素}}else {System.out.println(obj);}}}


0 0