Java知识

java基础-反射

2019-03-13  本文已影响13人  return_toLife

知识点

  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. 这里只是对反射中常用到的基本方法做了一些介绍,反射的应用场景并没有涉及到,后续会继续学习反射在开发中所发挥的作用
上一篇 下一篇

猜你喜欢

热点阅读