沈阳市建设工程项目管理中心网站,网络项目网,wordpress网站欣赏,揭阳百度关键词优化Field类Field类中定义了一些方法#xff0c;可以用来查询字段的类型以及设置或读取字段的值。将这些方法与继承而来的member方法结合在一起.就可以使我们能够找出有关字段声明的全部信息#xff0c;并且能够操纵某个特定对象或类的字段。getGenericType方法返回表示字段的声明…Field类Field类中定义了一些方法可以用来查询字段的类型以及设置或读取字段的值。将这些方法与继承而来的member方法结合在一起.就可以使我们能够找出有关字段声明的全部信息并且能够操纵某个特定对象或类的字段。getGenericType方法返回表示字段的声明类型的Type实例。对于像String或int这样的平凡类型该方法将返回与其相关联的Class对象例如String.class和int.classo对于像List Stri ng这样的参数化类型该方法将返回Parameterizedrype的实例例如对像T这样的类型该方法将返回Typevariable实例。遗留下来的getType方法将返回字段的类型的Class对象。对于平凡类型该方法的行为与getGenericType方法的相同。如果字段的声明类型是参数化类型那么getType方法将返回参数化类型的擦除所对应的Class对象即原始类型的Class对象。例如对于声明为List Stri ng的对象getType将返回Li St. class的。如果字段的声明类型是类型变量那么getType方法将返回类型变量的擦除所对应的class对象。例如假设有一个类FOO对于其声明为T类型的字段get丁ype将返回object.class对象。如果FOO被声明为FOo那么get下ype将返回 Number.class.我们可以使用isEnumConstant方法查询一个字段是否是枚举常量也可以使用get和set方法来获取和设置字段的值。这些接受object引元并返回Obj ect值的方法都有一种通用形式以及一些可以直接处理基本类型的更加特化的形式。所有这些方法都要接受一个引元用来指定所要操作的对象。对于静态字段将忽略这个对象引元所以此时也可以将其设置为null。下面的方法将打印一个对象的short型字段的值:public static void printShortField(Object o, String name)throws NoSuchFieldExceptionIllegalAccessException{Field fieldo.getClass().getField(name);short value(Short) field.get(o);System.out.println(value);get方法的返回值可以是这个字段所引用的任何对象如果该字段是基本类型那么该方法将返回恰当类型的包装器类对象。对于我们的”hort型字段get方法将返回包含该字段值的short类型的对象而在将它赋值给本地变量value时该对象值会自动进行拆箱转换。set方法的使用也是类似的。将short型字段设置为所提供的值的方法看起来可能像下面这样:public static voisetShortField(Object oString nameshort nv)throws NoSuchFieldExceptionIllegalAccessExceptionField field0.getClass().getField(name);field .set(o .nv);虽然set接受的是Object类型的参数但是我们可以直接传递一个short型的值并用包装转换将其包装为short类型的对象。在上面的方法中如果指定对象的域是不可访问的并且这种访问权限控制是强制执行的那么就会抛出IllegalACcessException异常;如果传递的对象与该域的类型不同就会抛出illegalArgumentException异常;如果该域是非静态的且传递的对象引用是null就会抛出NullPointerException异常;访问静态域可能会要求对类进行初始化所以该方法也会抛出ExceptionInInitializerError异常。Field类还有特定的用来获取和设置基本类型的方法例如我们可以在Field对象上调用getPrimitive7ype和set Primitive7ype其中Primitive7ype是(首字母大写的)基本类型名。get方法可用于下面的语句:short valuefield.getshort(o);而set方法可用于下面的语句:field.setshort(o, nv);用以上两种方式声明的语句中可以避免使用包装器类对象。Field类实现了AnnotatedElement接口所以我们也可以像16.2节那样查询应用于域上的注解。凭借上面介绍的方法我们可以将Field对象用作操纵任意值的一种方式但是我们应该尽量避免使用它。因为Java语言会在程序的编译期尽可能多地捕获编程错误所以在我们编写代码时使用的诸如「ield对象这样的间接方法越少那么在将它们编译成代码之前就可以防止更多的错误。而且我们可以看到在前面的代码中要想知道到底会发生什么与在普通的语法中直接使用域名的情况相比我们花费在阅读代码上的精力显然大了许多。Final字段在通常情况下对声明为final的字段进行设置将会导致抛出IllegalACcessException异常这是我们所能预期的因为final字段的值是永远不会改变的。但是有些特殊情况—例如在定制的反序列化(见20.8.4节)中改变final字段的值就是有意义的我们只有在实例字段上才能通过反射实现这一点并且前提是在该Field对象上已经调用过了setAccessible(true)。注意可以成功调用setAccessible(true)是不够的必须确实调用过它。这种能力是为高度特化的上下文提供的并非用于通用目的我们介绍它仅仅是为了保持内容的完整性。如果脱离了特定的上下文例如定制的反序列化那么改变final字段的值可能会导致意外的甚至是灾难性的后果。在这些上下文之外不能保证对final字段的改变是可见的。即便是在这样的上下文中在使用这项技术编码时也必须保证安全机制不会阻碍代码的执行。改变值为常量变量(见2.2.3节)的final字段将会导致此改变不可见除非通过使用反射来实现这种修改。Method类method类和它从member类继承而来的方法使得我们可以获得方法声明的完整信息: public Type getGenericReturnTypeO:该方法返回的是目标方法的返回类型的Type对象。如果目标方法被声明为返回void则该方法返回void.classo public Type[] getGenericParameterTypes():该方法返回目标方法所有参数类型的Type对象数组这些Type对象将按照参数的声明顺序存储于在数组中。如果目标方法没有任何参数则该方法返回一个空数组。.publ i c Type [] getGeneri caccepti onTypes Q:该方法返回在throws子句中列出的所有异常类型的Type对象数组这些Type对象将按照异常的声明顺序存储在数组中。如果目标方法没有声明任何异常则该方法返回一个空数组。Java还提供了getReturnType,getParameterTypes和getExceptionTypes方法用来返回Cl as”对象而不是Type对象。就像在使用Field.getType时参数化类型和类型变量是由它们的擦除所对应的Class对象表示的。method类实现了AnnotatedElement并且我们可以像16.2节所讨论的那样去查询应用于方法上的注解。另外Method类还提供了getParameterAnnotations用来提供对应用于方法参数上的注解进行访问。getParameterAnnotations方法可以返回Annotation数组其中最外层数组的每一个元素都与方法的参数相对应;如果某个参数没有任何注解则该方法为这个参数返回一个长度为0的Annotation数组。如果method对象所表示的方法自身就是一个注解元素那么getDefaultvalue方法将返回一个表示该元素默认值的Object对象;如果method对象本身不是注解元素或者它没有默认值则该方法将返回null.Method类也实现了GenericDeclaration因此定义了getTypeParameters方法该方法将返回一个Typevariable对象数组。如果给定的method对象表示的不是泛型方法该方法将返回一个空数组。我们可以使用isvarArgs方法来检查某个method对象是否是一个可变引元方法而i sBridge方法可以用来检查它是否是一个桥接方法Method对象最有趣的用法就是反射地调用它自己:.public object invoke(object onThisobject…args)throws IllegalACcessExceptionIllegalArgumentException工nvocation下argetException:该方法在onThis对象上调用method对象定义的方法并用args的值来设置被调用方法的参数。对于非静态方法onThis的实际类型就确定了将要调用方法的哪种实现而对于静态方法onThis会被忽略并且通常会设置为null. args值的数量必须和被调用方法的实际参数数量相同并且这些值的类型必须全部都可赋值给那些被调用方法的参数;否则我们将会得到工llegalArgumentException异常。请注意可变引元方法的最后一个参数是一个数组所以我们必须用实际想要传递的“可变”引元来填充该数组。如果我们想调用我们没有访问权限的方法该方法就会抛出IllegalACcessException异常。如果被调用方法不是on下his对象的方法该方法会抛出工llegalArgumentExcepti on异常。如果onThis为null并且是非静态的该方法就会抛出NO 1PointerException异常。如果这个 method对象表示的是静态方法并且声明这个静态方法的类仍处于待初始化状态该方法就会抛出ExceptionIn工nitializerError异常。如果被调用法出异幂谈万法就会抛出InvocationTargetException异常。当我们使用invoke方法时可以直接传递基本类型也可以使用合适的包装器类。包装器类表示的类型必须可赋值给方法所声明的参数类型。我们可以使用Long,Float或Double来包装double类型的引元但是不能用Double来包装long或float类型的引元因为double不是可赋值给long或们oat的。对invoke方法返回的object的处理方法和Field.get一样都是返回对应于它们的包装器类的基本类型。如果方法声明为void, invoke方法将返回null,简单地说就是我们在用invoke来调用方法时只能使用在Java语言中合法的与其参数具有相同类型和值的引元。例如下面的调用return str.indexof(.”8);可以用反射写成如下形式:Throwable fa们ure;try{Method indexMString.class.getMethod(index0fString.classint.class);return (Integer) indexM.invoke(str,””8);}catch (NoSuchMethodException e){failuree;}catch (InvocationTargetException e){fa们uree .getCause();}catch (IllegalAccessException e){failuree;}throw fa们ure;虽然编译器对于直接调用所做的安全性检查在使用反射的情况下只能在运行时使用invoke时进行但是基于反射的代码确实拥有与直接调用的代码在语义上等效的安全性检查。访问权限检查可能会以略为不同的方式执行—安全管理器可能会拒绝访问我们的包中的某个方法即使我们可以直接调用该方法。当我们可以使用这种形式的调用时我们有充分的理由去避免它。但是如果我们在编写调试器或其他需要将用户输入解释为对对象操作的泛型应用时使用invoke或get/set方法就会显得很合理。method对象在某种程度上可以当作类似其他语言中的方法指针来使用但是我们有更好的工具尤其是接口、抽象类和嵌套类可以用来处理那些通常在其他语言中用方法指针解决的问题。