转载

Java反射总结(1)

能够分析类能力的程序称为 反射 。对于给定的Java类名,可以通过反射获取类的信息、将类的各成分映射出相应的Java类。

一、Class类

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

创建Class类对象的三种方法:

1. 通过getClass方法

Object中的 getClass 方法将返回一个Class类型的实例。

class Person {    //... }  Person p = new Person(); Class c = p.getClass();

2. forName方法

可以通过静态方法 forName 获得类名对应的Class对象。

String className = "java.util.Date"; Class c = Class.forName(className);

如果需要在运行过程中需要改变类名,就可以使用这种方法。当然,字符串className必须是一种类名或接口(包括包名),否则会出现异常。

3. T.class

Class c1 = Date.class; Class c2 = int.class; Class c3 = Double[].class;

T表示任意的Java类型。通过T.class获取匹配的类对象。

注意:一个Class对象实际表示一种类型,而这种类型未必是一种类。

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

if (p.getClass() == Person.class) {...}

newInstance方法

通过 newInstance 方法可以创建一个类的实例。

Person person = p.getClass().newInstance();

创建了一个与p具有相同类类型的实例。 newInstance调用默认的构造器 初始化创建的对象。如果这个类没有默认的构造器,就会抛出异常。

二、利用反射解析类结构

获取包名+类名(包括父类名)

package com.xiaoxiaoyihan.reflection; class Person {  //... } class Student extends Person{ } public class ReflectionDemo1 {  public static void main(String[] args) {   Student s = new Student();   Class cl = s.getClass();   Class superCl = cl.getSuperclass();   System.out.println("获取类名:" + cl.getName());   System.out.println("获取父类名:" + superCl.getName());  } } 

【运行结果】:

获取类名:com.xiaoxiaoyihan.reflection.Student

获取父类名:com.xiaoxiaoyihan.reflection.Person

说明:如果类在一个包中,包的名字也作为类名的一部分。

一点扩展:

首先看一个例子:

class Person {  private String name = "萧萧弈寒";  // 省略setter和getter } class Animal {  private String name = "paqi";  // 省略setter和getter } Person p; Animal a; Class cPerson = p.getClass(); Class cAnimal = a.getClass(); // cPerson.getName()获取的是类名、p.getName()是Person实例的name属性值 System.out.println(cPerson.getName() + "<--->" + p.getName()); System.out.println(cAnimal.getName() + "<--->" + p.getName()); 

【运行结果】:

com.xxyh.reflec.Person<--->萧萧弈寒

com.xxyh.reflec.Animal<--->paqi

由此说明,一个Person对象p表示一个特定人的属性,一个Animal对象a表示一个特定动物的属性,一个Class对象表示一个特定类(Person或Animal)的属性。从这点看, Class的实例是一种对象

解析构造函数(Constructor)

Class类中的 getConstructors 方法将返回 公共 构造器数组。Class类中的getDeclaredConstructors将返回类中 声明的 构造器数组。

package com.xiaoxiaoyihan.reflection; import java.lang.reflect.Constructor; class Person {  private String name;  private int age;  private Person() {}  protected Person(String name) {   this.name = name;  }  public Person(String name, int age) {   this.name = name;   this.age = age;  } } public class ReflectionDemo1 {  public static void main(String[] args) throws ClassNotFoundException {   Class cl = Class.forName("com.xiaoxiaoyihan.reflection.Person");  // 直接抛出异常以简化代码     Constructor[] constructors = cl.getDeclaredConstructors();   //Constructor[] constructors = cl.getConstructors();   for (Constructor c :constructors) {    System.out.println(c);   }  } } 

【运行结果】:

private com.xiaoxiaoyihan.reflection.Person()

protected com.xiaoxiaoyihan.reflection.Person(java.lang.String)

public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int)

// public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int)// 本部分为运行getConstructors方法输出结果

对结果加以分析,会发现通过 System.out.println(c); 直接打印的构造函数是由几部分组成的,其中包括了 修饰符 (public/protected/private)、 类名 以及 构造函数的参数 ,那么,这些部分是如何获取的呢?

Modifier 类中包含静态方法 getModifiers 方法,它返回一个整数i,用不同的数值表示public、static、final这样的修饰符。Modifier中的静态方法 toString(i) 返回对应的修饰符。 Constructor 类中包含由静态方法 getParameterTypes ,它返回一个描述参数类型的 Class对象数组

package com.xiaoxiaoyihan.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; class Person {  private String name;  private int age;  private Person() {}  protected Person(String name) {   this.name = name;  }  public Person(String name, int age) {   this.name = name;   this.age = age;  } } public class ReflectionDemo1 {  public static void main(String[] args) throws ClassNotFoundException {   Class cl = Person.class;   Constructor[] constructors = cl.getDeclaredConstructors();   for (Constructor c :constructors) {    // 获取包名和类名    String name = c.getName();    // 获取修饰符    String modifiers = Modifier.toString(c.getModifiers());    if (modifiers.length() > 0) {   //如果有修饰符     System.out.print(modifiers + " ");    }    System.out.print(name + "(");    // 获取构造函数的参数类型    Class[] paramTypes = c.getParameterTypes();    for (int i = 0; i < paramTypes.length; i++) {     if (i > 0) { // 如果不止一个参数,使用","将参数类型分割      System.out.print(",");     }     System.out.print(paramTypes[i].getName());    }    System.out.println(");");   }  } }  

【运行结果】:

private com.xiaoxiaoyihan.reflection.Person();

protected com.xiaoxiaoyihan.reflection.Person(java.lang.String);

public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int);

解析方法(Method)

Class类中的 getMethods 将返回方法的数组,其中 包括本类的所有方法、从接口实现的方法、父类的公共(public)方法、父类的父类的公共方法……一直延伸到Object的公共方法getDeclaredMethods 方法将返回 本类声明的方法、从接口实现的方法

package com.xiaoxiaoyihan.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Method; class Person/* extends Object */ {  private void privateMethodPerson() {   //...  }  protected void protectedMethodPerson() {   // ...  }  public void publicMethodPerson() {   //...  } } interface Smoke {  void smoking(); } class Student extends Person implements Smoke{  @Override  public void smoking() {   // ...  }  private void privateMethodStudent() {   //...  }  protected void protectedMethodStudent() {   // ...  }  public void publicMethodStudent() {   //...  } } public class ReflectionDemo1 {  public static void main(String[] args) {   Student s = new Student();   Class cl = s.getClass();   Method[] methods = cl.getDeclaredMethods(); //  Method[] methods = cl.getMethods();   for (Method m : methods) {    System.out.println(m);   }  } } 

【运行结果】:

public void com.xiaoxiaoyihan.reflection.Student.smoking()

protected void com.xiaoxiaoyihan.reflection.Student.protectedMethodStudent()

private void com.xiaoxiaoyihan.reflection.Student.privateMethodStudent()

public void com.xiaoxiaoyihan.reflection.Student.publicMethodStudent()

上面的例子故意给出一种继承结构,是为了查看 getMethods 的结果,在此就不给出结果了。注意Person默认继承了Object类。顺便说一句,笔者(非科班自学菜鸟)曾在面试的时候被问到Object中有哪些方法,估计他是想问有哪些常用方法吧,我没答全~2333,不知道读者您能一眼看出结果吗??。

类似地,我们看到上面的 System.out.println(m); 打印出方法由 修饰符 返回值 类名 方法名 以及 参数 组成。那么这些部分是如果获取的呢? 与Construction类相似,Method类中也提供了静态方法 getParamTypes ,该方法返回描述参数类型的Class对象数组。此外,Method还提供了 getReturnType 方法,用于获取返回类型的Class对象。

package com.xiaoxiaoyihan.reflection; import java.lang.reflect.Method; import java.lang.reflect.Modifier; class Person {  private String name = "萧萧弈寒";  public String getName() {   return name;  }  public void setName(String name) {   this.name = name;  }  public static void speak() {   // ...  }  public final void eat() {   // ...  } } public class ReflectionDemo1 {  public static void main(String[] args) {   Class cl = Person.class;   Method[] methods = cl.getDeclaredMethods();   for (Method m : methods) {    // 返回类型的Class对象    Class retType = m.getReturnType();    //    String retTypeName = retType.getName();    // 获取方法名    String name = m.getName();    String modifiers = Modifier.toString(m.getModifiers());    if (modifiers.length() > 0) // 如果有修饰符     System.out.print(modifiers + " ");    // 返回值名    System.out.print(retType.getName() + " ");    System.out.print(name + "(");    Class[] paramTypes = m.getParameterTypes();    for (int i = 0; i < paramTypes.length; i++) {     if (i > 0) { // 如果不止一个参数,用","分割      System.out.print(paramTypes[i].getName());     }    }    System.out.println(");");   }  } } 

【运行结果】:

public java.lang.String getName();

public void setName();

public static void speak();

public final void eat();

解析域(Field)

Class类中的 getDeclaredFields 方法返回类中 声明的 域数组,getFields方法返回类中的 公有 域、接口中的域所组成的Field对象数组。

package com.xiaoxiaoyihan.reflection; import java.lang.reflect.Field; import java.util.Date; class Person {  private String name;  protected int age;  public Date birthday; } class Student extends Person implements Smoke{  private float score; } interface Smoke {  String brand = "大中华"; } public class ReflectionDemo1 {  public static void main(String[] args) {   Class cl = Student.class;   Field[] fields = cl.getFields();   for (Field f : fields) {    System.out.println(f);   }  } } 

【运行结果】:

public static final java.lang.String com.xiaoxiaoyihan.reflection.Smoke.brand

public java.util.Date com.xiaoxiaoyihan.reflection.Person.birthday

结果显示了字段由 修饰符 类型 类名 字段名 构成。这里需要引入Field类中的 getType 方法,它返回 字段声明类型的Class对象 。下面同样作出解析:

package com.xiaoxiaoyihan.reflection; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Date; class Person {  private String name;  protected int age;  public Date birthday; } public class ReflectionDemo1 {  public static void main(String[] args) {   Class cl = Person.class;   Field[] fields = cl.getDeclaredFields();   for (Field f : fields) {    // 属性类型的Class对象    Class type = f.getType();    // 属性类型名    String name = type.getName();    System.out.print(" ");    // 修饰符    String modifiers = Modifier.toString(f.getModifiers());    if (modifiers.length() > 0) {   // 如果有修饰符     System.out.print(modifiers + " ");    }    System.out.println(type.getName() + " " + name + ";");   }  } } 

【运行结果】:

private java.lang.String java.lang.String;

protected int int;

public java.util.Date java.util.Date;

本人非科班菜鸟一枚,不愿去培训,于是开始了苦逼地自学之路,好不容易找到一份能养活自己的工作~orz。在工作中后知后觉,越来越觉得“基础不牢,地动山摇”、及时总结的重要性。于是开始巩固基础知识,深知水平有限,望大神指教,拜谢!

正文到此结束
Loading...