在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能为Java语言的反射机制。
1.2 反射的应用场合程序在运行时可能接受到外部传入的对象,该对象的编译时类型为Object,但是程序有需要改对象的运行时类型的方法。
为了解决这些问题,程序需要在运行时发现对象和类的真实信息。
如果编译时根本无法预知该对象和类属于哪些类,比如这些类都是以字符串形式存放在配置文件中的时候,程序只能依靠运行时信息来发现该对象和类的真实信息,此时必须使用反射了。
① 获取想要操作的类的Class对象,他是反射的核心,通过Class对象我们可以任意调用类的方法;
② 调用Class类中的方法,即就是反射的使用阶段;
③ 使用反射API来操作这些信息。
位置:java.lang.Class
类对象,类的实例代表一个运行 类 java应用程序的类和接口。public final class Class
extends Object
implements Serializable, GenericDeclaration, Type, AnnotatedElement
2.1 常用方法和示例
常用方法:
String getName()
返回由 类对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String 。
static Class forName(String className)
获取类对象名
Package getPackage()
获取类对象的包名
Class getSuperclass()
获取父类的类对象名
Class[] getInterfaces()
获取接口的类对象名
Constructor[] getConstructors()
获取构造方法
Class[] getParameterTypes()
获取方法(构造/成员)的参数类型列表
Field[] getFields()
获取属性(自身+父类的所有public公开属性)
Field[] getDeclaredFields()
获取属性(自身所有的属性)
Method[] getMethods()
获取方法(自身+父类单继承叠加的所有public公开方法)
Method[] getDeclaredMethods()
获取方法(自身所有的方法)
T newInstance()
创建由此类对象表示的类的新实例(此类对象必须有无参构造)。
方法使用示例:
public class TestClassMethods {
public static void main(String[] args) throws Exception {
// 获取类对象
Class c = Class.forName("com.day.methods.Student");
System.out.println(c.getName()); // com.day.methods.Student
// 获得指定类对象的包名
Package pack = c.getPackage();
System.out.println(pack.getName()); // com.day.methods
// 获得父类的类对象
Class superClass = c.getSuperclass();
System.out.println(superClass.getName()); // com.day.methods.Person
// 获得接口的类对象
Class[] interfaces = c.getInterfaces();
for (Class inter : interfaces) {
// java.io.Serializable java.lang.Runnable java.lang.Comparable
System.out.print(inter.getName() + " ");
}
// 获取属性(自身+父类的public公开属性)
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.print(field.getName() + " "); // name age name money
}
// 获取属性(自身所有的属性)
Field[] fields2 = c.getDeclaredFields();
for (Field field : fields2) {
System.out.print(field.getName() + " "); // name age score
}
System.out.println("\n---------------------");
// 获取方法(自身+父类单继承叠加的所有public公开方法)
Method[] methods = c.getMethods();
for (Method method : methods) {
// run compareTo exam play sleep eat wait wait wait equals toString hashCode getClass notify notifyAll
System.out.print(method.getName() + " ");
}
System.out.println("\n---------------------");
// 获取方法(自身所有的方法)
Method[] methods2 = c.getDeclaredMethods();
for (Method method : methods2) {
// run:void compareTo:int play:void exam:void
System.out.println(method.getName() + ":" + method.getReturnType());
}
System.out.println("*************************");
// 获取构造方法
Constructor[] cs = c.getConstructors();
for (Constructor cc : cs) {
// com.day.methods.Student:java.lang.String int
// com.day.methods.Student:java.lang.String
// com.day.methods.Student: (无参构造)
System.out.print(cc.getName() + ":");
Class[] param = cc.getParameterTypes();
for (Class p : param) {
System.out.print(p.getName() + " ");
}
System.out.println();
}
System.out.println();
// new一个实例对象(必须要有无参构造)
Object o = c.newInstance();
Student stu = (Student)o;
System.out.println(stu); // com.day.methods.Student@3d4eac69
}
}
class Person {
public String name;
public double money;
public Person() {}
public void eat() {}
public void sleep() {}
}
@SuppressWarnings({ "serial", "rawtypes" })
class Student extends Person implements Serializable, Runnable, Comparable{
public String name;
public int age;
double score;
public Student() {super();}
public Student(String name) {}
public Student(String name, int age) {}
public void exam() {}
public void play() {}
@Override
public void run() {}
@Override
public int compareTo(Object o) { return 0; }
}
2.2 获取Class对象的 3 种方法
① 通过类的对象,获取Class对象
② 通过类名获取一个Class对象
③ 通过Class的静态方法forName()获取类对象 【最具普适性】
public class TestGetClassObject {
public static void main(String[] args) throws ClassNotFoundException {
// 1.通过类的对象,获取Class对象
Person p = new Person(); // 类的对象
Class c = p.getClass();
System.out.println(c.getName());
// 2.通过类名获取一个Class对象
Class c2 = Person.class;
System.out.println(c2.getName());
// 3.通过Class的静态方法获取类对象 【最具普适性】
Class c3 = Class.forName("com.day.reflect.Person");
System.out.println(c3.getName());
}
// 更通用的获取类对象的方法
public static Class getClassObject(String className) {
Class c = null;
try {
c = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return c;
}
}
class Person {
}
2.3 反射创建对象的 2 种方法
① 反射通过类对象创建类的对象
② 方法传参返回对象【普适性】
public class TestNewInstance {
public static void main(String[] args) throws Exception {
// 手工new对象
Teacher t = new Teacher();
t.name = "JJ";
System.out.println(t.name);
// 1.反射通过类对象创建类的对象
Class c = Class.forName("com.day.methods.Teacher");
Teacher t2 = (Teacher)c.newInstance();
t2.name = "Jerry";
System.out.println(t2.name);
// 2.方法传参返回对象【普适性】
Teacher t3 = (Teacher)createObject("com.day.methods.Teacher");
System.out.println(t3);
}
public static Object createObject(String className) {
try {
Class c = Class.forName(className);
return c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
class Teacher {
String name;
public Teacher() { }
}
3. 工厂设计模式(示例)
开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭;
工厂模式主要负责对象创建的问题;
可通过反射进行工厂模式的设计,完成动态的对象创建。
public class TestNewInstanceForFile {
public static void main(String[] args) throws Exception {
// 创建出入流对象
FileReader fr = new FileReader("files\\application.txt");
BufferedReader br = new BufferedReader(fr);
// 读出文件中的类的全限定名
String className = br.readLine();
// 创建Object对象返回后进行强转为对应类型,进而使用
Teacher t3 = (Teacher)createObject(className);
System.out.println(t3);
br.close();
}
/**
* 工厂:创建对象工厂
* @param className String类型的类的全限定名
* @return Object Object类型的对象
*/
public static Object createObject(String className) {
try {
Class c = Class.forName(className);
return c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
/*
* files\\application.txt 内容:
* com.methods.Teacher
*/