Java反射学习笔记
Java的反射机制,允许程序在运行时获取类的任何信息:包括类名、父类、实现的接口、参数列表、构造函数列表、方法列表以及属性和方法的修饰符等等。Java的反射机制使用过一组Java类实现的,包括:Class, Method, Constructor以及Modifier等。
下面的一个例子展示了Java反射机制的基本概念和用法(仅仅是学习笔记)。参考文献部分列出了比较好的博客,请自行参阅。
package reflection.data;
import java.lang.reflect.*;
/**
* Created by zmz on 16/5/26.
*/
interface Person{
public void sayHello(String otherName);
}
class Student implements Person{
private String name;
private int age;
public Student(){
this.name = "";
this.age = 0;
}
public Student(String name){
this.name = name;
this.age = 0;
}
public Student(int age){
this.name = "";
this.age = age;
}
public Student(String name, int age){
this.name = name;
this.age = age;
}
@Override
public void sayHello(String otherName){
System.out.println("Hello " + otherName + "! I'm " + this.name +".");
}
public String toString(){
return "[" + this.name + ", " + this.age +"]";
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
}
public class MyTest {
public static void main(String[] args){
/****************三种获取Class对象的方法********************************/
System.out.println("****************三种获取Class对象的方法********************************");
Class<Student> c1 = Student.class; // 第一种方法
Class<?> c2;
/*
* 第二种方法:最好使用这种方式,捕获异常
*/
try{
c2 = Class.forName("reflection.data.Student");
System.out.println(c1 == c2);
}
catch (Exception e){
e.printStackTrace();
}
Student p1 = new Student("zmz", 27);
// 第三种方法:通过变量的getClass()方法获取
Class c3 = p1.getClass();
System.out.println(c1 == c3);
System.out.println("\n****************获取包名和类名********************************");
String className = p1.getClass().getName();
String simpleName = p1.getClass().getSimpleName();
System.out.println("Class.getName()获取完整的类名(包括包名): " + className); // 输出:Class.getName()获取完整的类名(包括包名): reflection.data.Student
System.out.println("Class.getSimpleName()只获取类名:" + simpleName); // 输出: Class.getSimpleName()只获取类名:Student
System.out.println("\n****************构造函数类:Constructor********************************");
Class studentClass = Student.class;
try{
// 下面这种方式调用无参构造函数,所以必须保证类具有无参的构造参数
Student tem = (Student)studentClass.newInstance();
tem.sayHello("ssy"); // 输出: Hello! I'm .
System.out.println(tem.toString()); // [, 0]
}
catch (InstantiationException e){
e.printStackTrace();
}
catch (IllegalAccessException e){
e.printStackTrace();
}
System.out.println("----------------构造函数列表-------------------");
Constructor<reflection.data.Student>[] constructors = studentClass.getConstructors(); // 获取所有的构造参数
for(int i = 0; i < constructors.length; i++){
Constructor c = constructors[i];
System.out.println("第" + i + "个构造函数");
System.out.println(" 方法名: " + c.getName()); // Constructor.getName()获取完整的类名,例如:reflection.data.Student
System.out.println(" 修饰符: " + Modifier.toString(c.getModifiers())); // Constructor.getModifiers()获取修饰符,为枚举类型,需要使用Modifier类进行转换
Class[] paramTypes = c.getParameterTypes(); // 获取参数的类型列表
for(int j = 0; j < paramTypes.length; j++){
System.out.println(" 第" + j + "个参数的类型");
System.out.println(" " + paramTypes[j].getName()); //输出: java.lang.String
}
System.out.println(" 该构造函数的完整签名: " + c); // public reflection.data.Student(java.lang.String)
}
System.out.println("----------------通过构造函数对象新建对象-------------------");
try{
Student s1 = constructors[0].newInstance("zmz", 27); // 输出: [zmz, 27]
System.out.println(s1.toString());
}
catch (Exception e){
e.printStackTrace();
}
System.out.println("\n****************返回实现的接口********************************");
Class<?> interfaces[] = Student.class.getInterfaces();
for(int i = 0; i < interfaces.length; i++){
System.out.println("第" + i + "个接口");
System.out.println(interfaces[i].getName()); // reflection.data.Person
}
System.out.println("\n****************返回父类********************************");
Class superClass = Student.class.getSuperclass();
System.out.println("父类:" + superClass.getName()); //输出: 父类:java.lang.Object
System.out.println("\n****************获取所有的方法以及方法的异常********************************");
Method methods[] = Student.class.getMethods();
for(int i = 0; i < methods.length; ++i) {
Class<?> returnType = methods[i].getReturnType(); // 方法返回类型的Class对象
Class<?> paras[] = methods[i].getParameterTypes(); // 方法的参数的Class对象数组
int temp = methods[i].getModifiers(); // 获取修饰符
System.out.print(Modifier.toString(temp) + " ");
System.out.print(returnType.getName() + " ");
System.out.print(methods[i].getName() + " ");
System.out.print("(");
for(int j=0;j<paras.length;++j){
System.out.print(paras[j].getName()+" "+"arg"+j);
if(j<paras.length-1){
System.out.print(",");
}
}
Class<?> exce[]=methods[i].getExceptionTypes(); // 获取该函数的异常
if(exce.length>0){
System.out.print(") throws ");
for(int k = 0; k < exce.length; ++k){
System.out.print(exce[k].getName()+" ");
if(k<exce.length-1){
System.out.print(",");
}
}
}else{
System.out.print(")");
}
System.out.println(); // 一个完整函数的输出例子:public final void wait (long arg0,int arg1) throws java.lang.InterruptedException
}
System.out.println("\n****************获取所有的属性********************************");
System.out.println("---本类属性------");
Field fields[] = Student.class.getDeclaredFields(); //获取本类声明的属性
for (int j = 0; j < fields.length; j++) {
int mo = fields[j].getModifiers();// 权限修饰符
String priv = Modifier.toString(mo);
Class<?> type = fields[j].getType(); // 属性类型
System.out.println(priv + " " + type.getName() + " " + fields[j].getName() + ";");
}
System.out.println("---所有的属性------");
Field fields1[] = Student.class.getDeclaredFields(); //获取本类声明的属性
for (int j = 0; j < fields1.length; j++) {
int mo = fields1[j].getModifiers();// 权限修饰符
String priv = Modifier.toString(mo);
Class<?> type = fields1[j].getType(); // 属性类型
System.out.println(priv + " " + type.getName() + " " + fields1[j].getName() + ";");
}
System.out.println("\n****************通过反射调用类的函数********************************");
try {
Class demo = Student.class;
Method method=demo.getMethod("sayHello", String.class);//调用Person类中的sayHello方法
method.invoke(demo.newInstance(), "ssy");
Method method2 = demo.getMethod("toString");
System.out.println(method2.invoke(demo.newInstance()));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("-----调用set方法--------------");
Student s1 = new Student();
try{
Method setNameMethod = Student.class.getMethod("setName", String.class);
setNameMethod.invoke(s1, "zmz");
}
catch (Exception e){
e.printStackTrace();
}
System.out.println("-----调用get方法--------------");
try{
Method getNameMethod = s1.getClass().getMethod("getName");
System.out.println(getNameMethod.invoke(s1)); //输出: zmz
}
catch (Exception e){
e.printStackTrace();
}
System.out.println("\n****************通过反射操作属性********************************");
Student s2 = new Student("ssy", 28);
System.out.println(s2.toString()); //输出: [ssy, 28]
try{
Field ageField = s2.getClass().getDeclaredField("age"); // getDeclaredField()返回所有的属性,getFields()返回所有可访问的公共字段
ageField.setAccessible(true); // 私有变量可以访问
ageField.set(s2, 29);
System.out.println(s2); // 输出: [ssy, 29]
}
catch (Exception e){
e.printStackTrace();
}
System.out.println("\n****************通过反射修改数组的信息********************************");
int[] temp = {1,2,3,4,5};
Class<?> demo = temp.getClass().getComponentType();
System.out.println("数组元素类型: " + demo.getName()); // int
System.out.println("数组长度 " + Array.getLength(temp));
System.out.println("数组的第一个元素: "+Array.get(temp, 0));
Array.set(temp, 0, 100);
System.out.println("修改之后数组第一个元素为: " + Array.get(temp, 0));
/**
* 其实在java中有三种类类加载器。
1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
*/
System.out.println("\n****************获取类加载器********************************");
System.out.println(Student.class.getClassLoader().getClass().getName()); // sun.misc.Launcher$AppClassLoader
}
}
----EOF-----