Java学习day034 反射(一)Class类、捕获异常、利用反射分析类的能力

Orianna ·
更新时间:2024-09-20
· 550 次阅读

使用的教材是java核心技术卷1,我将跟着这本书的章节同时配合视频资源来进行学习基础java知识。

day034   反射(一)Class类、捕获异常、利用反射分析类的能力

反射库(reflection library)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵Java代码的程序。这项功能被大量地应用于JavaBeans中,它是Java组件的体系结构。使用反射,Java可以支持Visual Basic用户习惯使用的工具。特别是在设计或运行中添加新类时,能够快速地应用开发工具动态地查询新添加类的能力。

能够分析类能力的程序称为反射(reflective)。反射机制的功能极其强大,在下面可以看到,反射机制可以用来:

•在运行时分析类的能力。

•在运行时查看对象,例如,编写一个toString方法供所有类使用。

•实现通用的数组操作代码。

•利用Method对象,这个对象很像C++中的函数指针。

反射是一种功能强大且复杂的机制。使用它的主要人员是工具构造者,而不是应用程序员,如果仅对设计应用程序感兴趣,而对构造工具不感兴趣,可以跳过这部分,稍后再返回来学习。

1.Class类

在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。

然而,可以通过专门的Java类访问这些信息。保存这些信息的类被称为Class,这个名字很容易让人混淆。Object类中的getClass()方法将会返回一个Class类型的实例。

Employee e; ... Class cl=e.getClass();

如同用一个Employee对象表示一个特定的雇员属性一样,一个Class对象将表示一个特定类的属性。最常用的Class方法是getName。这个方法将返回类的名字。例如,下面这条语句:

System.out.println(e.getClass().getName()+""+e.getName());

如果e是一个雇员,则会打印输出:

Employee Harry Hacker

如果e是经理,则会打印输出:

Manager Harry Hacker

如果类在一个包里,包的名字也作为类名的一部分:

Random generator=new Random(); Class cl=generator.getClass(); String name=cl.getName(); //name is set to"java.util.Random"

还可以调用静态方法forName获得类名对应的Class对象。

String className="java.util.Random"; Class cl=Class.forName(className);

如果类名保存在字符串中,并可在运行中改变,就可以使用这个方法。当然,这个方法只有在dassName是类名或接口名时才能够执行。否则,forName方法将抛出一个checke dexception(已检查异常)。无论何时使用这个方法,都应该提供一个异常处理器(exception handler)。

获得Class类对象的第三种方法非常简单。如果T是任意的Java类型(或void关键字),T.class将代表匹配的类对象。例如:

Class cll=Random.class;//if you import java.util.*; class cl2=int.class; Class cl3=Doublet[].class;

请注意,一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类。例如,int不是类,但int.class是一个Class类型的对象。

虚拟机为每个类型管理一个Class对象。因此,可以利用=运算符实现两个类对象比较的操作。例如,

if(e.getClass()==Employee.class)...

还有一个很有用的方法newlnstance(),可以用来动态地创建一个类的实例例如,

e.getClass().newInstance();

创建了一个与e具有相同类类型的实例。newlnstance方法调用默认的构造器(没有参数的构造器)初始化新创建的对象。如果这个类没有默认的构造器,就会抛出一个异常.

将forName与newlnstance配合起来使用,可以根据存储在字符串中的类名创建一个对象

String s="java.util.Random"; Object m=Class.forName(s).newInstance(); 2.捕获异常

当程序运行过程中发生错误时,就会“抛出异常'。抛出异常比终止程序要灵活得多,这是因为可以提供一个“捕获”异常的处理器(handler)对异常情况进行处理。

如果没有提供处理器,程序就会终止,并在控制台上打印出一条信息,其中给出了异常的类型。可能在前面已经看到过一些异常报告,例如,偶然使用了null引用或者数组越界等。

异常有两种类型:未检查异常和已检查异常。对于已检查异常,编译器将会检查是否提供了处理器。然而,有很多常见的异常,例如,访问null引用,都属于未检查异常。编译器不会査看是否为这些错误提供了处理器。毕竟,应该精心地编写代码来避免这些错误的发生,而不要将精力花在编写异常处理器上。

并不是所有的错误都是可以避免的。如果竭尽全力还是发生了异常,编译器就要求提供一个处理器。Class.forName方法就是一个抛出已检查异常的例子。

将可能抛出已检査异常的一个或多个方法调用代码放在try块中,然后在catch子句中提供处理器代码。

try { statements that might throw exceptions } catch(Exception e) { handler action }

下面是一个示例:

try { String name=...;//get class name Class cl=Class.forName(name);//might throwe xception do something with cl } catch(Exceptione) { e.printStackTrace(); }

如果类名不存在,则将跳过try块中的剩余代码,程序直接进人catch子句(这里,利用Throwable类的printStackTrace方法打印出栈的轨迹。Throwable是Exception类的超类)。如果try块中没有抛出任何异常,那么会跳过catch子句的处理器代码。

对于已检查异常,只需要提供一个异常处理器。可以很容易地发现会抛出已检査异常的方法。如果调用了一个抛出已检查异常的方法,而又没有提供处理器,编译器就会给出错误报告。

3.利用反射分析类的能力

下面简要地介绍一下反射机制最重要的内容—检查类的结构。

在java.lang.reflect包中有三个类Field、Method和Constructor分别用于描述类的域、方法和构造器。这三个类都有一个叫做getName的方法,用来返回项目的名称。Held类有一个getType方法,用来返回描述域所属类型的Class对象。Method和Constructor类有能够报告参数类型的方法,Method类还有一个可以报告返回类型的方法。这三个类还有一个叫做getModifiers的方法,它将返回一个整型数值,用不同的位开关描述public和static这样的修饰符使用状况。另外,还可以利用java.lang.reflect包中的Modifier类的静态方法分析getModifiers返回的整型数值。例如,可以使用Modifier类中的isPublic、isPrivate或isFinal判断方法或构造器是否是public、private或final。我们需要做的全部工作就是调用Modifier类的相应方法,并对返回的整型数值进行分析,另外,还可以利用Modifier.toString方法将修饰符打印出来。

Class类中的getFields、getMethods和getConstructors方法将分别返回类提供的public域、方法和构造器数组,其中包括超类的公有成员。Class类的getDeclareFields、getDeclareMethods和getDeclaredConstructors方法将分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护成员,但不包括超类的成员。

下面的程序显示了如何打印一个类的全部信息的方法。这个程序将提醒用户输入类名,然后输出类中所有的方法和构造器的签名,以及全部域名。假如输入

java.lang.Double

程序将会输出:

public class java.lang.Double extends java.lang.Number { public java.lang.Double(java.lang.String); public java.1ang.Double(double); public int hashCode(); public int compareTo(java.1ang.Object); public int compareTo(java.lang.Double); public boolean equals(java.lang.Object); public java.lang.String toString(); public static java.lang.String toString(double); public static java.lang.Double valueOf(java.lang.String); public static boolean isNaN(double); public boolean isNaN(); public static boolean islnfinite(double); public boolean isInfinite(); public byte byteValue(); public short shortValue(); public int intValue(); public long longValueO; public float floatValueO; public double doubleValueO; public static double parseDouble(java.lang.String); public static native long doubleToLongBits(double); ublics tatic native long doubleToRawLongBits(double); public static native double 1ongBitsToDouble(long); public static final doublePOSITIVE_INFINITY; public static final doubleNECATIVEJNFINITY; public static final doubleNaN; public static final doubleMAX_VALUE; public static final doubleMIN_VALUE; public static final java.Iang.ClassTYPE; private doublevalue; privates taticfinallongserialVersionUID; }

值得注意的是:这个程序可以分析Java解释器能够加载的任何类,而不仅仅是编译程序时可以使用的类。

下面是程序代码:

/** *@author zzehao */ import java.util.*; import java.lang.reflect.*; public class ReflectionTest { public static void main(String[]args) { //read class name from command line args or user input String name; if(args.length>0) name=args[0]; else { Scanner in=new Scanner(System.in); System.out.println("Enter class name(e.g.java.util.Date):"); name=in.next(); } try { //print class name and super class name(if!=Object) Class cl=Class.forName(name); Class supercl=cl.getSuperclass(); String modifiers=Modifier.toString(cl.getModifiers()); if(modifiers.length()>0) System.out.print(modifiers+""); System.out.print("class"+name); if(supercl!=null&&supercl!=Object.class) System.out.print("extends"+supercl.getName()); System.out.print("\n{\n"); printConstructors(cl); System.out.println(); printMethods(cl); System.out.println(); printFields(cl); System.out.println("}"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.exit(0); } public static void printConstructors(Class cl) { Constructor[] constructors = cl.getDeclaredConstructors(); for (Constructor c : constructors) { String name = c.getName(); System.out.print(" "); String modifiers = Modifier.toString(c.getModifiers()); if (modifiers.length()> 0) System.out.print(modifiers+" "); System.out.print(name+"("); //print parameter types Class[] paramTypes= c.getParameterTypes(); for (int j = 0; j 0) System.out.print(","); System.out.print(paramTypes[j].getName()); } System.out.println(");"); } } public static void printMethods(Class cl) { Method[] methods=cl.getDeclaredMethods(); for (Method m : methods) { Class retType = m.getReturnType(); String name = m.getName(); System.out.print(" "); //print modifiers, return type and method name String modifiers = Modifier.toString(m.getModifiers()); if(modifiers.length()>0) System.out.print(modifiers+ " "); System.out.print(retType.getName()+" "+name+"("); //print parameter types Class[] paramTypes= m.getParameterTypes(); for (int j = 0; j 0) System.out.print(", "); System.out.print(paramTypes[j].getName()); } System.out.println(");"); } } public static void printFields(Class cl) { Field[] fields = cl.getDeclaredFields(); for (Field f : fields) { Class type = f.getType(); String name = f.getName(); System.out.print(" "); String modifiers = Modifier.toString(f.getModifiers()); if (modifiers.length()> 0) System.out.print(modifiers+" "); System.out.println(type.getName()+ " " +name+";"); } } }

运行的结果:


作者:Z zehao



java学 class类 反射 异常 JAVA 捕获 class

需要 登录 后方可回复, 如果你还没有账号请 注册新账号