赞
踩
本关任务:实现获取Class
对象的三种方式
为了完成本关任务,你需要掌握:
Class
对象;Class
类型的实例的方法;
Object
类中的getClass()
方法;Class.forName("全类名")
;Class.class
。Class
对象之间的区别。Java
运行时系统始终为所有的对象维护一个被称为运行时的类型标识(RTTI
)。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。保存这些信息的类被称为Class
,可以通过专门的Java
类访问这些信息。Class
类的实例表示正在运行的Java
应用程序中的类和接口。其中枚举是一种特殊的类,注释是一种特殊的接口。每个数组属于被映射为Class
对象的一个类,所有具有相同元素类型和维数的数组都共享该Class
对象基本的Java
类型(boolean
、byte
、char
、short
、int
、long
、float
和double
)和关键字void
也表示为Class
对象。Class
对象就是用来创建类的所有的”常规”对象的。每个类都有一个Class
对象,每当编写一个并且编译了一个新类,就会产生一个Class
对象(保存在体同名的 .class
文件中)。Class
没有公共构造方法。Class
对象是在加载类时由Java
虚拟机以及通过调用类加载器中的defineClass
方法自动构造的。方法1:通过Object
类中的getClass()
方法返回一个Class
类型的实例
示例如下:
Person person = new Person();
Class clazz = person.getClass();
方法2:通过静态方法Class.forName("全类名")
获取类名对应的Class
对象
Class.forName()
方法原型:
public static Class<?> forName(String className) throws ClassNotFoundException
若无法根据类路径className
找到对应的 .class
文件会抛出 ClassNotFoundException
异常,因此使用forName()
方法需要捕获异常或向上抛出异常。
示例如下:
Class clazz = null;
String className = "step1.Person";
try {
clazz = Class.forName(className);
} catch(ClassNotFoundException e) {
}
方法3:通过类字面常量Class.class
获取
示例如下:
Class clazz = Person.class;
该方法不仅更简单,而且更安全,因为它在编译时就会受到检查(因此不需要置于try
语句块中)。并且它根除了对forName()
方法的调用,所以更高效。
每个类都有一个Class
对象,因此对于某个类使用三种方式获取的 Class
对象都是相等。
请仔细阅读右侧代码,结合相关知识,在Begin-End
区域内进行代码补充,完成三个方法getPersonClass1()
、getPersonClass2()
、getPersonClass3()
的代码编写,要求分别使用三种方式获取Person
类的Class
对象并返回。 注意:无需修改main()
方法的输出内容。
平台会对你编写的代码进行测试:
预期输出:
通过Object 类中的 getClass() 获取的 Class 对象为:class step1.Person
通过静态方法 Class.forName() 获取的 Class 对象为:class step1.Person
通过类字面常量获取 Class 的对象为:class step1.Person
开始你的任务吧,祝你成功!
package step1; /** * 学员任务文件 */ public class Reflect_stu { public static void main(String[] args) { System.out.println("通过Object 类中的 getClass() 获取的 Class 对象为:" + getPersonClass1()); System.out.println("通过静态方法 Class.forName() 获取的 Class 对象为:" + getPersonClass2()); System.out.println("通过类字面常量获取 Class 的对象为:" + getPersonClass3()); } /** * 通过 Object 类中的 getClass() 获取的 Class 对象 * * @return */ public static Class getPersonClass1() { /********** Begin *********/ Person person = new Person(); Class clazz1 = person.getClass(); return clazz1; /********** End *********/ } /** * 通过静态方法 Class.forName() 获取的 Class 对象 * <p> * 注意:Person 类的全路径为: step1.Person * * @return */ public static Class getPersonClass2() { /********** Begin *********/ String className = "step1.Person"; Class clazz2 = null; try { clazz2 = Class.forName(className); } catch (ClassNotFoundException e) { } return clazz2; /********** End *********/ } /** * 通过类字面常量获取 Class 的对象 * * @return */ public static Class getPersonClass3() { /********** Begin *********/ Class clazz3 = Person.class; return clazz3; /********** End *********/ } }
package step1; /** * 评测执行文件 */ public class Reflect_run { public static void main(String[] args) { // Class clazz1 = Person.class; 2、通过对象的getClass()方法返回一个Class类型的实例 // Person person = new Person(); // Class clazz2 = person.getClass(); 3、通过静态方法Class.forName()获取类名对应的Class对象 // Class clazz3 = null; // try { // clazz3 = Class.forName("step1.Person"); // } catch (ClassNotFoundException e) { // e.printStackTrace(); // } // // // 使用 "==" 进行比较 clazz1 与 clazz2 的关系 // System.out.println(clazz1 == clazz2); // // 使用 "==" 进行比较 clazz2 与 clazz3 的关系 // System.out.println(clazz2 == clazz3); System.out.println("通过Object 类中的 getClass() 获取的 Class 对象为:" + getPersonClass1()); System.out.println("通过静态方法 Class.forName() 获取的 Class 对象为:" + getPersonClass2()); System.out.println("通过类字面常量获取 Class 的对象为:" + getPersonClass3()); } /** * 通过 Object 类中的 getClass() 获取的 Class 对象 * * @return */ public static Class getPersonClass1() { return new Person().getClass(); } /** * 通过静态方法 Class.forName() 获取的 Class 对象 * * @return */ public static Class getPersonClass2() { Class clazz = null; try { clazz = Class.forName("step1.Person"); } catch (ClassNotFoundException e) { e.printStackTrace(); } return clazz; } /** * 通过类字面常量获取 Class 的对象 * * @return */ public static Class getPersonClass3() { return Person.class; } }
package step1;
public class Person {
}
本关任务:利用反射获取Apple
类的的所有的方法和构造器签名,以及全部域名。
为了完成本关任务,你需要回顾上节所学Class
对象的相关知识, 以及需要掌握以下知识:
Class
对象与反射之间的关系;Class
的类结构;反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
Java
反射机制允许程序在运行时取得任何一个已知名称的Class
的内部信息,包括其 modifiers
(修饰符)、fields
(属性),methods
(方法)等,并可于运行时改变 fields
内容或调用 methods
。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!
在java.lang.reflect
包中有三个类Field
、Method
和Constructor
分别用于描述类的域、方法和构造器。Class
类中的getFields()
、getMethods()
和getConstructors()
方法将分别返回类提供的 public
域、方法和构造器,其中包括超类的共有成员。Class
类中的getDeclareFields()
、getDeclareMethods()
和getDeclareConstructors()
方法将分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护的成员,但不包括超类的成员。
如:
public Field[] getFields() throws SecurityException
public Method[] getMethods() throws SecurityException
public Constructor<?>[] getConstructors() throws SecurityException
通过获取某个类的Class
对象,并通过Class
类的 getFields()
、getMethods()
和getConstructors()
获得所有域、方法和构造器。
示例:
class Person { public String name; String sex; protected String height; private int age; public Person() { } private Person(String name) { this.name = name; } public Person(String name, String sex, String height, int age) { ...省略 } } public static void main(String[] args) { Person person = new Person(); printConstructors(person.getClass()); } public static void printConstructors(Class clazz) { Constructor[] constructors = clazz.getConstructors(); for (Constructor constructor : constructors) { String name = constructor.getName(); System.out.print(" "); String modifiers = Modifier.toString(constructor.getModifiers()); if (modifiers.length() > 0) { System.out.print(modifiers + " "); } System.out.print(name + "("); Class[] paramTypes = constructor.getParameterTypes(); for (int j = 0; j < paramTypes.length; ++j) { if (j > 0) { System.out.print(","); } System.out.print(paramTypes[j].getName()); } System.out.println(");"); } }
输出结果:
public Person();
public Person(java.lang.String,java.lang.String,java.lang.String,int);
请仔细阅读右侧代码,结合相关知识,在Begin-End
区域内进行代码补充,打印Apple
类的所有public
域、方法和构造器。已分别提供了方法声明printConstructors
、printFields
、printMethods
,请将代码补充完整,且按照打印格式要求输出。
提示:
Method.getReturnType()
可以获得方法的返回类型。printModifiers()
方法printParamTypes()
方法Field
的getType
方法可以获得域类型、getName
方法可以获得域的名称预期输出:
private java.lang.String name;
public step2.Apple();
public step2.Apple(java.lang.String);
public void setName(java.lang.String);
平台会对你编写的代码进行测试。
开始你的任务吧,祝你成功!
package step2; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; class Apple { private String name; public Apple() { } public Apple(String name) { } public void setName(String name) { this.name = name; } } public class Reflect_stu { public static void main(String[] args) { // 请根据提供的 classPath 获取 step2.Apple 的 Class 对象, 请使用 Class.forName() 方法, 注意捕获异常 // 通关之后,你也可以修改 clasapath 为其他类路径,分析某个类的能力, 例如: java.util.Date String classPath = "step2.Apple"; Class clazz = null; /********** Begin *********/ try { clazz = Class.forName(classPath); } catch (ClassNotFoundException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } /********** End *********/ printFields(clazz); printConstructors(clazz); printMethods(clazz); } /** * 请打印类的每个域,输出格式为:修饰符 类型 变量名; * * @param clazz */ public static void printFields(Class clazz) { /********** Begin *********/ try { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { System.out.print(Modifier.toString(field.getModifiers()) + " "); System.out.print(field.getType().getTypeName() + " "); System.out.println(field.getName() + ";"); } } catch (Exception e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } /********** End *********/ } /** * 打印构造函数,输出格式为:修饰符 方法名称(参数) * * @param clazz */ public static void printConstructors(Class clazz) { Constructor[] constructors = clazz.getDeclaredConstructors(); for (Constructor constructor : constructors) { Class[] paramTypes = null; /********** Begin *********/ paramTypes = constructor.getParameterTypes(); System.out.print(Modifier.toString(constructor.getModifiers()) + " "); System.out.print(constructor.getName() + "("); /********** End *********/ printParamTypes(paramTypes); } } /** * 请针对每个方法打印其签名,格式为:修饰符 返回值类型 方法名称(参数); * * @param clazz */ public static void printMethods(Class clazz) { Method[] methos = clazz.getDeclaredMethods(); for (Method method : methos) { Class[] paramTypes = null; /********** Begin *********/ paramTypes = method.getParameterTypes(); System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getReturnType().getName() + " " + method.getName() + "("); /********** End *********/ printParamTypes(paramTypes); } } /** * 打印方法参数 * * @param paramTypes */ private static void printParamTypes(Class[] paramTypes) { for (int j = 0; j < paramTypes.length; ++j) { if (j > 0) { System.out.print(","); } System.out.print(paramTypes[j].getName()); } System.out.println(");"); } }
package step2; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class Reflect_run { public static void main(String[] args) { // 请根据提供的 classPath 获取 step2.Apple 的 Class 对象 String classPath = "step2.Apple"; Class clazz = null; try { clazz = Class.forName(classPath); } catch (ClassNotFoundException e) { e.printStackTrace(); } printConstructors(clazz); printFields(clazz); printMethods(clazz); } public static void printConstructors(Class clazz) { Constructor[] constructors = clazz.getDeclaredConstructors(); for (Constructor constructor : constructors) { String name = constructor.getName(); printModifiers(clazz); System.out.print(name + "("); Class[] paramTypes = constructor.getParameterTypes(); printParamTypes(paramTypes); } } private static void printModifiers(Class clazz) { System.out.print(" "); String modifiers = Modifier.toString(clazz.getModifiers()); if (modifiers.length() > 0) { System.out.print(modifiers + " "); } } public static void printMethods(Class clazz) { Method[] methos = clazz.getDeclaredMethods(); for (Method method : methos) { Class returnType = method.getReturnType(); String name = method.getName(); printModifiers(clazz); System.out.print(returnType.getName() + " " + name + "("); Class[] paramTypes = method.getParameterTypes(); printParamTypes(paramTypes); } } private static void printParamTypes(Class[] paramTypes) { for (int j = 0; j < paramTypes.length; ++j) { if (j > 0) { System.out.print(","); } System.out.print(paramTypes[j].getName()); } System.out.println(");"); } public static void printFields(Class clazz) { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { Class type = field.getType(); String name = field.getName(); printModifiers(clazz); System.out.println(type.getName() + " " + name + ";"); } } }
package step2; public class Person { public String name; protected String height; String sex; private int age; public Person() {} public Person(String name) { this.name = name; } public Person(String name, String sex, String height, int age) { this.name = name; this.sex = sex; this.height = height; this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getHeight() { return height; } public void setHeight(String height) { this.height = height; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
本关任务:完成一个可供任意类使用的通用toString(Object)
方法。
为了完成本任务,你需要掌握:
Field
类的get
方法获取对象域;Java
安全访问控制获取私有对象域;Field
类的 get
方法获取对象域利用反射机制可以查看在编译时还不清楚的对象域。而查看对象域的关键方法就是Field
类中的get
方法。
Object | get(Object obj) 返回指定对象上此Field表示字段的值。 |
如果f
是一个Field
类型的对象(例如,通过getDeclaredFields()
得到的对象),obj
是一个包含f
域的类的对象, 那么f.get(obj)
将返回一个对象,其值为obj
域的当前值。如此就可以在运行时获得对象的域。
示例:
class Person {
public Integer weight;
private Integer age;
private double height;
// 省略构造器、setter 和 getter 方法
}
public void test() {
Person person = new Person(123, 19);
Class clazz = person.getClass();
Field field = clazz.getDeclaredField("weight");
Object name = field.get(person);
System.out.println(name); // 其打印结果为: "123"
}
Java
安全访问控制获取私有对象域那如果要获取对象的私有域呢,例如,要获取Perso
小明的年龄呢,直接修改上面示例为getDeclaredField("age")
可以吗。答案是,不行,因为age
是一个私有域,所以get
方法会抛出一个 IllegalAccessException
异常。
只有利用get
方法才能得到可访问域的值。除非拥有访问权限,Java
安全机制只允许查看任意对象有哪些域,而不允许读取它们的值。
反射机制的默认行为受限于 Java
的访问控制。然而,如果一个 Java
程序没有收到安全管理器的控制,就可以覆盖访问控制。调用 Field
、Method
或Constructor
对象的setAccessible
方法可以突破这种限制。
示例:
public void test() {
Person person = new Person(123, 19, 175);
Class clazz = person.getClass();
Field field = clazz.getDeclaredField("age");
// 获取私有域的访问权限
field.setAccessible(true);
Object name = field.get(person);
System.out.println(name); // 其打印结果为: "19"
}
Object | get(Object obj) 返回指定对象上此Field表示字段的值。 |
get
方法还有一个要解决的问题。name
域是一个String
,因此可以作为Object
返回。但是,如果要查看height
域,它属于double
类型,而 Java
中数值类型不是对象。因此要使用Field
的其他 getXXX()
方法。反射机制会自动的将这个域值打包到相应的对象包装器中。
double | getDouble(Object obj) 获取double类型或另一个通过扩展转换可以转换为double类型的基本类型的静态或实例字段的值。 |
---|---|
float | getFloat(Object obj) 获取float类型或另一个通过扩展转换可以转换为float类型的基本类型的静态或实例字段的值。 |
Type | getGenericType() 返回一个Tpye对象,它表示此Field对象所表示字段的声明类型。 |
int | getInt(Object obj) 获取int类型或另一个通过扩展转换可以转换为int类型的基本类型的静态或实例字段的值。 |
long | getLong(Object obj) 获取long类型或另一个通过扩展转换可以转换为long类型的基本类型的静态或实例字段的值。 |
请仔细阅读右侧代码,结合相关知识,在Begin-End
区域内进行代码补充,完成通用toString()
方法。
提示:
快速设置访问权限: ``AccessibleObject.setAccessible(fields, true); ``
获得所有域:``Class.getDeclaredFields()``
平台会对你编写的代码进行测试。
示例:
public static void toString(Object obj) {
// 请完成代码
}
public static void main(String[] args) {
Person person = new Person(123, 19, 175);
toString(person);
}
预期输出: [weight=[value=123],age=[value=19],height=[value=175.0]]
开始你的任务吧,祝你成功!
package step3; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class Reflect_stu { public static String toString(Object obj) { Class cl = obj.getClass(); String r = ""; r += "["; // 请获取所有 Field 并设置访问权限为 true /********** Begin *********/ Field[] fields = null; fields = cl.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); /********** End *********/ for (Field f : fields) { // 此处 if,逻辑为判断 Field 域是否为非静态域 if (!Modifier.isStatic(f.getModifiers())) { if (!r.endsWith("[")) r += ","; r += f.getName() + "="; try { // 请获取域的类型及值 /********** Begin *********/ Class t = null; Object val = null; t = f.getType(); val = f.get(obj); /********** End *********/ // isPrimitive() 用于判断是否为基本数据类型,若为基础数据类型直接拼接,否则递归调用 toString 方法 if (t.isPrimitive()) r += val; else r += toString(val); } catch (Exception e) { e.printStackTrace(); } } } r += "]"; return r; } public static void main(String[] args) { Person person = new Person(88, 19, 175); System.out.println(toString(person)); } } class Person { public Integer weight; private Integer age; private Double height; public Person(Integer weight, Integer age, double height) { this.weight = weight; this.age = age; this.height = height; } }
package step3; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class Reflect_run { public static String toString(Object obj) { Class cl = obj.getClass(); String r = ""; r += "["; Field[] fields = cl.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); for (Field f : fields) { if (!Modifier.isStatic(f.getModifiers())) { if (!r.endsWith("[")) r += ","; r += f.getName() + "="; try { Class t = f.getType(); Object val = f.get(obj); if (t.isPrimitive()) r += val; else r += toString(val); } catch (Exception e) { e.printStackTrace(); } } } r += "]"; return r; } public static void main(String[] args) { Person person = new Person(88, 19, 175); System.out.println(toString(person)); } }
本关任务:利用反射创建对象并调用其方法。
为了完成本关任务,你需要掌握:
反射创建类对象主要有两种方式,通过Class
对象的newInstance()
方法、通过Constructor
对象的 newInstance()
方法。
第一种:通过Class
对象的newInstance()
方法。
Class clazz = Apple.class;
Apple apple = (Apple)clazz.newInstance();
第二种:通过Constructor
对象的newInstance()
方法
Class clazz = Apple.class;
Constructor constructor = clazz.getConstructor();
Apple apple = (Apple)constructor.newInstance();
通过Constructor
对象创建类对象可以选择特定构造方法,而通过 Class
对象则只能使用默认的无参数构造方法。
示例:(调用有参构造方法进行类对象的初始化)
Class clz = Apple.class;
Constructor constructor = clz.getConstructor(String.class, int.class);
Apple apple = (Apple)constructor.newInstance("红富士", 15);
利用Method
的invoke
方法可以调用执行对象obj
的方法
More ActionsObjectinvoke(Object obj,Object… args) 对带有指定参数的指定对象调用由此Method对象表示的底层方法。 |
参数: obj
表示要调用的Method
方法对象。 args
表示要调用的方法的参数,是可变长参数类型。
示例:
// 获取类的 Class 对象实例 Class clz = Class.forName("Apple"); // 根据 Class 对象实例获取 Constructor 对象 Constructor appleConstructor = clz.getConstructor(); // 使用 Constructor 对象的 newInstance 方法获取反射类对象 Object appleObj = appleConstructor.newInstance(); // 而如果要调用某一个方法,则需要经过下面的步骤: // 1、获取方法的 Method 对象 Method setPriceMethod = clz.getMethod("setPrice", int.class); // 2、用 invoke 方法调用方法 setPriceMethod.invoke(appleObj, 14); class Apple { public void setPrice(int price) { //省略 } // 省略 }
请仔细阅读右侧代码,结合相关知识,在Begin-End
区域内进行代码补充,使用反射调用 Apple
类的 setPrice()
方法,设置苹果价格为 14
,并打印价格。接着还要用反射去调用getTotal
方法获取单价为 20
,数量 24
的总金额并打印。
预期输出:
14.0
480.0
平台会对你编写的代码进行测试。
开始你的任务吧,祝你成功!
package step4; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Reflect_stu { public static void main(String[] args) throws InvocationTargetException { // 使用反射调用 Class clazz = null; try { clazz = Class.forName("step4.Apple"); /********** Begin *********/ Constructor cons = clazz.getConstructor(); Apple apple = (Apple) cons.newInstance(); Method method = clazz.getMethod("setPrice", double.class); method.invoke(apple, 14); Method getPrice = clazz.getMethod("getPrice"); System.out.println(getPrice.invoke(apple)); Method getTotal = clazz.getMethod("getTotal", double.class, int.class); System.out.println(getTotal.invoke(apple, 20, 24)); /********** End *********/ } catch (Exception e) { e.printStackTrace(); } } } class Apple { private double price; private int count; public Apple() { } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public double getTotal(double price, int count) { return price * count; } }
package step4; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Reflect_run { public static void main(String[] args) throws InvocationTargetException { //使用反射调用 Class clazz = null; try { clazz = Class.forName("step4.Apple"); Method setPriceMethod = clazz.getMethod("setPrice", double.class); Constructor appleConstructor = clazz.getConstructor(); Object apple = appleConstructor.newInstance(); setPriceMethod.invoke(apple, 20); Method getPriceMethod = clazz.getMethod("getPrice"); System.out.println(getPriceMethod.invoke(apple)); Method getTotal = clazz.getMethod("getTotal", double.class, int.class); System.out.println(getTotal.invoke(apple, 20, 24)); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException e) { e.printStackTrace(); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。