Java反射

Java反射

前言

前一段时间,曾经学习Mybatis-plus,阅读源码解决过不少问题,便萌生想要去阅读Spring框架源代码,以便在今后的面试和工作中能有出色的表现,有朋友建议我在阅读源码之前,应该对java的基础知识(反射等)和设计模式这一块有很深的理解,好吧,我工作以来,这些东西很久没有关注过。承认学习过,但是,中了那句话的毒(学习是为了更好的遗忘),因此,对这一块内容进行特别整理一下。

我们编写的Java代码,并不是可以直接运行的,而是需要由Java虚拟机经过编译,形成class文件。然后才能去执行。因为Java是面向对象的,每一个程序都是由一个或者多个对象组成,在我们运行程序时,整个对象会随着代码翻译成class文件。对于java中的反射,我的理解是:通过程序,获取到class文件中的内容;通过Java反射,我们能动态获取类中的内容;

在这里,要注意一下: 一个类是由不同的属性 方法(函数)组成;

在这里,我们先创建一个对象,方便后面演示:

public class User {
    private int id;
    private String name;
    private String sex;
    public String descr;

    public User(int id, String name, String sex, String descr) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.descr = descr;
    }
    private User(int id){
        this.id = id;
    }

    public User() {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }

    public String getDescr() {
        return descr;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setDescr(String descr) {
        this.descr = descr;
    }
    private void setOtherId(int id){
        this.id = id;
    }

public void setNameAndSex(String name,String sex){
    this.name = name;
    this.sex = sex;
}


}

 

如何创建反射类对象

/**
 * 通过反射获取类的三种方法;
 * 无论以下哪种方式,都可以获取到反射类;
 * 通过getName的方式可以获取到它所属类型,打印方式 包名.类名
 */

// 1. 第一种方式,通过Class.forName()的方式,这里需要注意一下,参数中必须设置类的全路径名;
Class  c1 = Class.forName("Reflect.User");
System.out.println(c1.getName());
// 2. 通过创建对象的方式,获取对象的class对象
String  s = new String();
Class  aClass = s.getClass();
System.out.println(aClass.getName());
// 3. 直接通过类的方式创建
Class stringClass = String.class;
System.out.println(stringClass.getName());

 

执行之后,输出的内容为:

Reflect.User

java.lang.String

java.lang.String

 

代码中,用到的类型,都是引用类型;

如果是基本类型的包装类型,获取到它的Class对象内容是:

Class btype = Boolean.TYPE;
System.out.println("Boolean:"+btype);
Class byType = Byte.TYPE;
System.out.println("Byte:"+byType);
Class iType = Integer.TYPE;
System.out.println("Integer:"+iType);
Class fType = Float.TYPE;
System.out.println("Float:"+fType);
Class dType = Double.TYPE;
System.out.println("Double:"+dType);

输出结果为:

Boolean:boolean

Byte:byte

Integer:int

Float:float

Double:double

获取到对象的构造函数

User  user = new User();
Class userClass = user.getClass();
Constructor[] constructors = userClass.getConstructors(); // 获取到它所有的构造函数
for (Constructor constructor:
     constructors) {
    /**
     *
会打印出所有构造函数
     * public Reflect.User(int,java.lang.String,java.lang.String,java.lang.String)
     * public Reflect.User()
     */
   
System.out.println("getConstructors:"+constructor);
}

后天打印输出内容为:

getConstructors:public Reflect.User()

getConstructors:public Reflect.User(int,java.lang.String,java.lang.String,java.lang.String)

 

上述代码中的getConstructors() 方法,可以获取到“所有”的构造函数,这里的所有并不是真正意义上的所有,而是所有的public类型的构造函数;什么意思?比如:User类中的构造函数:

private User(int id){
        this.id = id;
}

这个构造函数,我们就无法通过getConstructors 获取到,因为它是私有的;

如果我需要获取到该怎么办呢?

可以使用getDeclaredConstructors()方法,代码如下:

System.out.println("-------------------------获取到私有构造函数--------------------");
Constructor[] declaredConstructors = userClass.getDeclaredConstructors();
for (Constructor c:
declaredConstructors) {
    System.out.println("declaredConstructors:"+c);
}
System.out.println("-------------------------获取到私有构造函数--------------------");

代码结果如下:

-------------------------获取到私有构造函数--------------------

declaredConstructors:public Reflect.User()

declaredConstructors:private Reflect.User(int)

declaredConstructors:public Reflect.User(int,java.lang.String,java.lang.String,java.lang.String)

-------------------------获取到私有构造函数--------------------

 

如果我想获取到某一个构造函数:

---- 获取到无参构造函数:

final Constructor constructor = userClass.getConstructor();

---- 获取到带参构造函数:

Class[] p={int.class,String.class,String.class,String.class};
Constructor constructor1 = userClass.getConstructor(p);

---- 获取到私有构造函数

Constructor declaredConstructor =  userClass.getDeclaredConstructor(new Class[]{int.class});

如果我想获取到这个构造函数中,可以传递哪些类型的参数:

System.out.println("--------------------------获取到构造函数的类型-------------------------");

Class[] p={int.class,String.class,String.class,String.class};
Constructor constructor1 = userClass.getConstructor(p);


Class[] parameterTypes = constructor1.getParameterTypes();
for (Class c:
     parameterTypes) {
    System.out.println("构造函数类型:" + c.getName());
}
System.out.println("--------------------------获取到构造函数的类型-------------------------");

控制台输出内容为:

--------------------------获取到构造函数的类型-------------------------

构造函数类型:int

构造函数类型:java.lang.String

构造函数类型:java.lang.String

构造函数类型:java.lang.String

--------------------------获取到构造函数的类型-------------------------

 

我已经知道了如何获取到这个对象(或者说是类)的构造函数,我如何利用已经知道的构造函数:去创建对象呢?

User  user = new User();
Class userClass = user.getClass();

User user1 =(User) constructor1.newInstance(10, "11", "12", "13"); //实例化对象
System.out.println(user1.getName());

上面调用的是public 类型的构造函数,如果我想通过private 类型的构造函数创建对象,应该如何使用呢?

System.out.println("-------------------------通过私有构造函数创建对象-----------------------");
Constructor<User> declareClass =   userClass.getDeclaredConstructor(new  Class[]{int.class});
declareClass.setAccessible(true);//暴力破解,不建议使用
User user2 = declareClass.newInstance(15);
System.out.println("通过私有化构造函数创建对象:"+user2.getId());
System.out.println("-------------------------通过私有构造函数创建对象-----------------------");

虽然可以使用这种方式来通过private方法来创建对象,但是这样做,会破坏代码的私密性,毕竟人家设置私有构造函数并不是希望外界来做调用的;

后台输出:

-------------------------通过私有构造函数创建对象-----------------------

通过私有化构造函数创建对象:15

-------------------------通过私有构造函数创建对象-----------------------

 

获取对象的方法

System.out.println("-------------------------获取到所有方法--------------------");

User  user = new User();
Class userClass = user.getClass();
Method[] methods = userClass.getMethods();//获取到当前类中所有方法
for (Method m:
     methods) {
    System.out.println(m);
}
System.out.println("-------------------------获取到所有方法--------------------");

 

控制台输出:

-------------------------获取到所有方法--------------------

public java.lang.String Reflect.User.getName()

public int Reflect.User.getId()

public void Reflect.User.setName(java.lang.String)

public void Reflect.User.setSex(java.lang.String)

public void Reflect.User.setDescr(java.lang.String)

public java.lang.String Reflect.User.getDescr()

public void Reflect.User.setId(int)

public java.lang.String Reflect.User.getSex()

public final void java.lang.Object.wait() throws java.lang.InterruptedException

public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException

public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException

public boolean java.lang.Object.equals(java.lang.Object)

public java.lang.String java.lang.Object.toString()

public native int java.lang.Object.hashCode()

public final native java.lang.Class java.lang.Object.getClass()

public final native void java.lang.Object.notify()

public final native void java.lang.Object.notifyAll()

-------------------------获取到所有方法--------------------

 

我们可以看到,获取到的方法中,全部是public;因为Object类是所有类的父类,所以,获取到的方法中,也包含了父类中的public方法;这里测试了一下,如果我向User类中增加方法protected Object clone()方法,这个方法并不能获取到;所以这里的“所有”也并不是全部的方法;

@Override
protected Object clone() throws CloneNotSupportedException {
    return super.clone();
}

 

如果我想获取到所有的方法,应该怎么做呢?

System.out.println("-------------------------获取到方法(包括私有)--------------------");

User  user = new User();
Class userClass = user.getClass();
Method[] declaredMethods = userClass.getDeclaredMethods();//获取到所有方法
for (Method m:
declaredMethods) {
    System.out.println(m);
}
System.out.println("-------------------------获取到方法(包括私有)--------------------");

 

PS:有这样一个现象,从一个类中获取到所有的构造函数到获取到所有的方法,调用的方法中都包含有Declared字样,这里先简单的理解成,只要包含有这样的字段,就可以不受权限限制(public  private  protected 默认);随心所以的获取到指定的构造函数 属性  方法等;

 

如果我想获取到其中某一个方法,该如何做呢?

Method getName = userClass.getMethod("getName");
System.out.println("获取到无参函数:"+getName.getName());

如果我想获取到带参的方法,该如何做呢?

Method setNameAndSex = userClass.getMethod("setNameAndSex", String.class, String.class);
System.out.println("获取到带参的函数:" + setNameAndSex.getName());

如果我想获取私有函数的方法,该如何做呢?

Method setOtherId = userClass.getDeclaredMethod("setOtherId", int.class);
System.out.println("获取到私有函数:"+setOtherId);

现在,我已经知道如何获取函数,那么,如果我想调用已经获取到的函数,该如何做呢?

System.out.println("-------------------------调用对象的函数-----------------------");
Class userClass2 = User.class;
Constructor<User> userConstructor =  userClass2.getConstructor(); // 获取到对应的构造函数
User user4 = userConstructor.newInstance(); //通过函数初始化对象
Method setName = userClass2.getMethod("setName", String.class);// 获取到指定对象的函数
setName.invoke(user4,"zpy");
System.out.println("获取到设置的name:" +user4.getName());
System.out.println("-------------------------调用对象的函数-----------------------");

 

控制台输出内容为:

-------------------------调用对象的函数-----------------------

获取到设置的name:zpy

-------------------------调用对象的函数-----------------------

 

获取到对象的属性

System.out.println("-------------------------获取到类的所有属性-----------------------");

User  user = new User();
Class userClass = user.getClass();
Field[] fields = userClass.getFields(); // 只能获取到public 类型的字段
for (Field field:
fields) {
    System.out.println(field);
}
System.out.println("-------------------------获取到类的所有属性-----------------------");

控制台输出:

public java.lang.String Reflect.User.descr

 

和上面提到获取到所有构造函数 和 所有函数的方式一样,只能获取到public类型的属性,如果我想获取到所有的属性,那么我该如何去做呢?

System.out.println("-------------------------获取到类的所有属性(包含私有)-----------------------");
Field[] declaredFields = userClass.getDeclaredFields();
for (Field field:
declaredFields) {
    System.out.println("获取到当前字段:"+field);
}
System.out.println("-------------------------获取到类的所有属性(包含私有)-----------------------");

控制台输出为:

-------------------------获取到类的所有属性(包含私有)-----------------------

获取到当前字段:private int Reflect.User.id

获取到当前字段:private java.lang.String Reflect.User.name

获取到当前字段:private java.lang.String Reflect.User.sex

获取到当前字段:public java.lang.String Reflect.User.descr

-------------------------获取到类的所有属性(包含私有)-----------------------

 

现在,我已经能够获取到对应的属性,现在如果我想针对获取到树形赋值,该如何做呢?

User  user = new User();
Class userClass = user.getClass();

Field name1 = userClass.getDeclaredField("name");
name1.setAccessible(true);
name1.set(user,"234");
System.out.println(user.getName());

控制台输出内容为:

234

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VogtZhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值