黑马程序员-----反射

来源:互联网 发布:黑马java 2016 编辑:程序博客网 时间:2024/06/04 00:22

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

我的理解是:所谓反射,就是根据一个已经实例化了的对象来还原类的完整信息。

 

Class类

如果要完成反射,那么必须了解Class类

实例1:通过对象取得包名和类名package org.siu; class Test {     } public class Demo {    public static void main(String[] args) {        Test t = new Test();        System.out.println(t.getClass());        System.out.println(t.getClass().getName());    }}

此处的getClass()方法是默认继承自Object类的。在java中,Object类是所有类的父类,同样,所有类的实例化对象也都是Class类的实例。因此,这样一来就会牵扯到向上转型和向下转型的概念由于向下转型的不安全因素,在这里泛型也会接踵而来。

实例2:Class类的实例化由于Class类没有构造方法,所以实例化Class类的方式有点特殊,有三种方式:对象.getClass( )类.ClassforName( )class Test {     } public class Demo {    public static void main(String[] args) {        //方式一:        Test t = new Test();        Class<? extends Test> c1 = t.getClass();        System.out.println(c1);                 //方式二:        //为了避免特殊性,这里不用Test类,而用java库中的String类        Class<String> c2 = String.class;        System.out.println(c2);                 //方式三:        //forName()方法会抛出异常        Class<?> c3 = null;        try {            c3 = Class.forName("Test");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        System.out.println(c3);    }} 其中,forName( )方法需要重点掌握,因为它可以在类不确定的情况下实例化Class,更具灵活性

Class类的应用

Class类中有一个方法叫做newInstance(),它可以用来创建一个Class类对象的新实例。怎么说呢?Class对象包含的内容就是反射好的那个类,我们要构造那个类的新实例(新对象)

实例3:Class类的无参构造对象public class Demo {    public static void main(String[] args) {        //实例化Class对象,forName()方法会抛异常        Class<?> c = null;        try {            //这里需要完整的包名和类名            c = Class.forName("java.lang.String");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }                 //生成一个字符串的引用        String s = null;        try {            //将构造好的对象向下转型为String类            //newInstance()方法会抛异常            s = (String) c.newInstance();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        System.out.println("字符串长度: " + s.length());    }}

这样就通过无参数的形式构造了一个新的对象,如同正常模式中通过无参构造方法来构造新对象一样。我们知道,类中除了有无参构造方法,还会存在有参数的构造方法,那在反射中如何通过有参数的形式构造对象呢?

实例4:Class类的有参构造对象import java.lang.reflect.Constructor; public class Demo {    //下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了    public static void main(String[] args) throws Exception {        Class<?> c = null;        try {            c = Class.forName("java.lang.String");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        char[] ch = {'h','e','l','l','o'};        String s = null;        //获得Class类对象的有参构造方法,括号里面参数的写法是:类型.class        Constructor<?> con = c.getConstructor(char[].class);        //用此构造方法构造一个新的字符串对象,参数为一个char数组        s = (String) con.newInstance(ch);        System.out.println("构造的字符串:" + s);    }}

我们还是使用String类做例,因为String类用的比较多,便于理解。这里需要注意的是,构造方法需要使用getConstructor( )方法获得,至于参数类型则是:原有类型.class

 

还有一点,无论是有参还是无参,这里所使用的构造方法,原本的类里面必须对应存在。那么,如何才能知道原有类里面的构造方法,普通方法,继承的父类等详细信息呢?

 

获取类的结构

要通过反射获取类的结构我们这里要导入一个新的包java.lang.reflect


实例5:取得类的构造方法import java.lang.reflect.Constructor;import java.util.Arrays; public class Demo {    //下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了    public static void main(String[] args) throws Exception {        Class<?> c = null;        try {            c = Class.forName("java.lang.Boolean");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        //这里的getConstructors()方法返回的是一个Constructor数组        Constructor<?>[] cons = c.getConstructors();        //打印的方式你可以自己写,为了方便我用Arrays.toString(),凑合着看        System.out.println(Arrays.toString(cons));    }} 选择Boolean类来做例,因为Boolean类的构造方法就两个,方便看。
实例6:取得类所实现的接口import java.util.Arrays; public class Demo {    public static void main(String[] args) throws Exception {        Class<?> c = null;        try {            c = Class.forName("java.lang.Boolean");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        Class<?>[] in = c.getInterfaces();        System.out.println(Arrays.toString(in));    }}
实例7:取得父类public class Demo {    public static void main(String[] args) throws Exception {        Class<?> c = null;        try {            c = Class.forName("java.lang.Boolean");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        //注意了,这里不会是数组,why?        Class<?> su = c.getSuperclass();        System.out.println(su);    }} 别忘了,java中是单继承,父类只有一个
 实例8:取得类的全部方法import java.lang.reflect.Method; public class Demo {    public static void main(String[] args) throws Exception {        Class<?> c = null;        try {            c = Class.forName("java.lang.Boolean");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        Method[] m = c.getMethods();        //好吧,这次我就大发慈悲的写个打印列表出来        for (int i = 0; i < m.length; i++) {            System.out.println(m[i]);        }    }} 
实例9:取得本类的全部属性import java.lang.reflect.Field; class Person {    private String name;    private int age;} public class Demo {    public static void main(String[] args) throws Exception {        Class<?> c = null;        try {            c = Class.forName("Person");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        Field[] f = c.getDeclaredFields();        for (int i = 0; i < f.length; i++) {            System.out.println(f[i]);        }    }}getDeclaredFielsd()方法可以获取全部属性,getFields()只能获取公共属性。
实例10:获取本类中属性的值import java.lang.reflect.Field; class Person {    public String name;    private int age;         public Person(String name, int age) {        this.name = name;        this.age = age;    }} public class Demo {    public static void main(String[] args) throws Exception {        Person p = new Person("zhangsan",12);         Class<?> c = p.getClass();                 //获取公共属性的值        Field f1 = c.getField("name");        //get(p)表明要获取是哪个对象的值        String str = (String) f1.get(p);        System.out.println("姓名: " + str);                 //获取私有属性的值        Field f2 = c.getDeclaredField("age");        //age是私有属性,所以要设置安全检查为true        f2.setAccessible(true);        int age = (int) f2.get(p);        System.out.println("年龄: " + age);    }} 要注意的是:setAccessible()方法可以设置是否访问和修改私有属性。

反射的应用

实例11:通过反射修改属性import java.lang.reflect.Field; class Person {    private String name;         public Person(String name) {        this.name = name;    }         public String toString() {        return "姓名: " + this.name;    }} public class Demo {    public static void main(String[] args) throws Exception {        Person p = new Person("王二狗");        System.out.println(p);        Class<?> c = p.getClass();             //定义要修改的属性        Field f = c.getDeclaredField("name");        f.setAccessible(true);        //修改属性,传入要设置的对象和值        f.set(p, "张二蛋");        System.out.println(p);    }}
实例12:通过反射调用方法import java.lang.reflect.Method; class Person {    public void print(int i) {        System.out.println("我在写数字: " + i);    }         public static void say(String str) {        System.out.println("我在说: " + str);    }} public class Demo {    public static void main(String[] args) throws Exception {        Person p = new Person();        Class<?> c = p.getClass();             //getMethod()方法需要传入方法名,和参数类型        Method m1 = c.getMethod("print", int.class);        //invoke()表示调用的意思,需要传入对象和参数        m1.invoke(p, 10);                 Method m2 = c.getMethod("say", String.class);        //这里的null表示不由对象调用,也就是静态方法        m2.invoke(null, "你妹");    }}这里演示了一个普通的有参方法和一个静态方法。既然有参数的都写出来了,那么无参的就更简单了,直接传入一个对象即可。 
实例13:通过反射操作数组import java.lang.reflect.Array; public class Demo {    public static void main(String[] args) throws Exception {        int[] arr = {1,2,3,4,5};        Class<?> c = arr.getClass().getComponentType();                 System.out.println("数组类型: " + c.getName());        int len = Array.getLength(arr);        System.out.println("数组长度: " + len);        System.out.print("遍历数组: ");        for (int i = 0; i < len; i++) {            System.out.print(Array.get(arr, i) + " ");        }        System.out.println();        //修改数组        System.out.println("修改前的第一个元素: " + Array.get(arr, 0));        Array.set(arr, 0, 3);        System.out.println("修改后的第一个元素: " + Array.get(arr, 0));    }} 这里要注意一点,getComponentType( )返回的是数组元素的Class。




0 0
原创粉丝点击