文章通过三部分描述反射的用法,class,field和method,array。具体学习可以查看reflect包下的代码:
理论方面的学习,请看这里。
先看下面简单的例子,对反射有些映像。
class:
import java.lang.reflect.Constructor;
/**
* 这个例子中,无参构造函数是私有的,但反射可以调用,说明了反射打破了类的访问性。
* 另一方面,newInstance方法反射依赖无参构造函数,如果沒有无参构造函数,就不能使用这个方法。
* 但仍然可以获取所有构造函数后调用,不过奇怪的是,这种方法调用构造函数必须是可见的,即private在其他类是不能访问的。
*/
public class Person {
private String name;
private int age;
@SuppressWarnings("unused")
private Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "[" + this.name + " " + this.age + "]";
}
public static void main(String[] args) {
Class<?> clazz = null;
try {
// 获取类实例
clazz = Class.forName("advanced.reflections.domian.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
// 调用构造函数
Person p = (Person) clazz.newInstance();//
p.setAge(100);
p.setName("Nature");
System.out.println(p);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
try {
// 這種方法構造對象需要構造器是可訪問的。即使在自己的類中定義的main中,如果構造器是私有的,仍然無法訪問。
// Constructor<?> construct = clazz.getConstructor(new Class[] { String.class, int.class });
Constructor<?> construct = clazz.getConstructor(String.class, int.class );
Person p = (Person) construct.newInstance("MyName", 20);
System.out.println(p);
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
反射提供了很多get方法,用于获取类的详细的信息,如下:
可以获得类的名字,包名,加载器,构造器,域,方法,修饰信息,嵌套类,泛型,父类等类的信息。其中,declared表示这个类中申明的,父类继承的不算。
举例,借用了上面的类:
import java.lang.reflect.Field;
/**
* Declared的用处。
*/
public class Strdent extends Person {
int number;
public String myWord;
public Strdent(String name, int age, int number, String myWord) {
super(name, age);
this.number = number;
this.myWord = myWord;
}
public static void main(String[] args) {
Class<?> clazz = Strdent.class;
{
System.out.println("declared");
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
System.out.println(f.getName());
}
}
System.out.println("--------------");
{
System.out.println("public");
// getFields 返回的是public的
Field[] fields = clazz.getFields();
for (Field f : fields) {
System.out.println(f.getName());
}
}
}
}
同时,Class也提供了大量的判断方法,如下图:
这样可以判断是够匿名,是否是数组,是够是父类isAssignableFrom,是够是实例,接口等。
举例:
System . out . println ( Collection . class . isAssignableFrom ( ArrayList . class ));//返回true
Field 和 Method:
Field:
Method:
举例:
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Declared的用处。 Field and Method stuff. field. 这里主要关注点就是方法和域的访问和修改。
* getInt():field是int,且obj中含有这个域。 method.invoke
*/
public class Student extends Person {
private int number;
int id = 12526845;
public String myWord;
public Student() {
}
public Student(String name, int age, int number, String myWord) {
super(name, age);
this.number = number;
this.myWord = myWord;
}
public String toString() {
return "[" + super.getName() + ":" + number + ":" + id + ":" + super.getAge() + "]";
}
public static boolean isMale(Student std) {
return (std.id & 1) == 1;
}
public static void main(String[] args) {
Class<?> clazz = Student.class;
Student std = null;
try {
std = (Student) clazz.newInstance();
std.setName("JAKKKK");
std.setAge(15);
} catch (InstantiationException | IllegalAccessException e1) {
e1.printStackTrace();
}
System.out.println("==========================\nField");
{
{
System.out.println("declared");
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
System.out.println(f.getName());
System.out.println(f.getModifiers());
System.out.println(f.getType());
try {
if (f.getName().equals("number")) {
// 外部无法访问到这个方法,因为是private
System.out.println("f.getInt()" + f.getInt(new Student()));
// 要检查f是否可以访问,true表示不检查访问性
f.setAccessible(false);
f.set(std, 21321299);
}
if (f.getName().equals("id")) {
System.out.println("f.getInt()" + f.getInt(new Student()));
f.set(std, 110119120);
}
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
System.out.println(std);
}
System.out.println("--------------");
{
System.out.println("public");
// getFields 返回的是public的
Field[] fields = clazz.getFields();
for (Field f : fields) {
System.out.println(f.getName());
}
}
}
System.out.println("==========================\nMethod");
{
{
System.out.println("Declared Methods");
Method[] ms = clazz.getDeclaredMethods();
for (Method m : ms) {
System.out.println(m.getName());
}
}
{
System.out.println("Methods");
// 所有的公开方法
Method[] ms = clazz.getMethods();
for (Method m : ms) {
System.out.println(m.getName());
System.out.println(m.getDefaultValue());
System.out.println(m.getModifiers());
System.out.println(m.getDeclaringClass());
System.out.println(m.getParameterTypes());
System.out.println(m.getReturnType());
System.out.println(m.isBridge());
System.out.println(m.isAccessible());
}
}
}
System.out.println("==========================\nMethod.Invoke");
{
try {
Method m1 = clazz.getMethod("toString");
System.out.println(m1.getName());
System.out.println(m1.invoke(std));
Method m2 = clazz.getMethod("getName");
System.out.println(m2.getName());
System.out.println(m2.invoke(std));
System.out.println(clazz.getMethod("isMale", Student.class).invoke(null, std));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
}
Array:
例子:
package advanced.reflections.arrays;
import java.lang.reflect.Array;
/**
* 主要探究反射在数组中的应用。关于数组,很多方法并不在class中,而是在Array中。 当然,主要也是get和set方法,但Array都是静态的方法。
*/
public class ArrayStuff {
public static void main(String[] args) {
int[] array = { 1, 2, 3, 4, 5 };
// 返回数组元素的类型
Class<?> componentType = array.getClass().getComponentType();
System.out.println("数组类型: " + componentType.getName());
System.out.println("数组长度 " + Array.getLength(array));
System.out.println("数组的第一个元素: " + Array.get(array, 0));
Array.set(array, 0, 100);
System.out.println("修改之后数组第一个元素为: " + Array.get(array, 0));
int[] newArr = (int[]) Array.newInstance(componentType, 10);
System.arraycopy(array, 0, newArr, 0, 5);
print(newArr);
System.out.println(Array.getInt(array, 3));
// 这句报错:argument type mismatch 因为int->char不能自动转化
System.out.println(Array.getChar(array, 3));
}
private static void print(int[] arr) {
for (Object o : arr) {
System.out.print(o + " ");
}
System.out.println();
}
}