Java复习——核心机制之反射

反射

能够分析类能力的程序称之为反射
反射机制可以用来:

  1. 在运行时分析类的能力
  2. 在运行时查看对象
  3. 实现通用的数组操作代码
  4. 利用Method对象

Class类
在程序运行期间,Java 运行时系统始终为所有的对象维护一个被称为运行时的类型标识 。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行 。
然而,可以通过专门的 Java 类访问这些信息。保存这些信息的类被称为Class,这个名字很容易让人混淆 。Object 类中的 getClass ( ) 方法将会返回一个 Class 类型的实例 。

Instances of the class {@code Class} represent classes and
interfaces in a running Java application.

Class类的描述
Class类是一个用来表示运行中的类或者接口

/* 
	 * Returns the runtime class of this {@code Object}. The returned
     * {@code Class} object is the object that is locked by {@code
     * static synchronized} methods of the represented class.
*/
public final native Class<?> getClass();

三种Class类获取的方式
作为演示,先设置了一个Student类

public class Student {
    private String name;
    private int age;
	public Student(){}
	public Student(String name,int age){...}
	Getter and Setter...
	toString()...
}

第一种获取方式:

Student stu = new Student();
Class cl1 = stu.getClass();
System.out.println(cl1.getName());

输出结果:(如果类在一个包里,包的名字也会作为类名的一部分)

Day10.ReflectReview.Student

第二种则是调用静态方法获取类名对应的Class对象

try{
    String className = "java.util.Arrays";
    Class cl2 = Class.forName(className);
    System.out.println(cl2.getName());
	}

输出结果:

java.util.Arrays

值得注意的时,这种方法只能在className是一个类名或者接口名才能够执行,否则将会抛出一个checked exception异常。所以无论何时使用该方式,都应该加上异常处理器。

第三种
如果T是任意Java类型,直接用T.class获取

Class cl3 = Math.class;
Class cl4 = int.class;
System.out.println(cl3.getName());
System.out.println(cl4.getName());

输出结果:

java.lang.Math
int

Class的对象表示的是一种类型,这种类型不一定是一个类。比如int是一个基本类型,而不是一个类,而int.class是一个Class类型的对象

反射的核心作用:检查类的结构
Java.lang.reflect包中,有三个类:Field,Constructor,Method分别用来描述一个类的域、构造器和方法。
这三个类都有一个getName()方法,用来返回项目名称。

public String getName() {
        return name;
 }

Field有一个getType()方法,用来返回域的类型的一个类对象。

public Class<?> getType() {
        return type;
}

Method也有报告返回类型、参数类型、、参数数量、异常类型的方法。

public Class<?> getReturnType() {
        return returnType;
}
public Class<?>[] getParameterTypes() {
        return parameterTypes.clone();
}
public int getParameterCount() {
 		return parameterTypes.length;
}
public Class<?>[] getExceptionTypes() {
        return exceptionTypes.clone();
}

Constructor也有参数类型和异常类型

而这三个类还有一个getModifiers()方法,返回一个整数类型来描述修饰符状况
另外,在reflect包中,还有个Modifier类,用来判断修饰符,下面列举几个比较常用的修饰符

public static boolean isPublic(int mod) {
        return (mod & PUBLIC) != 0;
}
public static boolean isPrivate(int mod) {
        return (mod & PRIVATE) != 0;
}
public static boolean isProtected(int mod) {
        return (mod & PROTECTED) != 0;
}
public static boolean isStatic(int mod) {
        return (mod & STATIC) != 0;
}
public static boolean isFinal(int mod) {
        return (mod & FINAL) != 0;
}
......

下面来尝试使用Class类对象
分别获取Field、Constructor、Method

需要注意的是:
Class类中的getFields、getMethods 和 getConstructors方法将分别返回类提供的public 域、方法和构造器数组,其中包括超类的公有成员。
Class类的getDeclareFields、getDeclareMethods和getDeclaredConstructors方法将分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护成员,但不包括超类的成员 。
如果单独调用某一个Field、Constructor、Method,可以用

public Field getField(String name)
public Constructor<T> getConstructor(Class<?>... parameterTypes)
public Method getMethod(String name, Class<?>... parameterTypes)

方法,不过需要注意对应的参数

我们把所有的域、构造器和方法都打印出来看看

Class cl1 = stu.getClass();
Field[] declaredFields = cl1.getDeclaredFields();
Constructor[] declaredConstructors = cl1.getDeclaredConstructors();
Method[] declaredMethods = cl1.getDeclaredMethods();

结果:

private java.lang.String Day10.ReflectReview.Student.name
private int Day10.ReflectReview.Student.age
//上面是域
public Day10.ReflectReview.Student()
public Day10.ReflectReview.Student(java.lang.String,int)
//这里是两个构造方法
//下面是Getter和Setter方法和一个toString方法
public java.lang.String Day10.ReflectReview.Student.toString()
public java.lang.String Day10.ReflectReview.Student.getName()
public void Day10.ReflectReview.Student.setName(java.lang.String)
public int Day10.ReflectReview.Student.getAge()
public void Day10.ReflectReview.Student.setAge(int)

可以看到,输出了Student类的所有信息,域的修饰符,返回类型,全域名,以及包括了所有构造器和方法的签名

接下来我们运用反射机制查看编译时对象的域

try{
            Student stu = new Student("张三",23);
            Class cl1 = stu.getClass();
            Field f = cl1.getDeclaredField("name");
//            f.setAccessible(true);
            Object o = f.get(stu);
            System.out.println(o.toString());

}

因为name是一个私有域,所以调用get方法会抛出一个IllegalAccessException异常
然后发现还是得不到值,这时就需要把注释解开

public void setAccessible(boolean flag)

setAccessible是AccessIbleObject的一个方法,
作用是将此对象的accessible标志设置为指示的布尔值。 true的值表示反射对象应该在使用时抑制Java语言访问检查。 false的值表示反映的对象应该强制执行Java语言访问检查。

AccessIbleObject是Field、Constructor、Method的公共超类,它提供了将反射对象标记为在使用它时抑制默认Java语言访问控制检查的功能

这时我们就能的取出stu这个对象的,name域中的值

张三

既然能取出,也就能改变
我们使用Field类中的set方法
在上面的代码后面添加上如下代码

System.out.println(stu.toString());//修改前打印信息
f.set(stu,"法外狂徒张三");
System.out.println(stu.toString());//修改后打印信息

执行后:

Student{name='张三', age=23}
Student{name='法外狂徒张三', age=23}

关于反射的内容就复习到这里,后续如果有补充,就再加上

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值