在Java中我们经常说”everything is object”即万物皆对象,其实万物皆对象是面向对象的思想,和具体的语言没有太大关系,但是Java作为一种面向对象的语言却毫无疑问的将这种思想发扬光大了。从Java的反射特性的角度去理解似乎更加深刻。
什么是反射,Java反射的特性,又有什么用途呢?反射主要是用于一些Java的组件开发中比如一些流行的框架Spring,Hibernate等。由于反射特性在一般的开发中很少用到,所以大多数的Java入门书籍都鲜有提及,其实我也是最近才有打算系统的了解一下Java的反射特性,其实工作中也只有在极少数的情况下使用(当然工作中所用到过的框架中含有的不算),关于反射我特别查看了一下官方JDK文档上的说法,由于是英文,担心翻译会有问题,误导大家,现把原文贴出,然后再说说我的理解。
Reflectionis commonly used by programs which require the ability to examine ormodify the runtime behavior of applications running in the Javavirtual machine. This is a relatively advanced feature and should beused only by developers who have a strong grasp of the fundamentalsof the language. With that caveat in mind, reflection is a powerfultechnique and can enable applications to perform operations whichwould otherwise be impossible.
在Java的反射机制中,较多的会提到“字节码”的概念,描述起来不太容易,其实也容易理解举个例子:字符串或日期在Java中可以用String或Date的对象来进行描述,但这里缺少一个基础,我们说万物皆对象,那么对于String或Date以及其他的一些类型包括基本的数据类型它们又是谁的对象。在Java中就定义了一个叫做Class的类,这个类的对象就是Java中其他的那些所有类,也称为“字节码”,如果按照这样理解就会有一种比较搞笑的事情出现,就是会不会存在Class clazz = String这种表达式呢。这样的写法在情理上似乎是通的,但是Java并没有允许这么干。而是提供了别的途径来获取字节码。总的来说有三种:
/**
* Class不存在构造方法所以无法通过构造方法进行获取
* * 通过class属性获取,最简单的
*
* * 运行时沟通类对象的getClass获取
*
* * 大家比较熟悉的方式,在JDBC编程中都使用过的
* 也是经常会使用到的
* 使用Class.forName获取,这种方式要注意传入
* 的参数应该是类的全路径
* */
// 使用class属性获取
Class<String> strClazz = String.class;// 普通类型
Class<String[]> strsClazz = String[].class;// 数组
Class intClazz = int.class;// 基本数据类型
Class listClazz = ArrayList.class;// 集合类型
// 使用getClass方法获取
String str = new String();
Class<String> strobj = (Class<String>) str.getClass();
String[] strs = new String[0];
Class<String[]> strsobj = (Class<String[]>) strs.getClass();
// 使用Class.forName
Class<String> strClazz1 = (Class<String>) Class.forName("java.lang.String");
Class<ArrayList> arrayListClazz1 = (Class<ArrayList>) Class.forName("java.util.ArrayList");
其实到这里可能仍会有童鞋继续追问这Class说到底也还是个类,它又是谁的对象呢,这个问题这么延续下去将会变成了“鸡和蛋”终极问答,其实上面的注释也写类Class是一个特殊的类它没构造方法。其实以下的代码都是可行的:
Class clazz = Class.forName("java.lang.Class");
System.out.println(clazz);// class java.lang.Class
Class clazz1 = Class.class;
System.out.println(clazz == clazz1); //true
Java规定所有的类型的字节码在Java的虚拟机中只会存在一份,即同一类的不同对象它的字节码会是相同的。
String str1 = new String("aaa");
String str2 = new String("bbb");
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
System.out.println(str1.getClass() == str2.getClass());//true
反射机制也是Java被视为动态语言的重要表现。通过Java反射的API可以获取程序在运行时刻的内部结构,可以遍历出来一个Java类的内部结构,包括其中的构造方法(Construct)、声明的域(Field)和定义的方法(Method)等同时可以操作这些属性和方法,这是很强大的,也是很恐怖的。这种特性甚至已经与Java语法中的定义的某些规则相冲突,比如使用反射来调用对象的属性或方法时完全都不用再顾忌什么共有(public)或私有(private)的概念了。
下面的程序使用Java反射部分API获取类的构造方法,类中的方法,以及属性
定义普通的Person类
package pz.soft.chen.reflect;
public class Person {
private int age = 22;
public String name;
protected String sex;
private Person(){}
protected Person(String name, String sex){
this.name = name;
this.sex = name;
}
public Person(int age, String name, String sex){
this.age = age;
this.name = name;
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
private void display(){
System.out.println("name: " +name +" age: "+age +" sex: "+sex);
}
public void show(){
display();
}
}
测试所用类:
package pz.soft.chen.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test1 {
public static void main (String[] args) throws Exception {
getConsductors();
System.out.println("############################################################");
getMethods();
System.out.println("############################################################");
getFields();
}
@SuppressWarnings("unchecked")
private static void getConsductors() throws Exception {
Class<Person> perClazz = (Class<Person>) Class.forName("pz.soft.chen.reflect.Person");
/**
* 获取Person类所有构造的方法包括共有,私有,受保护类型
* getDeclaredConstructors
* */
Constructor<Person>[] constructors = (Constructor<Person>[]) perClazz.getDeclaredConstructors();
for(Constructor<Person> cs: constructors){
System.out.println(cs);
}
System.out.println("===========================================================");
/**
* 获取Person类所有构造的方法,只能获取共有的
* getConstructors
* */
constructors = (Constructor<Person>[]) perClazz.getConstructors();
for(Constructor<Person> cs: constructors){
System.out.println(cs);
}
// 也可获取指定的构造方法
}
private static void getMethods(){
Class<Person> perClazz = Person.class;
// 获取子类及父类所有的public方法
Method[] methods = perClazz.getMethods();
for(Method m: methods){
System.out.println(m);
}
System.out.println("===========================================================");
// 获取当前类的所有方法包括public,private,protected
methods = perClazz.getDeclaredMethods();
for(Method m: methods){
System.out.println(m);
}
}
private static void getFields(){
Class<Person> perClazz = Person.class;
Field[] fields = perClazz.getFields();
for(Field f: fields){
System.out.println(f);
}
System.out.println("===========================================================");
fields = perClazz.getDeclaredFields();
for(Field f: fields){
System.out.println(f);
}
}
}