Java--反射的逐步理解

来源:互联网 发布:nginx 多个域名站点 编辑:程序博客网 时间:2024/05/23 21:34

层层引入反射的作用

一.类类型的概念:所有类都是对象,是Class类的实例对象,这个对象我们成为该类的类类型

1.下面是一个小的test,以产生3种方式的类类型:

public class test {    /**     * @param args     */    public static void main(String[] args) {        foo user = new foo();        //任何一个类都包含一个隐含的静态成员变量class        Class c1 = foo.class;        Class c2 = user.getClass();        Class c3 = null;        try {            c3 = Class.forName("test.foo");        } catch (ClassNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }
        //c1 c2,c3是foo类的类类型
    }
class foo{ void print(){ System.out.println("haha"); } }

2.其实数据类型也有自己的类类型

  Class class1 = int.class;//int的类类型  Class class2 = String.class;  Class class3 = double.class;  Class class4 = Double.class;  System.out.println(class1);  System.out.println(class2.getSimpleName());  System.out.println(class3);  System.out.println(class4);

3.类类型可以创建类的实例对象

try {    foo h =(foo)c1.newInstance();//类类型可以创建该类的实例对象    //需要有无参数的构造方法    h.print();} catch (InstantiationException e) {    // TODO Auto-generated catch block    e.printStackTrace();} catch (IllegalAccessException e) {    // TODO Auto-generated catch block    e.printStackTrace();}

 

二.动态加载类

1.我们有这样的疑惑,如果一个主函数中有好多个类,其中有一个类出现错误,其他类都没法用,所以我们就想我们要用那个类就让那个类运行,并且不想在重新编译主类,这时候动态加载类就派上了用场,不用动态类的时候会出现类似这样的问题:

当然这种情况只会出现在我们手动采用javac编译导致的,开发工具让我们看不到这些细节的东西。.

2.我们先引出动态加载类的概念,class.forName("")是动态加载类,而new class()是静态加载类,本质区别是,静态加载类的时候,编译时类必须存在,而动态加载类不一定存在。

public class sum {    public static void main(String[] args) {        try        {            //动态加载类            //args[0]表示的是在main方法里面传进来的第一个参数            Class c = Class.forName(args[0]);        }        catch(Exception e)        {            e.printStackTrace();        }    }}

三.类对类的操作

1.通过Method类获取成员方法

/**     * 获取成员方法     * Method类,方法对象     * 一个成员方法就是一个Method对象     * getMethods()方法获取所有的public的函数,包括父类继承而来的     * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限     * @param obj     */    public static void  printClassMessage(Object obj) {        Class c1 = obj.getClass();        System.out.println(c1.getName());        Method[] ms = c1.getMethods();//c.getDeclaredMethods()        for (int i = 0; i < ms.length; i++) {            //得到方法的返回值类型的类类型            Class returnType = ms[i].getReturnType();            System.out.print(returnType.getName()+"");            //得到方法的名称            System.out.print(ms[i].getName()+"(");            //获取参数类型--->得到的是参数列表的类型的类类型            Class[] paramTypes = ms[i].getParameterTypes();            for (Class class1 : paramTypes) {                System.out.println(class1.getName());            }            System.out.println(")");        }            }

2.通过Field类获取成员变量

/**     * 获取成员变量     * 成员变量也是对象     * java.lang.reflect.Field     * Filed类封装了关于成员变量的操作     * getFileds()方法获取的是所有的public的成员变量的信息     * getDeclaredFiled获取的是该类自己声明的成员变量的信息     * @param obj     */    public static void printFieldMethod(Object obj) {        Class c1 = obj.getClass();        Field[] fs =c1.getDeclaredFields();        for (Field field : fs) {            //得到成员变量的类型的类类型            Class fieldType =field.getType();            String typeName = fieldType.getName();            //得到成员变量的名称            String fieldName=field.getName();            System.out.println(typeName+" "+fieldName);        }    }

3.通过Constructor类获取构造函数

/**     * 打印对象的构造函数的信息     * java.lang.Constructor中封装了构造函数的信息     * getConstructors获取所有的public的构造函数     * getDeclaredConstructors得到所有的构造函数     * @param obj     */    public static void printConMessage(Object obj){        Class c = obj.getClass();        //Constructor cs = c.getConstructors();        Constructor[] cs =c.getDeclaredConstructors();        for (Constructor constructor : cs) {            System.out.println(constructor.getName()+"(");            Class[] paramTypes =constructor.getParameterTypes();            for (Class class1 : paramTypes) {                System.out.println(class1.getName()+",");            }            System.out.println(")");        }    }

四.反射

1.反射的作用是指定方法名称调用方法,demo如下:

public class demo {    public static void main(String[] args) {        //获取类的信息,就得先获取类的类类型        A a1 = new A();        Class c1 = a1.getClass();        /*         * 获取方法,名称和参数列表来决定         * getMethod获取的是public的方法         * getDelcaredMethod获取的的是自己声明的方法         *          */        try {            Method method = c1.getMethod("print", int.class,int.class);                        /*             * 方法的反射操作             * a1.print(10,20);方法的反射操作是用m对象来进行方法调用和a1.print调用的效果相同             * 方法如何没有返回值返回null,有返回值返回具体的返回值             * ...表示有几个参数传几个             */             Object object =method.invoke(a1, 10,20);             Method method2 =c1.getMethod("print", new Class[]{String.class,String.class});             method2.invoke(a1, "hello","world");             Method method3 =c1.getMethod("print",null);             Object a = method3.invoke(a1);        } catch (SecurityException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (NoSuchMethodException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }catch (IllegalArgumentException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IllegalAccessException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (InvocationTargetException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    }class A{    public void print() {        System.out.println("hello world");    }        public void print(int a,int b){        System.out.println(a+b);    }    public void print(String a,String b){                System.out.println(a.toUpperCase()+b.toLowerCase());    }        }

2.案例,通过标准JavaBean的属性名获取其属性值

五.泛型

1.泛型是什么?看下面两个声明

//只能传String类型的数        ArrayList<String> list = new ArrayList<String>();        ArrayList list2 = new ArrayList();

2.泛型的本质,看下面的demo

public class fanxing {/** * 通过Class,Method来认识泛型的本质 * @param args */    public static void main(String[] args) {        //只能传String类型的数        ArrayList<String> list = new ArrayList<String>();        ArrayList list2 = new ArrayList();        list.add("hello");        //list.add(20);        Class c1 = list.getClass();        Class c2 =list2.getClass();        System.out.println(c1==c2);       }}

由运行结果可以得出下面结论:

反射的操作都是编译之后的操作

c1==c2结果返回true说明编译之后的泛型是去泛型化的

Java中集合的泛型,是防止错误输入的,只是在编译阶段有效

3.利用方法的反射来操作,绕过编译

try {            Method a1 =c1.getMethod("add", Object.class);            Object a2 = a1.invoke(list, 2);         System.out.println(list.size());         System.out.println(list);        } catch (SecurityException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (NoSuchMethodException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }catch (IllegalArgumentException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IllegalAccessException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (InvocationTargetException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }

代码的运行结果验证了泛型,得出结论,绕过编译操作就绕过了泛型

最后谢谢大家的阅读

原创粉丝点击