美文网首页知识点
深入理解反射

深入理解反射

作者: Cherry300 | 来源:发表于2019-01-15 22:23 被阅读30次

    众所周知,如果没有了java的反射,那么java中的框架将不复存在,所以当我们学好了反射以后对我们日后学习框架是有很多的帮助的,下面,我把我学反射的一些总结分享给大家。

    刚接触反射的时候感觉它真是太帅了,尤其是暴力反射我感觉真的很牛x(下面我会介绍的),其实反射说白了点讲,就是通过java中给我们提供的一些类和方法,将我们类的字段、方法以及各种成分映射成相应的它们给我们提供的类和方法。

    Class类为反射的基石,下面我将介绍三种方式获得Class对象的方式:

    //以String类为例,获得其字节码对象,首先我们定义一个String对象

    String str = "getClass";

    //第一种方式

    Class stringClassOne = str.getClass();

    //第二种方式

    Class stringClassTwo = String.class;

    //第三种方式,forName()方法的参数必须是包名和类名

    Class stringClassThree = Class.forName("java.lang.String");

    //但是,当我们通过上面的方式获得了字节码对象以后,我们可以怎么用这个对象呢?

    String str = "reflect";

    //这个方法判断当前的类型是否为原始类型

    System.out.println(str.getClass().isPrimitive());

    //我们可以看出Integer和int的字节码文件并不是同一份,但是Integer.Type得到的是原始类型的字节码文件

    System.out.println(Integer.class == int.class);

    System.out.println(Integer.TYPE == int.class);

    //通过Class对象看是否为一个数组类型

    System.out.println(new int[2].getClass().isArray());

    //通过Class对象得到当前对象的类型

    System.out.println("The class of " + str +" is " + str.getClass().getName());

    //但是上面的getName()这个方法有几点我们应该注意

    //首先,如果此类对象表示一个基本类型或 void,则返回的名字是一个与该基本类型或 void所对应的 Java语言关键字相同的 String。

    System.out.println(int.class.getName());

    System.out.println(void.class.getName());

    /*

    * 如果此类对象表示一个数组类,则名字的内部形式为:表示该数组嵌套深度的一个或多个 '[' 字符加元素类型名。元素类型名的编码如下:

    *  元素类型名   编码

    boolean     Z

    byte     B

    char     C

    class or interface Lclassname;

    double     D

    float     F

    int     I

    long     J

    short     S

    */

    System.out.println(new Object[3].getClass().getName());

    System.out.println(new int[3][4][5][6][7][8][9].getClass().getName());

    //下面,我们可以通过Class的实例对象创建一个对应的类的实例对象:

    @SuppressWarnings("unchecked")

    //得到String类型的Class对象

    Class<String> stringClass = (Class<String>)Class.forName("java.lang.String");

    //通过这个Class对象得到一个构造方法,但是构造方法参数类型并不相同,所以我们给这个方法一个参数

    Constructor<String> con = stringClass.getConstructor(char[].class);

    //用这个构造方法创建一个String类型的实例,参数要与上面给的参数类型相对应

    String newValue = con.newInstance(new char[]{'j','a','v','a'});

    System.out.println(newValue);

    //我们也可以通过Class的实例对象创建一个String类型的实例

    //这种方法是用缓存一个无参数的构造方法实现的,所以,由此看出,反射是比较消耗性能的

    String str = stringClass.newInstance();

    System.out.println(str.length());

    下面我们得到对象身上的字段:

    public class ClassTest {

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

    Point point = new Point(13,14,"javareflect","man");

    @SuppressWarnings("unchecked")

    Class<Point> pointClass = (Class<Point>) Class.forName("com.java.day01.ClassTest$Point");

    //因为y字段是public的,所以我们可以通过这种方式访问

    Field yField = pointClass.getField("y");

    int y = (Integer) yField.get(point);

    System.out.println(y);

    //通过下面的这种方式访问私有的字段

    Field xField = pointClass.getDeclaredField("x");

    xField.setAccessible(true);

    int x = (Integer) xField.get(point);

    System.out.println(x);

    //我们也可以将其私有的字段更改,通过上面这种反射的方式,是不是很帅气!!!

    System.out.println(point);

    Field[] fields = pointClass.getDeclaredFields();

    for(Field field : fields) {

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

    field.setAccessible(true);

    field.set(point, field.get(point).toString().replace('a', '$'));

    }

    }

    System.out.println(point);

    }

    static class Point {

    private int x;

    public int y;

    private String name;

    private String sex;

    public Point(int x, int y, String name, String sex) {

    super();

    this.x = x;

    this.y = y;

    this.name = name;

    this.sex = sex;

    }

    @Override

    public String toString() {

    return "Point [name=" + name + ", sex=" + sex + "]";

    }

    }

    }

    下面我们得到对象身上的方法:

    String str = "javareflect";

    Class<String> strClass = (Class<String>) str.getClass();

    //通过Class实例得到String对象的方法

    Method method = strClass.getMethod("charAt", int.class);

    //方法与对象是没有关系的,它是属于类的,是方法作用在某个对象身上

    char printVal = (Character)method.invoke(str, 2);

    System.out.println(printVal);

    深入理解关于方法的反射

    public class ClassTest {

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

    //我们通过run配置,给主方法的数组赋值,从而得到其他类的类名,然后运行这个类的主函数

    String className = args[0];

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

    /*

    * 由于jdk1.5之前并没有可变参数这一特性,以前invoke的第二个参数是一个Object数组类型,而高的jdk版本

    * 必须向下兼容,所以当我们new一个引用类型的数组时,java会把他认为是一个Object类型的数组,从而导致程序

    * 出错,所以我们自己new一个Object数组将正确的参数类型给放进去,这样程序就不会出错了,但是基本类型并没有继承

    * Object类型,所以基本类型的数组并不存在这样的问题。

    */

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

    Method m1 = Class.forName(className).getMethod("say",char[].class);

    m1.invoke(null, new char[] {12});

    }

    }

    class TestMain {

    public static void main(String[] args) {

    for(String arg : args) {

    System.out.println(arg);

    }

    }

    public static void say(char[] i) {

    System.out.println("i am primitive type test");

    }

    }

    关于数组的反射:

    public class ClassTest {

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

    //利用Array类实现数组的反射

    Object obj = new int[] {12,14};

    //将obj这个不知道的类型打印输出

    if(obj.getClass().isArray()) {

    int length = Array.getLength(obj);

    for(int i = 0;i < length;i++) {

    Object arrVal = Array.get(obj, i);

    System.out.println(arrVal);

    }

    } else {

    System.out.println(obj);

    }

    }

    }

    相关文章

      网友评论

        本文标题:深入理解反射

        本文链接:https://www.haomeiwen.com/subject/lsbudqtx.html