Java就业-反射技术

前言

反射可以说是Java中最强大的技术之一了,很多框架都是基于反射来实现的,反射可以动态获取任意一个类的方法或属性,是不是听起来就厉害!

一、获取class对象

首先我们来认识一下java.lang.Class这个类,这个类没有公共构造方法,该类的实例由虚拟机和类加载器自动构造完成,那我们怎么获取class对象呢?

1.1 类名.class

通过类名.class的方式获得该类的class对象

Class c = Student.class;

1.2 getClass方式

Object类中有一个getClass()方法,而所有类都是Object子类,天然的继承了该方法

Student student = new Student();
Class c = student.getClass();

需要注意的是,基本数据类型不是对象,因此不能通过int.getClass()这种方式获取class对象,需要用到它的包装类,包装类的TYPE属性可以获取基本数据类型的class对象

Class c = Integer.TYPE;

1.3 Class.forName()

直接传入包名.类名,就可以获取该类的对象

Class.forName("com.lagou.Student");

通过以上三种方式均可以获得class对象,不同的是第一种方式需要导入对应类的包,第二种方式则先要获取到类的实例才行,而我们一般用到反射都是为了创建实例,因此常用的是第三种方式,快捷灵活。

二、获取方法

有了该类的class对象,我们就能对该类为所欲为了,包括私有函数、私有变量,通通都能访问!你就是这个世界的老大!

2.1 获取构造函数

获取构造函数,需要用到class对象的getConstructor()方法
首先我们来定义一个Student类

public class Student {
    private String name;
    private String sex;
    private String birth;

    public Student() {

    }

    public Student(String name,String sex,String birth) {
        this.name = name;
        this.birth = birth;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

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

    private String getBirth() {
        return birth;
    }

    private void setBirth(String birth) {
        this.birth = birth;
    }
}

我们来获取一下无参构造函数

Class c = Class.forName("Student");
Constructor constructor = c.getConstructor();

获取有参构造函数时,需要传递参数的类型.class

Class c = Class.forName("Student");
Constructor constructor = c.getConstructor(String.class,String.class,String.class);

获取所有构造函数

Class c = Class.forName("Student");
Constructor[] constructor = c.getConstructors();

2.2 获取普通函数

通过class的method()方法,我们可以获取到类的普通对象
先来获取无参函数:

Method m = c.getDeclaredMethod("getName");
System.out.println(m);   // 输出public java.lang.String Student.getName()

再来获取一个有参函数:

Method m = c.getDeclaredMethod("getName");
System.out.println(m);   // 输出public void Student.setName(java.lang.String)

如果想要获得私有函数呢?

Method m = c.getDeclaredMethod("setBirth", String.class);
System.out.println(m);

看来getDeclaredMethod()这个方法私有公有都可以获得呀!太万能了!
同理,获得私有构造函数也可以用getDeclaredConstructor()方法,认准Declared,什么方法都能访问!

三、获取变量

除了获得构造方法,我们还可以获取变量

Field name = c.getDeclaredField("name");
System.out.println(name);    // 输出:private java.lang.String Student.name

通过输出我们可以发现,私有变量获取到了!神不神奇!
getDeclaredFields()方法,可以获取到所有变量,和获得方法一样,无脑Declared

Field[] name = c.getDeclaredFields("name");

想要什么,遍历就完了!

四、获取其他信息

仍然是class对象中的方法,如下表所示,比较简单,就不做过多演示了

作用方法名
获取包名getPackage()
获取父类getSuperClass()
获取接口getInterfaces()
获取注解getAnnotations()
获取泛型getGenericInterfaces()

五、获取对象实例

我们得到了class对象,不能光是看看都有哪些方法吧,肯定需要调用的呀,而调用首先就要用到实例,来看一下如何通过反射获得对象实例吧!

Class c = Class.forName("Student");
Constructor declaredConstructor = c.getDeclaredConstructor();
Student student = (Student) declaredConstructor.newInstance();
student.setName("12");
System.out.println(student.getName());  // 12

看,就是这么轻松加easy!

那如果想要调用私用方法getBirth()呢?用student.私有方法是不可能的,这就需要用到下面的知识了

六、获取Method

method眼熟呀,刚才在前面不还见到了,通过class对象的getDeclaredMethod()方法就可以访问到私有方法了,但是访问归访问,如何调用呢?

// 获得class对象
Class c = Class.forName("Student");
// 获得构造函数
Constructor declaredConstructor = c.getDeclaredConstructor(String.class, String.class, String.class);
// 通过构造函数获得对象实例
Object o = declaredConstructor.newInstance("张三", "女", "1995年1月1日");
// 获得私有方法
Method getBirth = c.getDeclaredMethod("getBirth");
// 设置访问权限为true,即可以访问
getBirth.setAccessible(true);
System.out.println(getBirth.invoke(o));   // 输出1995年1月1日

如果调用的私用方法需要传递参数呢?

// 获得class对象
Class c = Class.forName("Student");
// 获得构造函数
Constructor declaredConstructor = c.getDeclaredConstructor(String.class, String.class, String.class);
// 通过构造函数获得对象实例
Object o = declaredConstructor.newInstance("张三", "女", "1995年1月1日");
// 获得私有方法,该私有方法有一个String类型的参数
Method setBirth = c.getDeclaredMethod("setBirth",String.class);
// 设置访问权限为true,即可以访问
setBirth.setAccessible(true);
// 调用方法并传递string类型的参数
setBirth.invoke(o,"1996年12月12日");

Method getBirth = c.getDeclaredMethod("getBirth");
getBirth.setAccessible(true);
System.out.println(getBirth.invoke(o));  // 输出为1996年12月12日,证明setBirth方法生效了!

至此,反射的主要内容都说完了!毕竟我们最主要的就是用反射来动态的创建对象并调用方法嘛,套路就是这么个套路,学会了吗?

七、总结

如果阅读API文档,以及前面所写,会发现class对象中有这么几个方法:

  1. getMethod();
  2. getMethods();
  3. getDeclaredMethod();
  4. getDeclaredMethods();

getMethod()只能返回当前类及所有继承的父类的public修饰的方法。仅包括public,而
getDeclaredMethod()可以获得当前类的所有方法,因此私有的就也能访问到啦,但是要注意,它不能获得父类的方法哦!
复数的方法就不用说了,那自然是获得所有方法了,返回的是一个数组列表。

虽说反射大法好,但还是有一定弊端的:

  • 破坏了程序的安全性,连private都能访问,还有什么隐私可言啊喂!
  • 反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。

因此反射虽好,可不要乱用哦!如果一个功能可以不用反射完成,那么最好就不用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值