• java高级——反射


    慕课网《反射——Java高级开发必须懂的》听课笔记

    一、class类的使用

    class ClassDemo 
    {
        public static void main(String[] args) 
        {
            //Foo的对象怎么表示?
            Foo foo1 = new Foo();//foo1就表示出来了
            //Foo这个类是Class类的实例对象,只有java的虚拟机能创建它的实例对象
            //任何一个类都是 Class的实例对象,这个实例对象有三种表示方式:
    
            //(1)、类名.class 任何一个类都有一个隐含的静态成员变量class
            Class c1 = Foo.class;
    
            //(2)、已知该类的对象,通过getClass方法
            Class c2 = foo1.getClass();
            /*
             * c1、c2表示类的类类型,一个类只可能是一个Class类的类类型
             * 万物皆对象
             * 类为Class类的实例对象
             * 这个对象称之为该类的类类型
             *
            */
    
            //(3)、
            Class c3 = null;
            try
            {
                c3 = Class.forName("Foo");
            }
            catch (ClassNotFoundException e)
            {
                e.printStackTrace();
            }
            System.out.println(c2 == c3);
    
            //我们完全可以通过类的类类型创建该类的实例对象--->通过c1、c2、c3创建Foo类的实例对象
            try
            {
                /*
                 * 为什么强制转换呢?
                 * newInstance到底返回什么才能让所有的类都可以这样去实例化呢?
                 * 那就需要所有类的父类对不对,那个所有类的父类就是Object,所以返回回来的是Object,
                 * 那么这样的话就需要转换类型了,如果设计的人本身就不知道你有Foo这个类,所以他当然不会返回Foo这个类型。
                 *
                */
                Foo foo = (Foo)c1.newInstance();//需要无参构造方法
                foo.print();
            }
            catch (InstantiationException e)
            {
                e.printStackTrace();
            }catch (IllegalAccessException e)
            {
                e.printStackTrace();
            }
        }
    }
    class Foo
    {
        void print(){}
    }

     二、方法的反射

    new 创建的对象,是静态加载类,在编译时刻就需要加载所有可能使用到的类,无论用不用的到,通过动态加载类可以解决这个问题

    class Office 
    {
        public static void main(String[] args) 
        {
            try
            {
                //动态加载类,在运行时加载
                Class c = Class.forName(args[0]);
                //通过类类型创建对象
                OfficeAble oa = (OfficeAble)c.newInstance();
                oa.start();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    统一标准

    interface OfficeAble
    {
        public void start();
    }

    当需要拓展功能,如要增加Excel时,只需要实OfficeAble接口,不需要重新编译,一般功能性的类使用动态加载

    class Word implements OfficeAble 
    {
        public void start()
        {
            System.out.print("Word start");
        }
    }

     三、获取方法的信息

    基本数据类型存在类类型

    class classType
    {
        public static void main(String[] args) 
        {
            //基本数据类型都存在类类型,以下方式可以表示
            Class c1 = int.class;//int的类类型
            Class c2 = String.class;//String的类类型  String 的类字节码
            Class c3 = double.class;//int的类类型
            Class c4 = void.class;//int的类类型
            //打印类的名称
            System.out.println(c1.getName());
            System.out.println(c2.getName());
            System.out.println(c2.getSimpleName());//不含包名
        }
    }

    打印类的基本信息,包括成员变量、成员函数、构造方法

    import java.lang.reflect.Method;
    import java.lang.reflect.Field;
    import java.lang.reflect.Constructor;
    class  ClassMessage
    {
        /**
         * 打印类的信息,包括类的成员函数、成员变量
         * obj该对象所属类的信息
        */
        //获取类的成员函数的信息
        public static void ClassMessage (Object obj) 
        {
            //要获取类的信息,首先要获取类的类类型
            Class c = obj.getClass();//传递的是哪个子类的对象,得到的就是哪个类的类类型
    
            System.out.println("类名称:" + c.getName());
            /**
             * Method类,方法对象
             * 一个成员方法就是一个Method对象
             * getMethod()方法获取的就是所有的public函数,包括父类继承来的
             * getDeclaredMethod()获取的就是所有该类自己声明的方法,不问访问权限
            */
            Method[] ms = c.getMethods();//c.getDeclaredMethod()
            for(int i = 0; i<ms.length; i++)
            {
                //获取方法返回值类型的类类型,如得到int,就是得到int.class
                Class returnType = ms[i].getReturnType();
                System.out.print(i + " " + returnType.getName() + " ");
                //获取方法名称
                System.out.print(ms[i].getName() + "(");
                //获取参数类型--->得到的是参数列表的类型的类类型
                Class[] paramTypes = ms[i].getParameterTypes();
                for (Class class1: paramTypes)
                {
                    System.out.print(class1.getName() + ",");
                }
                System.out.println(")");
            }
    //-----------------------------------------------------------------------------------------
            /**
             * 成员变量也是函数
             * java.lang.reflect.Field
             * getFields()方法获取的是所有的public的成员变量的信息
             * getDeclaredField()获取该类自己声明的成员变量的信息(私有)
            */
            //Field[] fs = c.getField();
             Field[] fs = c.getDeclaredFields();
             for (Field field : fs) 
             {
                 //得到成员变量的类类型
                 Class fieldType = field.getType();
                 String typeName = fieldType.getName();//成员变量的名字
                 String fieldName = field.getName();//成员变量的名称
                 System.out.println(typeName + " " + fieldName);
             }
    
    //-----------------------------------------------------------------------------------------
             /**
             * 打印对象的构造函数信息
             * 构造函数也是对象
             * java.lang.Constructor中封装了构造函数的信息
             * getConstructor()获取所有的public构造函数,getDeclaredConstructor()获取所有的构造函数
             */
             // Constructor[] cs = c.getConstructor();
             Constructor[] cs = c.getDeclaredConstructors();
             for (Constructor constructor: cs)
             {
                 System.out.print(constructor.getName() + "(");
                 //获取构造函数的参数列表-->得到的是参数列表的类类型
                 Class[] paramTypes = constructor.getParameterTypes();
                 for (Class class1 : paramTypes)
                 {
                     System.out.print(class1.getName() + ",");
                 }
                 System.out.println(")");
             }
        }
    }

    测试

    class ClassMessageMain
    {
        public static void main(String[] args) 
        {
            String s = "hello";
            ClassMessage.ClassMessage(s);
            Integer n1 = 1;
            ClassMessage.ClassMessage(n1);
        }
    }

     四、方法的反射操作

    1)如何获取某个方法

    方法的名称和方法的参数列表才能唯一决定某个方法

    2)方法的反射操作

    method.invoke(对象,参数列表)

    import java.lang.reflect.Method;
    @SuppressWarnings("unchecked")
    public class MethodReflect 
    {
        public static void main(String[] args) 
        {
            /**
             * 获取print(int,int)方法,
             * 1、获取一个方法要先获取类的信息,获取类的信息要先获取类的类类型
            */
            A a1 = new A();
            Class c = a1.getClass();
            /**
             * 2、获取方法  名称和参数列表来决定
             * getMethod获取的就是public的方法
             * getDelcaredMethod自己声明的方法
            */
            try
            {
                //两种写法都可以
                //Method m = c.getMethod("print", new Class[]{int.class, int.class});
                Method m = c.getMethod("print", int.class, int.class);
                /**
                 * 方法的反射操作
                 * 以往调用 a1.print(10, 20);
                 * 方法的反射操作是用m 对象来进行方法调用,和上面方式效果完全相同
                 * 方法无返回值则返回null,有返回值则返回具体返回值
                */
                //Object o = m.invoke(a1, new Object[]{10, 20});
                Object o = m.invoke(a1, 10, 20);
    
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
    
            System.out.println("========================");
            try
            {
                //获取方法print(String, String);
                Method m1 = c.getMethod("print", String.class, String.class);
                //用方法进行反射操作·
                Object o = m1.invoke(a1, "hello", "World");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            
        }
    }
    class A
    {
        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());
        }
    }

     五、集合泛型的本质

    import java.util.ArrayList;
    import java.lang.reflect.Method;
    @SuppressWarnings("unchecked")
    class  GenericNature
    {
        public static void main(String[] args) 
        {
            ArrayList list1 = new ArrayList();
            ArrayList<String> list2 = new ArrayList<String>();//只能放String 类型
            list1.add("hello");
            //list1.add(20);会出错
            Class c1 = list1.getClass();
            Class c2 = list2.getClass();
            System.out.println(c1==c2);//输出true
            /**
             * 反射的操作都是编译之后的操作,是运行时的操作
             * 上面结果返回true说明编译之后集合的泛型是去泛型化的
             * java集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效
             * 验证:可以通过方法的反射来绕过编译
            */
            try
            {
                Method m = c2.getMethod("add", Object.class);
                m.invoke(list2, 50);//绕过编译去操作就绕过了泛型
                System.out.println(list2.size());
                System.out.println(list2);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            //不能用for (String str:list2){}遍历,类型错误
        }
    }
  • 相关阅读:
    Java-使用IO流对大文件进行分割和分割后的合并
    Java-单向链表算法
    Java-二分查找算法
    Java-二叉树算法
    Java-对象比较器
    Android中Activity的四种开发模式
    Struts2工作原理
    C++实现单例模式
    数组中有一个数字出现的次数超过数组的一半,请找出这个数字
    c++ enum用法【转】
  • 原文地址:https://www.cnblogs.com/suwy/p/9174252.html
Copyright © 2020-2023  润新知