java核心技术卷1::反射机制

反射

在程序运行期间发现更多的类及其属性的能力,能够分析类能力的程序称为反射,便于编写能够动态操纵 java 代码的程序。特别是在设计或运行中添加新类时,能够快速地应用开发工具动态的查询新添类的能力
反射机制作用:
  • 在运行时分析类的能力
  • 在运行时查看对象
  • 实现通用的数组操作代码
  • 利用 Method 对象,类似函数指针

Class 类

<Class> e;
Class cl = e.getClass();//获取 Class 类型实例,Class 对象表示一个特定类的属性。
e.getClass().getName();//返回类的名字。
//如果类名保存在字符串中,并可在运行中改变,就可以使用这个方法。
//异常处理器,必须提供。
try{
Class c2 = Class.forName(className);//静态方法,获取类名对应的 Class 对象
}catch(Exception e){
    e.printStackTrace();// 将 Throwable 对象和栈的轨迹输出到标准错误流
}
如果T是任意的java类型(或void关键字),T.class 将代表匹配的类对象。
Class cl3 = Random.class;
一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类。
if(e.getClass() == Employee.class); // == 比较两个类对象。
e.getClass().newInstance(); // 动态创建类实例,调用默认的构造器(无参)。
Object m = Class.forName("Employee").newInstance(); //根据存储在字符串中的类名创建一个类

捕获异常

抛出异常比终止程序灵活的多,这是因为可以提供一个“捕获”异常的处理器(handle)对异常情况进行处理
异常有两种类型:
  • 已检查类型(会检查是否提供了处理器)
  • 未检查类型(不会检查是否提供了处理器,需要精心编写代码避免错误发生)

利用反射分析类的能力

reflect 包中有三个类 Field、Method 和 Constructor 分别用于描述类的域、方法和构造器。
  • Field 类有一个 getType 方法,用来返回描述域所属类型的 class 对象。
  • Method 和 Constructor 类有能够报告参数类型的方法。
  • Method 类还有一个可以报告返回类型的方法。
  • 三个类中还有一个 getModifiers 它将返回一个整型数值,用不同的位开关描述 public 和 static 这样的修饰符使用状况。
  • Modifier 类的静态方法分析 getModifiers 返回的整型数值。
  • Modifier.toString 方法将修饰符打印出来。
  • Class 类中的 getFields、getMethods 和 getConstructors 方法将分别返回类提供的 public域、方法和构造器数组,其中包括超类的公有成员。
  • Class 类的 getDeclareFields、getDeclareMethods 和 getDeclaredConstructors 方法将分别返回类中的全部域、方法和构造器,其中包括私有和受保护的成员,但不包括超类成员。

在运行时使用反射分析对象

如果 f 是一个 Field 类型的对象(如,通过 getDeclaredFields 得到的对象),obj 是某个包含 f 域的类的对象,f.get(obj) 将返回一个对象,其值为obj域的当前值。
反射机制的默认行为受限于 Java 的访问控制。如果 f 是一个私有域,所以 get 方法将会跑出一个 IllegalAccessException。只有利用 get 方法才能得到可访问域的值。除非拥有访问权限,否则 Java 安全机制只允许查看任意对象有哪些域,而不允许读取他们的值。
  • setAccessible(true);能够覆盖访问控制。这个特性是为调试、持久存储和相似机制提供的。
  • 面对数值类型,使用 get 方法时,反射机制将会自动地将这个域值打包到相应的对象包装器中。
  • f.set(obj, value)可以将 obj 对象的 f 域设置成新值。
  • OnjectAnalyzer 将记录已经被访问过的对象以防止无限递归。

使用反射编写泛型数组代码

在编写一个通用的动态数组创建方法时,会遇到原数组无法copy元素至创建的 Object 类型数组里。
这是因为一个子类数组能够临时转换成父类数组,然后再转换回来也可以。而一个一开始就是父类的数组不能转换成子类数组。如果这样做,则在运行时 java 会产生 ClassCastException 异常。
  • Object newArray = Array.newInstance(componentType, newLength);通过Array类的静态方法构造新数组。需要提供元素类型和数组长度
  • Array 元素类型获取:
    • 首先获得 a 数组的类对象。
    • 确认它是一个数组。
    • 使用 Class 类(只能定义表示数组的类对象)的 getComponentType 方法确定数组对应的类型。
// this method can use for the type at will of array.
public static Object CopyOf(Object a, int newLength){
    Class cl = a.getClass();
    if(!cl.isArray()) return null;
    Class componentType = cl.getComponentType();
    int length = Array.getLength(a);
    Object newArray = Array.newInstance(componentType, newLength);
    System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength));
    return newArray;
}

调用任意方法

仅建议在有必要的时候使用,建议使用接口或 lambda
  • 获得方法
// 需要提供参数类型
Method m1 = <Object>.class.getMethod(<MethodName>);
Method m2 = <Object>.class.getDeclaredMethod(<MethodName>);
  • 调用方法
<Type> M1Go = (TypeName) m1.invoke(<obj>, <Obj_Arg>);

反射与泛型

反射允许你在运行时分析任意的对象。如果对象是泛型类的实例,关于泛型类型参数则得不到太多信息,因为它们会被擦除

泛型 Class 类

Class类是泛型的。String.class 实际上是一个 Class 类的对象(唯一)。

使用 Class 参数进行类型匹配

// 匹配泛型方法中的 Class<T> 参数的类型变量很有使用价值。
public static <T> Pair<T> makePair(Class<T> c) throws InstantiationException,IllegalAccessException
{
	return new Pair<>(c.newInstance(), c.newInstance());
}
// Employee.class 是类型 Class<Employee> 的一个对象。makePair 方法的类型参数 T 同 Employee 匹配,并且编译器可以推断出这个方法将返回一个 Pair<Employee>。

虚拟器中的泛型类型信息

Java 泛型的卓越特性之一是在虚拟机中泛型类型的擦除。但擦除的类依旧保留泛型祖先的微弱记忆。
// 原始类 pubilc static <T extends Comparable<? super T>> T min(T[] a)
public static Comparable min(Comparable[] a) // 擦除类
反射 API 能够确定:
  • 这个泛型方法有一个叫做 T 的类型参数。
  • 这个类型参数有一个子类型限定,其自身又是一个泛型类型。
  • 这个限定类型有一个通配符参数。
  • 这个通配符参数有一个超类型限定。
  • 这个泛型方法有一个泛型数组参数。
需要重新构造实现者声明的泛型类以及方法中的所有方法。但是,对于特定的对象或方法调用,如何解释类型参数。
为表达泛型类型声明,使用 java.lang.reflect 包中提供的接口 Type。这个接口包含下列子类型:
  • Class 类,描述具体类型。
  • TypeVariable 接口,描述类型变量(如 T extends Comparable<? super T>)。
  • WildcardType 接口,描述通配符(如 ? super T)。
  • ParameterizedType 接口,描述泛型类或接口类型(如 Comparable<? super T>)。
  • GeneticArrayType 接口,描述泛型数组(如 T[])。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值