反射指程序可以访问、检测和修改它本身状态或行为的一种能力。反射使程序的代码能够得到装载到Java 虚拟机中的类的内部信息。本章将详细介绍 Java 的反射机制,主要内容包括 java.lang.reflect 包提供的Class 类、 Constructor 类、 Method 类、 Field 类和 Array 类等,以及ParameterizedType 接口如何获取泛型类、泛型方法的信息。*
通过 Java 的反射机制, 程序员可以方便、 灵活地创建代码, 这些代码可以在运行时进行装配, 在程序运行过程中可以动态地扩展程序。
Java 的反射机制主要有以下功能:
Java 提供的反射所需要的类主要有 java.lang.Class 类和 java.lang.reflect 包中的 Field 类、 Constructor 类、Method 类和 Array 类等。
1. 测试代码一获取反射类的对象(三种方式):
package test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Constructor;
import java.lang.reflect.Parameter;
public class Classtest1 {
public static void main(String[] args) throws ClassNotFoundException {
Object obj = new Object();
Class c1 = obj.getClass();
try{
Class c2 = Class.forName("java.util.Date");//获取Class对象的三种方法
Class c3 = Integer.class;
System.out.println(c2);
Package p = c2.getPackage();
System.out.println("Date类包名信息"+p);
int m = c2.getModifiers();//获取类的修饰符
String str = Modifier.toString(m);//强制类型转换修饰符
System.out.println("Date的类修饰符"+str);
System.out.println("Date的类名"+c2.getName());
Field[]f = c2.getDeclaredFields();//获取Date类的字段
System.out.println("foreach循环输出Date类的字段名");
for(Field field : f){
System.out.print(field.getName()+" ");
}
System.out.println();
Constructor[]con = c2.getConstructors();//获取Date的构造方法
System.out.println("循环输出Date类的构造方法信息");
for(Constructor cc : con){
System.out.print(cc.getName()+"的修饰符:"+Modifier.toString(cc.getModifiers()));
System.out.println();
Parameter[] ps = cc.getParameters();//获取构造方法中的参数
System.out.println(cc.getName()+"的参数");
for(Parameter pp : ps){//嵌套的foreach循环
System.out.print(pp.getName()+" ");
}
System.out.println();
}
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
}
运行结果:
class java.util.Date
Date类包名信息package java.util, Java Platform API Specification, version 1.8
Date的类修饰符public
Date的类名java.util.Date
foreach循环输出Date类的字段名
gcal jcal fastTime cdate defaultCenturyStart serialVersionUID wtb ttb
循环输出Date类的构造方法信息
java.util.Date的修饰符:public
java.util.Date的参数
arg0 arg1 arg2 arg3 arg4 arg5
java.util.Date的修饰符:public
java.util.Date的参数
arg0
java.util.Date的修饰符:public
java.util.Date的参数
java.util.Date的修饰符:public
java.util.Date的参数
arg0
java.util.Date的修饰符:public
java.util.Date的参数
arg0 arg1 arg2
java.util.Date的修饰符:public
java.util.Date的参数
arg0 arg1 arg2 arg3 arg4
2. 测试代码二有参和无参的构造方法:
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Classtest2 {
public static void main(String[] args) {
try {
Class c1 = Class.forName("java.util.Date");
c1.newInstance();//在程序运行中才新建类的对象并且要捕捉空值的异常(无参数构造方法)
System.out.println(c1.newInstance());
Class c2 = Class.forName("java.lang.Integer");
//第一步,通过Class类对象c2
Constructor construct = c2.getConstructor(int.class);
//第二步,通过Class类对象c2的方法getConstruct()方法获得指定符合参数类型的构造方法
Integer in = (Integer)construct.newInstance(2341324);
//第三步,通过Constructor类对象construct的newInstrance()方法传入参数,创建对象(有参构造方法)
System.out.println(in);
} catch (Exception e) {//
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
Wed Nov 20 21:03:13 CST 2019
2341324
3. 测试代码三
java.lang.reflect包中Construct类,Method类,Field类的方法
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
public class ReflectTest1 {
public static void main(String[] args) {
try {
Class obj = Class.forName("test.Computer");//获取一个表示Computer的Class类的对象
Constructor constructor[] = obj.getConstructors();//获取Computer类中的构造方法
System.out.println("Computer类中的构造方法:");
for(Constructor con : constructor)//将构造方法输出
System.out.println(con.toString());
System.out.println();
Field field[] = obj.getDeclaredFields();//获取Computer中的所有域
System.out.println("Computer类中的域:");
for(Field f : field)
System.out.println(f.toString());
System.out.println();
Method method[] = obj.getMethods();//获取Computer类中的所有方法
System.out.println("Computer类中的方法:");
for(Method m : method)
System.out.println(m.toString());
System.out.println();
Computer myComputer = new Computer(2.5,4,450,"Inter");//声明一个对象
Computer aComputer = (Computer) duplicate(myComputer);// 复制一个对象
System.out.println("复制后的对象:");
System.out.println(aComputer.toString());//输出复制后的对象
} catch (Exception e) {//用try—catch抛出反射信息中的所有异常
e.printStackTrace();
}
}
private static Object duplicate(Object source) throws Exception {
Class classObj = source.getClass();//由对象source获得对应的Class对象
Field [] sourceFields = classObj.getDeclaredFields();//获得source类对象所在类中的所有域
Object target = classObj.newInstance();//利用classObj.newInstrance()方法获得一个新对象
for(Field sourceField : sourceFields){//将source对象的域值赋给新对象对应的域
sourceField.setAccessible(true);//设置域可访问true
sourceField.set(target, sourceField.get(source));
}
return target;
}
}
class Computer{//电脑类
private double frequency = 2.0;
private int RAM = 4;
private int HardDisk = 500;
private String CPU = "Inter";
public Computer(){//无参数构造方法
}
public Computer(double frequency,int RAM,int HardDisk,String CPU){//有参构造方法
this.frequency = frequency;
this.RAM = RAM;
this.HardDisk = HardDisk;
this.CPU = CPU;
}
// 为了能实现复制,下面的方法需按Bean 规则写,即setter 或getter
public void setFrequency(double frequency){
this.frequency = frequency;
}
public double getFrequency(){
return frequency;
}
public void setRAM(int RAM) {
this.RAM = RAM;
}
public int getRAM() {
return RAM;
}
public void setHardDisk(int HardDisk) {
this.HardDisk = HardDisk;
}
public int getHardDisk() {
return HardDisk;
}
public void setCPU(String CPU) {
this.CPU = CPU;
}
public String getCPU() {
return CPU;
}
public String toString(){
String ss = "主频:" + frequency + "MHz 内存:" + RAM + "GB 硬盘:" + HardDisk + "GB CPU:" + CPU;
return ss;
}
}
运行结果:
Computer类中的构造方法:
public test.Computer()
public test.Computer(double,int,int,java.lang.String)
Computer类中的域:
private double test.Computer.frequency
private int test.Computer.RAM
private int test.Computer.HardDisk
private java.lang.String test.Computer.CPU
Computer类中的方法:
public java.lang.String test.Computer.toString()
public void test.Computer.setHardDisk(int)
public double test.Computer.getFrequency()
public void test.Computer.setRAM(int)
public void test.Computer.setFrequency(double)
public java.lang.String test.Computer.getCPU()
public void test.Computer.setCPU(java.lang.String)
public int test.Computer.getHardDisk()
public int test.Computer.getRAM()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
复制后的对象:
主频:2.5MHz 内存:4GB 硬盘:450GB CPU:Inter
4. 测试代码四数组类
java.lang.reflect 包中 Array 类提供了使用反射动态创建和访问 Java 数组的方法。 数组作为一个对象,
可以通过反射来查看其各个属性信息以及类型名
package test;
import java.lang.reflect.Array;
public class ReflectTest2 {
public static void main(String[] args) {
int[]array = new int[10];
Class c1 = array.getClass();//获得整数数组Class类对象c1
System.out.println("int数组的类型名:"+c1.getName());
Class c2 = c1.getComponentType();//获得数组类型的Class对象c2
System.out.println("int数组的类名:"+c2.getName());
Object obj = Array.newInstance(int.class, 10);//使用Array类动态创建数组obj
for(int i=0;i<10;i++){//对数组进行赋值
Array.setInt(obj, i, i*10);
}
System.out.println("数组元素值:");
for(int i=0;i<10;i++){//获得数组值
System.out.print(Array.getInt(obj, i)+" ");
}
}
}
运行结果:
int数组的类型名:[I
int数组的类名:int
数组元素值:
0 10 20 30 40 50 60 70 80 90