Java基础-反射的基本使用

Java反射机制概述

Java中的反射机制允许程序在JVM的运行期动态加载类,创建类对象,调用类的成员变量,执行类的成员方法。

通过Java的反射机制可以下面的功能

  1. 在运行时判断任意一个对象所属的类;
  2. 在运行时构造任意一个类的对象;
  3. 在运行时判断任意一个类所具有的成员变量和方法;
  4. 在运行时修改任意一个对象的成员变量;
  5. 在运行时调用任意一个对象的方法;
  6. Java的反射机制可以临时修改类、类的成员变量、类的方法的访问属性。

Java的反射机制主要用于框架开发方面,是一个高级工程师的必备技能。

Java中的反射框架

功能
java.lang.Class实例表示正在运行的 Java 应用程序中的类和接口
java.lang.reflect.Constructor提供关于类的单个构造方法的信息以及对它的访问权限
java.lang.reflect.Field提供有关类或接口的单个字段的信息,以及对它的动态访问权限
java.lang.reflect.Method提供关于类或接口上单独某个方法(以及如何访问该方法)的信息

创建一个测试类

为了演示反射的使用,我创建一个名字为Book的类,表示一本图书,有两个成员变量保存书的名字和价格,可以通过构造方法、静态工厂方法创建类的实例,同时又一个静态变量表示创建类实例的数量。

package com.yumodev.java.entry;

/**
 * Created by yumodev
 * Book类,目前用于反射测试
 */
public class Book {
    /**
     * 书的名字
     */
    public String name = "";
    /**
     * 书的价格
     */
    private double price = 0.0;
    /**
     * 创建书的数量,静态变量
     */
    private static int count;

    /**
     * 默认构造方法
     */
    public Book(){
        count++;
    }

    /**
     * 构造方法
     * @param name
     * @param price
     */
    public Book(String name, double price) {
        this.name = name;
        this.price = price;
        count++;
    }

    /**
     * 通过静态工厂的创建Book实例
     * @param name
     * @param price
     * @return
     */
    public static Book newBook(String name, double price){
        Book book = new Book();
        book.name = name;
        book.price = price;
        count++;
        return book;
    }

    @Override
    public String toString() {
        return super.toString()+" "+name+" 价格:"+price;
    }

    /**
     * 获取价格
     * @return
     */
    public double getPrice() {
        return price;
    }

    /**
     * 设置新的价格
     * @param price
     */
    public void setPrice(double price) {
        this.price = price;
    }

    /**
     * 获取图书的数量。
     * @return
     */
    public static int getCount(){
        return count;
    }
}

Class类的使用

获取类对象

  • 通过类的名字直接调用
Class cls = Book.class
  • 通过类的实例创建类的对象
Book book = new Book();
Class cls = book.getClass();
  • 通过类的静态方法forName()创建类对象
Class.forName("com.yumodev.java.entry.Book")

获取类对象基础属性

通过Class cls = Book.class获取一个Class对象,通过这个Class对象来熟悉其一些属性的获取

  • 获取类的名称包括包名:
cls.getName();//输出:com.yumodev.java.entry.Book
  • 获取类的包名:
cls.getPackage();//输出:com.yumodev.java.entry
  • 获取类的名字,不包含包名
cls.getSimpleName();//输出:Book
  • 获取类的父类
cls.getSuperclass();//输出:java.lang.Object

类的签名

类的签名的获取有两种方式,一种利用Class类的方法,这种方法比较简单,只能用于获取类对象的签名,还有一种是使用反射框架下java.lang.reflect.Modifier类进行获取签名,它不仅可以获取类的签名,还可以获取成员变量、方法、构造方法的签名。Modifier类的主要方法如下:

方法名含义
static boolean isAbstract(int mod)是否为抽象类或者方法
static boolean isFinal(int mod)是否为Final类型的类、方法、成员变量
static boolean isInterface(int mod)判断类是否为接口
static boolean isNative(int mod)判断方法是否为本地方法
static boolean isPrivate(int mod)判断类、方法、成员变量是否为私有访问权限
static boolean isProtected(int mod)判断类、方法、成员变量是否为保护访问权限
static boolean isPublic(int mod)判断类、方法、成员变量是否为公开方法
static boolean isStatic(int mod)判断类、方法、成员变量是否为静态的。
static boolean isSynchronized(int mod)判断方法是否为同步方法。
static boolean isTransient(int mod)判断成员变量是否有transient声明
static boolean isVolatile(int mod)判断成员变量是否有volatile声明

这是一个获取类对象签名的演示:

int modifiers = cls.getModifiers();
Modifier.isAbstract(modifiers);//是否为抽象对象

类构造方法

遍历类的构造方法

通过Class类的getConstructors()方法可以获取其所有的构造方法

Class cls = Book.class;
Constructor[] constructors = cls.getConstructors();
for (Constructor constructor : constructors){
   System.out.println(constructor.toString());        
}

获取类对象的构造方法

通过Class类的 Constructor<T> getConstructor(Class... var1)来获取指定参数的构造方法。其参数为可变参数, 当要获取构造方法不存在的时候,会抛出NoSuchMethodException异常

下面的例子是获取Book类的public Book(String name, double price)构造方法.

Class cls = Book.class;
try {
    Constructor constructor = cls.getConstructor(String.class, double.class);
} catch (NoSuchMethodException e) {
    e.printStackTrace();
} 

通过构造方法生成类的实例

通过java.lang.reflect.Constructor类的public T newInstance(Object... var1)方法可以创建一个类的实例。

Class cls = Book.class;
try {
    Constructor constructor = cls.getConstructor(String.class, double.class);
    Book book = (Book) constructor.newInstance("《Java入门详解》", 990f);
    System.out.println("通过构造方法创建实例成功了:"+book.toString());
} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}

类的方法

遍历类的方法

通过Class类的getMethods()方法可以获取其所有的方法

Class cls = Book.class;
Methond[] methods = cls.getMethods();
for (Method method : methods){
   System.out.println(method.toString());        
}

查询类的方法

java.lang.reflect.Method类表示类的一个方法。
通过Class中的public Method getMethod(String var1, Class... var2)获取类中的一个方法。其中参数var1表示方法的名字, var2表示方法的参数列表,如果没有参数可以设置为null。用法如下:

Class cls = Book.class;
cls.getMethod("setPrice", double.class);//获取void setPrice(double)方法
cls.getMethod("getPrice", null);//获取double getPrice()方法。参数传入为null编译有警告,可以采用下面的方式实现
cls.getMethod("getPrice", new Class[0]);

执行类的方法

通过Method类的public Object invoke(Object var1, Object... var2)方法,可以执行一个类的方法。invoke()的方法依次传入类的实例、方法的参数列表的值。下面通过反射调用Book类的setPrice()修改图书的价格为例演示,如何反射获取方法并执行。

Book book = Book.newBook("《Book》", 10f);
Class cls = book.getClass();
try {
    Method method = cls.getMethod("setPrice", double.class);
    method.invoke(book, 20f);
    System.out.println(book.getPrice());
} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

执行静态方法

上面的例子演示如何反射执行类的一个普通的方法,如果是静态方法该如何执行呢。在回头看下Method类的invoke()方法的声明public Object invoke(Object var1, Object... var2),invoke()方法的第一次参数是传入类的实例的,如果传入null,就表示调用的该类对象的一个静态方法。下面的例子演示了反射调用Book类的newBook()方法生成一个实例。

Class cls = Book.class;
try {
    Method method = cls.getMethod("newBook", String.class, double.class);
    Book book = (Book) method.invoke(null, "《Book》", 20f);
    System.out.println(book.toString());
} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

类的成员变量

遍历类的成员变量

通过Class类的getDeclaredFields()方法可以获取其所有的字段,不包括其父类的成员变量。

Class cls = Book.class;
Field[] field = cls.getDeclaredFields();
for (Field method : fields){
   System.out.println(field.toString());        
}

获取一个类的成员变量

Class类提供了两个方法用于获取类的成员变量。

  1. getField(): 获取类的public类型的成员变量
  2. getDeclaredField():可以获取类的所有成员变量
Class cls = Book.class;
Field name = cls.getField("name");
Field price = cls.getDeclaredField("price");
Field count = cls.getDeclaredField("count");

获取和设置类的成员变量的值

Field类表示一个成员变量,其封装很多方法,用于获取和设置成员变量的值。其主要方法如下:

  1. public void set(Object var1, Object var2)
  2. public Object get(Object var1)
Book book = Book.newBook("《Book》", 10f);
Class cls = book.getClass();
try {
    Field name = cls.getField("name");
    name.set(book, "new book");
    System.out.println(book.getPrice());
} catch (NoSuchFieldException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

修改字段的访问权限

在本文中的Book类中有一个静态私有的count成员变量,如何通过反射修改其值呢。
首先因为是私有变量,所有只能通过Class类的getDeclaredField()方法获取该成员变量。
其次访问和修改私有变量前,需要设置该字段的访问权限。

Field、Method、Constructor类都继承自AccessibleObject。在AccessibleObject类中
有一个成员变量来设置类的成员变量、构造方法、方法的访问属性。

下面的例子演示的如果操作Book的静态私有count成员变量

Book book = Book.newBook("《Book》", 10f);
Class cls = book.getClass();
try {
    Field count = cls.getDeclaredField("count");
    //修改器访问属性
    count.setAccessible(true);
    count.set(null, 2);
} catch (NoSuchFieldException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

参考

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值