Java反射机制(Reflection)
一、反射机制是什么
Java反射机制是程序在运行过程中,对于任意一个类都能够知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意一个方法和属性,这种动态获取类信息以及动态调用对象方法的功能就是JAVA语言的反射机制。
二、反射机制能干什么
(1)在运行时判断任意一个对象所属的类
(2)在运行时构造任意一个类的对象
(3)在运行时判断任意一个类所具有的成员变量和方法
(4)在运行时调用任意一个对象的方法
(PS:注意反射机制都是在程序运行时,而不是在编译时。)
反射机制允许程序在运行时透过JDK提供的反射API获取任意一个已知名称的class的内部消息,包括: 修饰符、父类、接口、属性、构造方法、方法 等所有的信息,并可在程序运行时改变属性的值或者调用方法。
三、JDK提供的反射机制中的类
在JDK中主要由以下类来实现Java的反射机制,这些类都位于java.lang.reflect包中(Class类除外):
java.lang.Class: 代表一个类
java.lang.reflect.Constructor:代表类的构造方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Modifier:代表修饰符
java.lang.reflect.Array:提供动态创建数组,以及访问数组的元素的静态方法
四、利用示例对反射机制的使用进行初步体会
示例一:
利用反射机制打印java.lang.String类中所有的属性、构造方法、方法
/**
*利用反射机制打印String类中的所方法信息
* @author Administrator
*
*/
public class ObjectReflectDemo {
public static void main(String[] args) throws Exception {
//反射的第一步是获取要操作的类所对应的Class对象
Class<?> cls = Class.forName("java.lang.String");
System.out.println("---------String类中的属性:---------------------"); Field[] fields = cls.getDeclaredFields();
for(Field f : fields){
System.out.println(f);
}
System.out.println("---------String类中的构造方法:--------------------");
Constructor[] contructors = cls.getDeclaredConstructors();
for(Constructor c : contructors){
System.out.println(c);
}
System.out.println("---------String类中的方法:---------------------");
Method[] methods = cls.getDeclaredMethods();
for(Method m : methods){
System.out.println(m);
}
}
}
运行结果:
---------String类中的属性:---------------------
private final char[] java.lang.String.value
private int java.lang.String.hash
private static final long java.lang.String.serialVersionUID
private static final java.io.ObjectStreamField[] java.lang.String.serialPersistentFields
public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER
private static final int java.lang.String.HASHING_SEED
private transient int java.lang.String.hash32
---------String类中的构造方法:--------------------
public java.lang.String(byte[])
public java.lang.String(byte[],int,int)
public java.lang.String(byte[],java.nio.charset.Charset)
public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int,int,java.nio.charset.Charset)
java.lang.String(int,int,char[])
java.lang.String(char[],boolean)
public java.lang.String(java.lang.StringBuilder)
public java.lang.String(java.lang.StringBuffer)
public java.lang.String(int[],int,int)
public java.lang.String(char[],int,int)
public java.lang.String(char[])
public java.lang.String(java.lang.String)
public java.lang.String()
public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int)
public java.lang.String(byte[],int,int,int)
---------String类中的方法:---------------------
public boolean java.lang.String.equals(java.lang.Object)
public java.lang.String java.lang.String.toString()
public int java.lang.String.hashCode()
public int java.lang.String.compareTo(java.lang.String)
public int java.lang.String.compareTo(java.lang.Object)
public int java.lang.String.indexOf(int)
public int java.lang.String.indexOf(java.lang.String,int)
public int java.lang.String.indexOf(java.lang.String)
public int java.lang.String.indexOf(int,int)
static int java.lang.String.indexOf(char[],int,int,char[],int,int,int)
public static java.lang.String java.lang.String.valueOf(double)
public static java.lang.String java.lang.String.valueOf(char[],int,int)
public static java.lang.String java.lang.String.valueOf(float)
public static java.lang.String java.lang.String.valueOf(java.lang.Object)
public static java.lang.String java.lang.String.valueOf(long)
public static java.lang.String java.lang.String.valueOf(char[])
public static java.lang.String java.lang.String.valueOf(boolean)
public static java.lang.String java.lang.String.valueOf(char)
public static java.lang.String java.lang.String.valueOf(int)
public char java.lang.String.charAt(int)
private static void java.lang.String.checkBounds(byte[],int,int)
public int java.lang.String.codePointAt(int)
public java.lang.String java.lang.String.concat(java.lang.String)
public boolean java.lang.String.contains(java.lang.CharSequence)
public static java.lang.String java.lang.String.copyValueOf(char[])
public static java.lang.String java.lang.String.copyValueOf(char[],int,int)
public boolean java.lang.String.endsWith(java.lang.String)
public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[])
public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[])
public byte[] java.lang.String.getBytes()
public byte[] java.lang.String.getBytes(java.nio.charset.Charset)
public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException
public void java.lang.String.getBytes(int,int,byte[],int)
public void java.lang.String.getChars(int,int,char[],int)
void java.lang.String.getChars(char[],int)
public int java.lang.String.codePointBefore(int)
public int java.lang.String.codePointCount(int,int)
public int java.lang.String.compareToIgnoreCase(java.lang.String)
public boolean java.lang.String.contentEquals(java.lang.CharSequence)
public boolean java.lang.String.contentEquals(java.lang.StringBuffer)
public boolean java.lang.String.equalsIgnoreCase(java.lang.String)
private int java.lang.String.indexOfSupplementary(int,int)
private int java.lang.String.lastIndexOfSupplementary(int,int)
public int java.lang.String.offsetByCodePoints(int,int)
int java.lang.String.hash32()
public native java.lang.String java.lang.String.intern()
public boolean java.lang.String.isEmpty()
public int java.lang.String.lastIndexOf(java.lang.String,int)
static int java.lang.String.lastIndexOf(char[],int,int,char[],int,int,int)
public int java.lang.String.lastIndexOf(int,int)
public int java.lang.String.lastIndexOf(int)
public int java.lang.String.lastIndexOf(java.lang.String)
public int java.lang.String.length()
public boolean java.lang.String.matches(java.lang.String)
public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence)
public java.lang.String java.lang.String.replace(char,char)
public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String)
public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String)
public java.lang.String[] java.lang.String.split(java.lang.String,int)
public java.lang.String[] java.lang.String.split(java.lang.String)
public boolean java.lang.String.startsWith(java.lang.String)
public boolean java.lang.String.startsWith(java.lang.String,int)
public java.lang.CharSequence java.lang.String.subSequence(int,int)
public java.lang.String java.lang.String.substring(int)
public java.lang.String java.lang.String.substring(int,int)
public char[] java.lang.String.toCharArray()
public java.lang.String java.lang.String.toLowerCase(java.util.Locale)
public java.lang.String java.lang.String.toLowerCase()
public java.lang.String java.lang.String.toUpperCase(java.util.Locale)
public java.lang.String java.lang.String.toUpperCase()
public java.lang.String java.lang.String.trim()
public boolean java.lang.String.regionMatches(int,java.lang.String,int,int)
public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int)
从上面示例中可以看出,要想使用反射的第一步就是获取要操作类所对应的Class对象,一共有三种方法:
第一种: 调用Class类的静态方法forName,比如 Class.forName("java.lang.String")
第二种: 使用类的.class语法,比如 : Class cls = String.class
第三种: 调用对象的getClass方法, 比如:String str = "123"; Class cls = str.getClass();(PS:在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型)
示例二:
import java.lang.reflect.Field;
import java.lang.reflect.Method; /**
* 要求:
* 1.通过反射的方式调用add方法
* 2.通过反射的方式调用getNum方法
* 3.通过反射的反射修改num属性的值为55,再通过反射的方式调用getNum方法
* @author Administrator
*
*/
public class ReflectTest {
private int num = 2; public int add(int a,int b){
return a+b;
} public int getNum() {
return num;
} public static void main(String[] args) throws Exception {
//第一步: 获取ReflectTest类所对应的Class对象
Class<?> cls = Class.forName("ReflectTest");
//第二步:通过Class类的newInstance()方法来创建ReflectTest类的一个对象
Object obj = cls.newInstance(); //第步:通过Class的getDeclaredMethod(String name, Class<?>... parameterTypes)获取ReflectTest类中指定的方法
Method addMethod = cls.getDeclaredMethod("add", new Class[]{int.class,int.class});
Method getNumMethod = cls.getDeclaredMethod("getNum", new Class[]{}); //第四部:通过Method类的invoke(Object obj, Object... args)方法来反射调用ReflectTest类中指定的方法
//4.1通过反射调用add方法
int addResult = (int)addMethod.invoke(obj, new Object[]{11,22});
System.out.println("addResult = " + addResult); //4.2通过反射的方式调用getNum方法
int returnNum1 = (int)getNumMethod.invoke(obj, new Object[]{});
System.out.println("returnNum1 = " + returnNum1); //4.3通过反射的反射修改num属性的值为55,再通过反射的方式调用getNum方法
Field field = cls.getDeclaredField("num");
field.set(obj, 55);
int returnNum2 = (int)getNumMethod.invoke(obj, new Object[]{});
System.out.println("returnNum2 = " + returnNum2);
}
}
通过上面的2个示例,可以看出:
(1)反射的第一步是获取要操作的类所对应的Class对象(有三种方式)
(2)类中每一个方法对应着一个java.lang.reflect.Method对象
(3)类中每一个属性对应着一个java.lang.reflect.Field对象
五、使用java反射机制,需要遵循的三步
第一步:获取要操作的类所对应的Class对象,得到该Class对象后就可以获取想要操作类的所有信息。(具体参考java.lang.Class API)
第二步: 通过Class对象去获取操作类的属性、构造方法、方法 所分别对应的Field、Constructor、Method的对象
第三步: 调用Field、Constructor、Method对象中的方法