能够分析类能力的程序成为反射,反射可以用来:
- 在运行时分析类的能力;
- 在运行时查看对象;
- 实现通用的数组操作代码;
- 利用 Method 对象。
# Class 类
获取 Class 类方法:
- Object 类的 getClass () 方法会返回一个 Class 类型的实例;
- Class 类的静态方法 forName (String className)。
- T.class,T 可以是任意类型,如 Random,int,Double []。
常用方法:
- String getName () 返回类的名字。
- Object newInstance () 动态创建一个类的实例。
- Field [] getFields () 返回类或超类的公有域。
- Field [] getDeclaredFields () 返回类中所有域。
- Method [] getMethods () 返回类或超类的公有方法。
- Method [] getDeclaredMethods () 返回类或接口的所有方法。
- Constructor [] getConstructors () 返回类的所有公有构造器。
- Constructor [] getDeclaredConstructors () 返回类的所有构造器。
- Field getField (String name) 返回指定名称的公有域。
- Field getDeclaredField (String name) 返回类中声明的给定名称的域。
# Field 类、Method 类、Constructor 类
常用方法:
- Class getDeclaringClass () 返回一个用于描述类中定义的构造器、方法或域的 Class 对象。
- Class [] getExceptionTypes () 返回一个用于描述方法抛出的异常类型的 Class 对象数组。
- int getModifiers () 返回一个用于描述构造器、方法或域的修饰符的整型数值。
- String getName () 返回一个用于描述构造器、方法或域名的字符串。
- Class [] getParametertypes () 返回一个用于描述参数类型的 Class 对象数组。(在 Method 类和 Constructor 类中)
- Class getReturnType () 返回一个用于描述返回类型的 Class 对象。(在 Method 类中)
- Object get (Object obj) 返回 obj 对象中用 Field 对象表示的域值。(在 Field 类中)
- void set (Object obj, Object newValue) 用一个新值设置 obj 对象中 Field 对象表示的域。(在 Filed 类中)
# Modifier 类
- static String toString (int modifiers) 返回对应 modifiers 中位设置的修饰符的字符串表示。
- static boolean isAbstract (int modifiers) 是否包含 Abstract。
- static boolean isFinal (int modifiers) 是否包含 Final。
- static boolean isInterface (int modifiers) 是否包含 Interface。
- static boolean isNative (int modifiers) 是否包含 Native。
- static boolean isPrivate (int modifiers) 是否包含 Private。
- static boolean isProtected (int modifiers) 是否包含 Protected。
- static boolean isPublic (int modifiers) 是否包含 Public。
- static boolean isStatic (int modifiers) 是否包含 Static。
- static boolean isSynchronized (int modifiers) 是否包含 Synchronized。
- static boolean isVolatile (int modifiers) 是否包含 Volatile。
以上方法运用:
package com.example.demo.test; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Modifier; | |
public class ClassTest { | |
public static void main(String[] args) { | |
String name = "java.lang.Double"; | |
try { | |
Class cl = Class.forName(name); | |
String modifiers = Modifier.toString(cl.getModifiers()); | |
if (modifiers.length() > 0) { | |
System.out.print(modifiers + " "); | |
} | |
System.out.print("class " + name); | |
Class superCl = cl.getSuperclass(); | |
if (superCl != null && superCl != Object.class) { | |
System.out.print(" extends " + superCl.getName() + " {"); | |
} | |
System.out.println(); | |
printFields(cl); | |
System.out.println(); | |
printConstructors(cl); | |
System.out.println(); | |
printMethods(cl); | |
System.out.println("}"); | |
} catch (ClassNotFoundException e) { | |
e.printStackTrace(); | |
} | |
} | |
public static void printFields(Class cl) { | |
Field[] fields = cl.getFields(); | |
for (Field field : fields) { | |
System.out.print(" "); | |
String modifiers = Modifier.toString(field.getModifiers()); | |
if (!modifiers.isEmpty()) { | |
System.out.print(modifiers + " "); | |
} | |
System.out.println(field.getType().getName() + " " + field.getName()); | |
} | |
} | |
public static void printConstructors(Class cl) { | |
Constructor[] constructors = cl.getConstructors(); | |
for (Constructor constructor : constructors) { | |
System.out.print(" "); | |
String modifiers = Modifier.toString(constructor.getModifiers()); | |
if (!modifiers.isEmpty()) { | |
System.out.print(modifiers + " "); | |
} | |
System.out.print(constructor.getName() + "("); | |
Class[] paramTypes = constructor.getParameterTypes(); | |
for (int i = 0; i < paramTypes.length; i++) { | |
if (i > 0) { | |
System.out.print(", "); | |
} | |
System.out.print(paramTypes[i].getName()); | |
} | |
System.out.println(");"); | |
} | |
} | |
public static void printMethods(Class cl) { | |
Method[] methods = cl.getMethods(); | |
for (Method method : methods) { | |
System.out.print(" "); | |
String modifiers = Modifier.toString(method.getModifiers()); | |
if (!modifiers.isEmpty()) { | |
System.out.print(modifiers + " "); | |
} | |
System.out.print(method.getReturnType().getName() + " " + method.getName() + "("); | |
Class[] paramTypes = method.getParameterTypes(); | |
for (int i = 0; i < paramTypes.length; i++) { | |
if (i > 0) { | |
System.out.print(", "); | |
} | |
System.out.print(paramTypes[i].getName()); | |
} | |
System.out.println(");"); | |
} | |
} | |
} |
运行结果:
public final class java.lang.Double extends java.lang.Number {
public static final double POSITIVE_INFINITY
public static final double NEGATIVE_INFINITY
public static final double NaN
public static final double MAX_VALUE
public static final double MIN_NORMAL
public static final double MIN_VALUE
public static final int MAX_EXPONENT
public static final int MIN_EXPONENT
public static final int SIZE
public static final int BYTES
public static final java.lang.Class TYPE
public java.lang.Double(double);
public java.lang.Double(java.lang.String);
public boolean equals(java.lang.Object);
public static java.lang.String toString(double);
public java.lang.String toString();
public int hashCode();
public static int hashCode(double);
public static double min(double, double);
public static double max(double, double);
public static native long doubleToRawLongBits(double);
public static long doubleToLongBits(double);
public static native double longBitsToDouble(long);
public volatile int compareTo(java.lang.Object);
public int compareTo(java.lang.Double);
public byte byteValue();
public short shortValue();
public int intValue();
public long longValue();
public float floatValue();
public double doubleValue();
public static java.lang.Double valueOf(java.lang.String);
public static java.lang.Double valueOf(double);
public static java.lang.String toHexString(double);
public static int compare(double, double);
public static boolean isNaN(double);
public boolean isNaN();
public static boolean isFinite(double);
public static boolean isInfinite(double);
public boolean isInfinite();
public static double sum(double, double);
public static double parseDouble(java.lang.String);
public final void wait();
public final void wait(long, int);
public final native void wait(long);
public final native java.lang.Class getClass();
public final native void notify();
public final native void notifyAll();
}
# Accessible 类
Accessible
类是 Field
类、 Method
类和 Constructor
类的公共超类,其 setAccessible()
方法可以修改访问控制。如下面的 field.setAccessible(true)
语句,没有这个语句,将不能获取私有变量 name
的值。当属性类型是基本数据类型时,会将值包装到对应的包装器中,即 double
包装成 Double
。
Java 代码:
package com.example.demo.test; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Modifier; | |
public class ClassTest { | |
public static void main(String[] args) { | |
Person person = new Person("huihui", 18); | |
Class cl = person.getClass(); | |
try { | |
Field field = cl.getDeclaredField("name"); | |
Field field1 = cl.getDeclaredField("age"); | |
field.setAccessible(true); | |
field1.setAccessible(true); | |
Object v = field.get(person); | |
Object v1 = field1.get(person); | |
System.out.println(v + ":" + v.getClass().getName()); | |
System.out.println(v1 + ":" + v1.getClass().getName()); | |
} catch (NoSuchFieldException e) { | |
e.printStackTrace(); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
class Person { | |
private String name; | |
private double age; | |
public Person(String name, Integer age) { | |
this.name = name; | |
this.age = age; | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public double getAge() { | |
return age; | |
} | |
public void setAge(double age) { | |
this.age = age; | |
} | |
} |
运行结果:
huihui:java.lang.String
18.0:java.lang.Double
# AccessibleObject 类
- void setAccessible (boolean flag) 为反射对象设置可访问标志。
- boolean isAccessible () 返回反射对象可访问标志的值。
- static void setAccessible (AccessibleObject [] array, boolean flag) 设置对象数组可访问标志的快捷方法。
# Array 类
- static Object get (Object array, int index) 返回储存在给定位置上的给定数组的内容。
- static xxx getXxx (Object array, int index) xxx 是基本数据类型中的一种,返回存储在给定位置上的给定数组的内容。
- static void set (Object array, int index, Object newValue) 将一个新值存储到给定位置上的给定数组中。
- static void setXxx (Object array, int index, Object newValue) xxx 是基本数据类型中的一种,将一个新值存储到给定位置上的给定数组中。
- static int getLength (Object array) 返回数组的长度。
- static Object newInstance (Class componentType, int length) 返回一个具有给定类型、给定维数的新数组。
- static Object newInstance (Class componentType, int length) 返回一个具有给定类型、给定维数的新数组。
Java 代码:
package com.example.demo.test; | |
import java.lang.reflect.*; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
public class ClassTest { | |
public static void main(String[] args) { | |
int[] a = {1, 2, 3}; | |
a = (int[]) goodCopyOf(a, 10); | |
System.out.println(Arrays.toString(a)); | |
String[] b = {"aa", "bb", "cc"}; | |
b = (String[]) goodCopyOf(b, 10); | |
System.out.println(Arrays.toString(b)); | |
b = (String[]) badCopyOf(b, 10); | |
} | |
public static Object[] badCopyOf(Object[] a, int newLength) { | |
Object[] newArray = new Object[newLength]; | |
System.arraycopy(a, 0, newArray, 0, Math.min(a.length, newLength)); | |
return newArray; | |
} | |
public static Object goodCopyOf(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; | |
} | |
} |
运行结果:
[1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
[aa, bb, cc, null, null, null, null, null, null, null]
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;at com.example.demo.test.ClassTest.main(ClassTest.java:18)
在 badCopyof
方法中, Object[]
转 String[]
报错,将 String[]
临时转为 Object[]
再转为 String[]
可以。从一开始就是 Object
的数组永远不能转换为 String[]
。在 goodCopyof
方法中, int[]
可以转换成 Object
,但不能转换为 Object[]
,所以方法返回 Object
。
# invoke () 方法
public Object invoke (Object implicitParameter, Object [] explicitParameters),调用这个对象所描述的方法,传递给定参数,并返回方法的返回值。对于静态方法,把 null 作为隐式参数传递,在使用包装器传递基本类型的值时,基本类型的返回值必须是未包装的。
Java 代码:
package com.example.demo.test; | |
import java.lang.reflect.*; | |
import java.util.ArrayList; | |
public class ClassTest { | |
public static void main(String[] args) { | |
try { | |
Method square = ClassTest.class.getMethod("square", double.class); | |
Method sqrt = Math.class.getMethod("sqrt", double.class); | |
printTable(1, 10, 10, square); | |
printTable(1, 10, 10, sqrt); | |
} catch (NoSuchMethodException e) { | |
System.out.println(e.getMessage()); | |
} | |
} | |
public static double square(double x) { | |
return x * x; | |
} | |
public static void printTable(double from, double to, int n, Method f) { | |
System.out.println(f); | |
double dx = (to - from) / (n - 1); | |
for (double x = from; x <= to; x += dx) { | |
try { | |
double y = (Double) f.invoke(null, x); | |
System.out.printf("%10.4f | %10.4f%n", x, y); | |
} catch (Exception e) { | |
System.out.println(e.getMessage()); | |
} | |
} | |
} | |
} |
运行结果:
public static double com.example.demo.test.ClassTest.square(double)
1.0000 | 1.0000
2.0000 | 4.0000
3.0000 | 9.0000
4.0000 | 16.0000
5.0000 | 25.0000
6.0000 | 36.0000
7.0000 | 49.0000
8.0000 | 64.0000
9.0000 | 81.0000
10.0000 | 100.0000
public static double java.lang.Math.sqrt(double)
1.0000 | 1.0000
2.0000 | 1.4142
3.0000 | 1.7321
4.0000 | 2.0000
5.0000 | 2.2361
6.0000 | 2.4495
7.0000 | 2.6458
8.0000 | 2.8284
9.0000 | 3.0000
10.0000 | 3.1623