美文网首页Java知识
java基础-反射

java基础-反射

作者: return_toLife | 来源:发表于2019-03-13 21:59 被阅读13次

    知识点

    1. 反射的基本概念
    2. 反射中class类的获取
    3. 反射中field类属性的获取
    4. 反射中method类方法的获取
    5. 反射中consturct类构造方法的获取
    6. 反射中implement类接口的获取
    7. 反射获取父类,调用方法

    一、反射的基本概念

    1.1 概念

    反射是一种强大的工具,它使得我们可以灵活的构建代码,这些代码可以在运行时装配,无需在组件之间进行源代码链接。反射允许我们在编写执行时,使我们的程序能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码,这使得反射成为构建灵活的应用的主要工具。但是需要注意,如果反射使用不当,成本会很高

    1.2 反射涉及到的相关包

    java.lang.Class;     //对应就是类
    java.lang.Field;      //对应就是类中的成员变量
    java.lang.Method;  //对应就是类中的方法
    java.lang.Modifier; //对应就是类中的变量/方法的定义域
    

    1.3反射的作用

    反射可以实现常说的反编译功能
    通过反射可以获得java对象的属性,方法,构造方法等

    二、获取class的三种方式

    2.1 获取方法如下:

     public static void main(String[] args) throws Exception{
    
            //通过类的包名获取
            Class clazz=Class.forName("com.dongdian.jj.myjavalib.reflect.ReflectTestBean");
    
            //通过class属性获取,每个类对象都会有个class属性
            Class clazz2=ReflectTestBean.class;
    
            //通过getClass方法获取,每个类对象都会该方法
            ReflectTestBean reflectTestBean=new ReflectTestBean();
            Class clazz3=reflectTestBean.getClass();
    
            System.out.println((clazz==clazz2)+"");
            System.out.println((clazz2==clazz3)+"");
          //  System.out.printf("clazz="+clazz+"--clazz2="+clazz2+"--clazz3="+clazz3);
        }
    
    //输出结果
    true
    true
    

    注意:由于jvm中只会加载一次reflectTestBean这个对象,他只会存在一个class实例,所以三种方式获取到的class对象地址都是相同的,上面代码输出结果肯定是相等的

    2.2 通过class对象获取实例

    在2.1中我们获取到了class对, 那么我们可以直接通过如下方法获取对象实例

     Class clazz2=ReflectTestBean.class;
     clazz2.newInstance();
    

    注意: class.newsInstance()调用的原java对象的无参构造方法,如果该对象没有无参构造方法则无法成功创建实例

    三、反射中field类属性的获取

    3.1获取类属性主要通过class类中的4个方法:

    //返回所有public的属性
     Field[] getFields();
    //返回指定的public的属性
     Field getField(String s);
    //返回所有属性
     Field[] getDeclaredFields();
    //返回指定的属性
     Field getDeclaredField(String s);
    

    3.2通过field对象获取对应属性的修饰符已经字段类型

    //返回属性的修饰符(public,private等)
    getModifiers();
    //返回属性的类型(Stirng,int 等)
    getType();
    //返回属性的名称
    getName();
    

    3.3例子,获取java.lang.String类中所有属性

           Class clazz=Class.forName("java.lang.String");
    
            Field[] fields=clazz.getDeclaredFields();
    
            for (Field field : fields) {
                System.out.println(Modifier.toString(field.getModifiers())
                        +" "+field.getType().getSimpleName()
                        +" "+field.getName());
            }
    
    //输出结果
    private final char[] value
    private int hash
    private static final long serialVersionUID
    private static final ObjectStreamField[] serialPersistentFields
    public static final Comparator CASE_INSENSITIVE_ORDER
    

    (ps:Modifier.toString(int i) 该方法可以将对应的值转换为我们常见的修饰符类型 )

    四、反射中method类方法的获取

    其实获取方式和上面属性的获取方式是类似的,这里接直接上例子了

    4.1获取java.lang.String类的所有方法

            Class clazz=Class.forName("java.lang.String");
            Method[] mothods=clazz.getDeclaredMethods();
            StringBuilder stringBuilde=new StringBuilder();
            for (Method mothod : mothods) {
                stringBuilde.append(Modifier.toString(mothod.getModifiers())).append(" ");
                stringBuilde.append(mothod.getReturnType().getSimpleName()).append(" (");
    
                Class[] classParameters=mothod.getParameterTypes();
    
                for (int i = 0; i < classParameters.length; i++) {
                    if(i==classParameters.length-1){
                        stringBuilde.append(classParameters[i].getSimpleName());
                    }else {
                        stringBuilde.append(classParameters[i].getSimpleName()).append(",");
                    }
                }
                stringBuilde.append(")");
    
                System.out.println(stringBuilde);
                stringBuilde.setLength(0);
            }
    
    //输出结果
    public boolean (Object)
    public String ()
    public int ()
    public volatile int (Object)
    public int (String)
    public int (String,int)
    static int (char[],int,int,String,int)
    static int (char[],int,int,char[],int,int,int)
    ....
    

    五、反射中consturct类构造方法的获取

    构造方法也同上,例子如下:

            Class clazz=Class.forName("java.lang.String");
            Constructor[] constructors=clazz.getDeclaredConstructors();
            StringBuilder stringBuilder=new StringBuilder();
            for (Constructor constructor : constructors) {
                stringBuilder.append(Modifier.toString(constructor.getModifiers())).append(" ");
                stringBuilder.append(clazz.getSimpleName()).append("(");
    
                Class[] params=constructor.getParameterTypes();
    
                for (int i = 0; i < params.length; i++) {
                    if(i==params.length-1){
                        stringBuilder.append(params[i].getSimpleName()).append(")");
                    }else {
                        stringBuilder.append(params[i].getSimpleName()).append(",");
                    }
                }
                stringBuilder.append("\n");
            }
            System.out.println(stringBuilder);
    
    //输出结果
    public String(byte[],int,int)
    public String(byte[],Charset)
    public String(byte[],String)
    public String(byte[],int,int,Charset)
    public String(byte[],int,int,String)
    ...
    

    六、 反射中implement类接口的获取

    同上

            Class clazz=Class.forName("java.lang.String");
            Class[] interfaces=clazz.getInterfaces();
            StringBuilder stringBuilder=new StringBuilder();
            for (Class anInterface : interfaces) {
                stringBuilder.append(anInterface.getName()).append("\n");
            }
            System.out.println(stringBuilder);
    
    //输出结果
    java.io.Serializable
    java.lang.Comparable
    java.lang.CharSequence
    

    七、反射获取父类,调用方法

    7.1 获取父类

      Class clazz=Class.forName("java.lang.String");
      Class surperClazz=clazz.getSuperclass();
    

    7.2通过反射调用方法

    准备一个对象

    public class Persion  {
    
    
        public String name;
        private int age;
        protected boolean gender;
    
        private String change(String newName){
            this.name=newName;
    
            return name;
        }
    
        private String change(String newName,boolean gender){
            this.name=newName;
            this.gender=gender;
            return name;
        }
    }
    

    通过反编译调用对象的私有方法

            Class clazz=Persion.class;
            //根据传入的形参类型找到对应的方法
            Method method=clazz.getDeclaredMethod("change",String.class);
            //设置为true才可以调用private修饰的方法
            method.setAccessible(true);
            //invoke就是调用方法,注意newInstance只能调用无参构造
            Object object=method.invoke(clazz.newInstance(),"Kiana Kaslana ");
            System.out.println(object.toString());
    
    //输出结果
    Kiana Kaslana 
    

    总结

    1. 反射基础中,比较需要注意的就是,每个class类对象只会存在一个实例,class.newInstance方法必须要有无参构造,想调用私有方法必须设置method.setAccessible(true);
    2. 在熟悉了上面的反射基础之后,我们也能自己动手实现简单的反编译
    3. 这里只是对反射中常用到的基本方法做了一些介绍,反射的应用场景并没有涉及到,后续会继续学习反射在开发中所发挥的作用

    相关文章

      网友评论

        本文标题:java基础-反射

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