java反射机制就是在程序运行时能够动态地获取类的各种信息(方法、属性等)的方法,即对任意的一个类,通过反射机制都能知道它的所有属性和方法,并能生成该类对应的实例;对于任何一个对象都能查看并调用它的任何方法等。
运用反射机制时需要一个很重要的类是Class类,这是在类加载完成以后由JVM自动生成的一个对象(类加载过程:虚拟机将外部二进制字节流按照虚拟机所需的格式存储在方法区之中,方法区中的数据存储格式由虚拟机实现自行定义,然后在内存中实例化一个java.lang.Class类的对象,该Class对象记录着该类的字段、方法等信息,因此它将作为程序访问方法区中的这些类型数据的外部接口)。在生成某个类的实例时,都会存储这个对象所对应的Class对象,以后在调用该对象的“getClass()”方法时就能返回相应的Class对象,也就知道某个对象是哪个类的实例(即使用父类引用指向子类对象时,也能用getClass()方法返回其真正的子类名称)。
实质:运行时通过JVM自动生成的各类的独一无二的Class对象来获取类的信息的手段,即在编译时可以不知道所用类的类型,在运行时才动态载入(可以由用户在程序运行时输入需要的类)并自审以知道其所有成员变量和方法。
作用:1.运行时判断任意对象所属的类;
2.运行时构造出任意类的对象;
3.运行时获取任意类的方法或属性;
4.运行时调用任意对象的方法;
5.生成动态代理;
一. 获取Class对象的三种方法:
//编译后生成RefClass.class字节码文件备用
public class RefClass {
/*类的方法和属性*/
}
1. 运用已知对象的“getClass()”方法,例如:
public class GetClassTest {
/*类的方法和属性*/
public static void get() {
GetClassTest test = new GetClassTest();
Class class = test.getClass();//可以返回<span style="font-family: Arial, Helvetica, sans-serif;">GetClassTest类的Class对象;</span>
}
}
2. Class.forName("类名"),例如:
public class ForNameTest {
/*类的方法和属性*/
public static void get() {
Class class = Class.forName("包名.RefClass");//加载RefClass类,生成对应的Class对象,并对RefClass类进行初始化;
}
}
3. 类名.class,例如:
public class ClassTest {
/*类的方法和属性*/
public static void get() {
Class class = RefClass.class;//加载RefClass类,生成对应的Class对象,但是并不对RefClass类进行初始化;
}
}
二. 反射机制的应用例子
1. 在JDBC编程中,在加载数据库驱动时运用到反射机制;
Class.forName("com.mysql.jdbc.Driver")加载驱动类,并将Driver类实例注册到DriverManager类中。
2. 在工厂设计模式下的运用;
接口及其实现类:
interface Fruit {
public void say();
}
class Apple implements Fruit {
public void say() {
System.out.println("I am an Apple !");
}
}
class Orange implements Fruit {
public void say() {
System.out.println("I am a Orange !");
}
}
普通的工厂类如下:
public class FruitFactory {
public static Fruit getFruit(String name) throws Exception {
if(name.equals("apple")) {
return new Apple();
}
else if(name.equals("orange")) {
return new Orange();
}//当需要增加子类类型时就需要更改工厂类实现,加入对个"else if"语句,十分的不方便;
else {
throw new Exception("No that fruit !");
}
}
public static void main(String[] args) throws Exception {
getFruit("apple").say();
}
}
利用反射机制改进工厂类的实现:
public class FruitFactory {
public static Fruit getFruit(String name) {
Fruit fruit = null;
try {
fruit = (Fruit)Class.forName(name).newInstance();//当加入子类类型时不需要更改工厂类的实现方式。
} catch(Exception e) {
e.printStackTrace();
}
return fruit;
}
public static void main(String[] args) {
getFruit("Apple").say();
}
}//getFruit方法中的name参数必须是类的全限定名,因此可以运用属性文件(properties)来加载,会简化一点;
3. 访问不能访问的成员变量等;
4. 获取类的方法、成员变量;