要点
- java反射机制
- 反射机制的功能
- Class类
- 方法反射
- 反射机制的应用
java反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射机制的功能
主要是动态处理类
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
- 生成动态代理。
Class类
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。 Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
1、在java中,除了静态的成员、普通数据类型,其他的都是对象
2、class也是一个对象,是java.lang.Class类的实例对象
3、任何一个类都是Class的实例对象
//Food的实例对象是foo1
Food foo1 = new Food();
//Food这个类 是Class类的实例对象,这个实例对象有三种表示方式
//第一种表示方式(任何一个类都有一个隐含的静态成员变量class)
Class c1 = Food.class;
//第二中表达方式 已经知道该类的对象通过getClass方法
Class c2 = foo1.getClass();
//第三种表达方式
Class c3 = null;
try {
c3 = Class.forName("test.reflect.Food");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 实例对象c1 ,c2,c3 表示了Food类的类类型(class type)
//不管c1 or c2都代表了Food类的类类型,一个类只可能是Class类的一个实例对象
//c1 == c2 的结果是true
Class c = obj.getClass();
/*
* 类的成员变量也是对象
* java.lang.reflect.Field
* Field类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields获取的是该类自己声明的成员变量的信息
*/
//Field[] fs = c1.getFields();
Field[] fs = c1.getDeclaredFields();
for (Field field : fs) {
//得到成员变量的类型的类类型
Class fieldType = field.getType();
String typeName = fieldType.getName();
//得到成员变量的名称
String fieldName = field.getName();
System.out.println(typeName+" "+fieldName);
}
/*
* 构造函数也是对象
* java.lang. Constructor中封装了构造函数的信息
* getConstructors获取所有的public的构造函数
* getDeclaredConstructors得到所有的构造函数
*/
//Constructor[] cs = c.getConstructors();
Constructor[] cs = c.getDeclaredConstructors();
for (Constructor constructor : cs) {
System.out.print(constructor.getName()+"(");
//获取构造函数的参数列表--->得到的是参数列表的类类型
Class[] paramTypes = constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName()+",");
}
System.out.println(")");
方法反射
- 方法的名称和方法的参数列表才能唯一决定某个方法
- 方法反射的操作 method.invoke(对象,参数列表)
补充:编译和运行是两个不同的操作,先编译才可以运行,编译过程会进行静态加载类,实际开发中一些功能性的类应使用动态加载,从而使我们的项目健壮性更好,不会因为一个类出错而导致整个项目不能运行
//要获取print(int ,int )方法 1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型
A a1 = new A();
Class c = a1.getClass();
/*
* 获取方法 名称和参数列表来决定
* getMethod获取的是public的方法
* getDelcaredMethod自己声明的方法
*/
try {
//Method m = c.getMethod("print", new Class[]{int.class,int.class});
Method m = c.getMethod("print", int.class,int.class);//两种方法的效果是一样的
//方法的反射操作
//a1.print(10, 20);方法的反射操作是用m对象来进行方法调用 和a1.print调用的效果完全相同
//方法如果没有返回值返回null,有返回值返回具体的返回值
//Object o = m.invoke(a1,new Object[]{10,20});
Object o = m.invoke(a1, 10,20);
System.out.println("==================");
//获取方法print(String,String)
Method m1 = c.getMethod("print",String.class,String.class);
//用方法进行反射操作
//a1.print("hello", "WORLD");
o = m1.invoke(a1, "hello","WORLD");
System.out.println("===================");
// Method m2 = c.getMethod("print", new Class[]{});
Method m2 = c.getMethod("print");
// m2.invoke(a1, new Object[]{});
m2.invoke(a1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//ps:invoke方法可以绕过编译阶段,可以在指定类型的泛型集合中添加其他类型的数据
反射机制的应用
/**
* 对于普通的工厂模式当我们在添加一个子类的时候,就需要对应的修改工厂类。 当我们添加很多的子类的时候,会很麻烦。现在我们利用反射机制实现工厂模式,可以在不修改工厂类的情况下添加任意多个子类。
*/
interface animal {
public abstract void eat();
}
class Pig implements animal {
public void eat() {
System.out.println("I like eatting");
}
}
class Dog implements fruit {
public void eat() {
System.out.println("dog");
}
}
class Factory {
public static animal getInstance(String ClassName) {
animal animal1 = null;
try {
animal1= (animal) Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return animal1;
}
}
PS:博文中如有什么不对的地方恳请大家指出,谢谢~