不懂java反射机制?

概念

Java 反射机制是 Java 语言的一个重要特性。在学习 Java 反射机制前,大家应该先了解两个概念,编译期和运行期。

编译期:是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。

运行期:是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。

百度百科:
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

个人理解:
Java反射机制可以视为一个输入流,将一个自定义的类,视为一个普通文件,我们可以得到该文件的所有信息,但又比输入流更加的高级,我们又可以执行该类中的功能点,简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的全限定名,就可以通过反射机制来获得类的所有信息

什么是静态语言什么是动态语言?

静态类型语言:变量定义时有类型声明的语言。

  1. 变量的类型在编译的时候确定
  2. 变量的类型在运行时不能修改

动态类型语言:变量定义时无类型声明的语言。

  1. 变量的类型在运行的时候确定
  2. 变量的类型在运行可以修改

如何实现java的语言动态化?

  1. 通过java的反射机制
  2. 多态,Java又可以通过接口等方式,在运行时注入相关的类的实现,所以这个又是其动态性的提现

如何使用java的反射机制

熟悉获取 Java 反射使用到类

  1. Class类
  2. Constructor 类
  3. Method 类
  4. Field 类
    Constructor,Method,Field 都是通过Class类得到的,在java.lang.reflect 包下

掌握Class类的常用方法

如何得到Class类对象?
1.众所周知,所有 Java 类均继承了 Object 类,在 Object 类中定义了一个 getClass() 方法,该方法返回同一个类型为 Class 的对象。
2.或者使用 Class类的静态方法forName(“全限定类名”)

类型访问方法返回值类型说明
包路径getPackage()Package 对象获取该类的存放路径
类名称getName()String 对象获取该类的名称
继承类getSuperclass()Class 对象获取该类继承的类
实现接口getlnterfaces()Class 型数组获取该类实现的所有接口
构造方法getConstructor()Constructor 对象实例获取权限为 public 的构造方法,包括,所继承的父类的构造
getConstructors()Constructor 型数组获取所有权限为 public 的构造方法
getDeclaredContruectors()Constructor 对象获取当前对象的所有构造方法
方法getMethods()Method 型数组获取权限为 public 的方法,包括父类
getDeclaredMethods()Method 对象数组获取当前对象的所有方法
getDeclaredMethod(String name, Class<?>… parameterTypes)Method对象获取本类指定的方法
成员变量getFields()Field 型数组获取所有权限为 public 的成员变量,包含父类
getDeclareFileds()Field 型数组获取当前对象的所有成员变量

Student类

package cn.entity;

public class Student {
    private String name;
    private Integer age;
    private Double score;
    public Student(){
        System.out.println("执行了Student的无参构造方法---------------->");
    }

    public Student(String name) {
        System.out.println("执行了Student的有参构造方法---------------->");
        this.name=name;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
        System.out.println("setAge-------------------->");
    }

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}

示例代码:

Class<?> cls = Class.forName("cn.entity.Student");
//得到Student类的构造器,此时并未创建实例
Constructor  constructor= cls.getDeclaredConstructor();
//得到Student类的所有方法,不包括父类
Method[] methods = cls.getDeclaredMethods()
//得到Student类的指定方法名的方法
Method getName = cls.getMethod("getName");
//得到Student类的指定属性名的属性
Field age = cls.getDeclaredField("age");

掌握 Constructor 类的常用方法

方法名称说明
isVarArgs()查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回false
getParameterTypes()按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型
getExceptionTypes()以 Class 数组的形式获取该构造方法可能抛出的异常类型
newInstance(Object … initargs)通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示采用默认无参的构造方法
setAccessiable(boolean flag)如果该构造方法的权限为 private,默认为不允许通过反射利用
newlnstance()方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对象
getModifiers()获得可以解析出该构造方法所采用修饰符的整数

示例代码:

 //此方法忽略构造方法的访问修饰符,不推荐使用,会破坏类的封装性,
constructor.setAccessible(true);
//此步是真正的创建一个实例,执行了类的无惨构造,当无惨构造为private时无法使用,需执行setAccessible(true);才能创建实例
Object obj = constructor.newInstance();

Method类的常用方法

静态方法名称说明
getName()获取该方法的名称
getParameterTypes()按照声明顺序以 Class 数组的形式返回该方法各个参数的类型
getReturnType()以 Class 对象的形式获得该方法的返回值类型
getExceptionTypes()以 Class 数组的形式获得该方法可能抛出的异常类型
invoke(Object obj,Object…args)利用 args 参数执行指定对象 obj 中的该方法,返回值为 Object 类型
isVarArgs()查看该方法是否允许带有可变数量的参数,如果允许返回 true,否则返回 false
getModifiers()获得可以解析出该方法所采用修饰符的整数

示例代码:

Method[] methods = cls.getDeclaredMethods();
//遍历所有本类方法
for (Method method : methods) {
	System.out.println(method);
}
//使用方法名,和指定参数类型,得到需要执行的方法,此时并未指定,只是得到该方法。参数类型,可根据对应的属性类型获取
Method setName = cls.getDeclaredMethod("setName", String.class);
/*此时才是真正的执行方法,"obj"为使用那一个对象,
来调用这个方法,“张三”为参数的值,
使用非反射的方式调用就是这种:((Student)obj).setName("张三")*/
setName.invoke(obj,"张三");

Field类的常用方法

方法名称说明
getName()获得该成员变量的名称
getType()获取表示该成员变量的 Class 对象
get(Object obj)获得指定对象 obj 中成员变量的值,返回值为 Object 类型
set(Object obj, Object value)将指定对象 obj 中成员变量的值设置为 value
getlnt(0bject obj)获得指定对象 obj 中成员类型为 int 的成员变量的值
setlnt(0bject obj, int i)将指定对象 obj 中成员变量的值设置为 i
setFloat(Object obj, float f)将指定对象 obj 中成员变量的值设置为 f
getBoolean(Object obj)获得指定对象 obj 中成员类型为 boolean 的成员变量的值
setBoolean(Object obj, boolean b)将指定对象 obj 中成员变量的值设置为 b
getFloat(Object obj)获得指定对象 obj 中成员类型为 float 的成员变量的值
setAccessible(boolean flag)此方法可以设置是否忽略权限直接访问 private 等私有权限的成员变量
getModifiers()获得可以解析出该方法所采用修饰符的整数

示例代码:

//得到本类所有属性并遍历输出
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
	System.out.println(method);
}
//得到指定名称的属性
Field age = cls.getDeclaredField("age");
 //此方法属性的访问修饰符,不推荐使用,会破坏类的封装性,
age.setAccessible(true);
//为obj的age属性赋值,常规写法,为:((Student)obj).age=18;age为私有的,无法调用
age.set(obj,18);

那么反射到底有什么用?

反射最主要还是运用在框架的设计中,了解了反射才更好的了解一些框架功能实现的原理。

我们所学的springmvc中的某些功能使用到的反射:

  1. 页面向controller中传值,的参数自动映射
    他的下一个博客
    使用反射自定义一个简易的参数自动映射.
  2. DispatchServlet(前端控制器)
    他的下一个博客
    使用反射自定义一个简易DispatchServlet

Java 反射机制的优缺点

优点

  • 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
  • 与 Java 动态编译相结合,可以实现无比强大的功能。
  • 对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

缺点

  • 一个主要的缺点是对性能有影响,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
  • 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。

总结:

使用java的反射机制,一般需要遵循三步:

  • 获得你想操作类的Class对象,使用全限定类名,“包名+类名””
  • 使用Class对象,得到构造,方法,属性,
  • 再使用具体的构造,方法,属性,来操作对应的方法,
  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值