反射机制
特点:动态获取类以及类中成员。
通常在程序扩展时,会使用父类或者接口完成,其实就是多态。
在这种情况,运行时,还是需要给其传递一个自定义的子类对象。需要自己new来完成。
虽然修改动作已经很少了,但还是需要修改部分细节。
interface Inter{void show();}
class Demo{
void function(Inter in){
in.show();
}
}
main(){
Demo d = new Demo();
d.function(new InterImpl());//这里需要传入一个新的后期子类对象。
}
class InterImpl implements Inter{
public void show(){}
}
能不能完全不改动源程序,就可以运行后期子类内容呢?
我们可以对外暴露一个配置文件,该配置文件可以是键值对形式的.ini文件、xml文件。
通过反射机制动态获取子类字节码文件,并动态创建其对象。
main(){
Demo d = new Demo();
BufferdReader bufr = new BufferedReader(new FileReader("config.txt"));
String className = bufr.readLine();
Class clazz = Class.forName(className);
Inter in = (Inter)clazz.newInstance();
d.function(in);
}
通过上面示例,可以看到反射进一步增强了程序的扩展性。
Class
类的实例表示正在运行的 Java 应用程序中的类和接口,它将字节码文件封装成了对象,类字段,方法,构造函数也被封装为对象,我们可以通过对象效用获取类中的字段方法和构造函数。
例:
package cn.itcast.test;
public class Person {
private String name;
private int age;
private String address;
public Person(String name, int age, String address) {
super();
this.name = name;
this.age = age;
this.address = address;
}
public void show(String name,int age){
System.out.println(name+age+address+"---");
}
}
package cn.itcast.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import cn.itcast.test.Person;
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//获取指定类对象
Class clazz = Class.forName("cn.itcast.test.Person");
//Person类中没有无参构造函数,必须获取带参数构造函数进行初始化
Constructor cons = clazz.getConstructor(String.class,int.class,String.class);
//使用带参数的构造函数进行初始化
Person p = (Person)cons.newInstance("zhangsan",22,"shandong");
//获取Person类中的方法对象
Method method = clazz.getMethod("show",String.class,int.class);
/*
Method[] methods = clazz.getDeclaredMethods();//可以获得所有声明过的方法,包括私有和静态方法
methods = clazz.getMethods(); //不能获得私有和静态方法,但可获取从父类继承来的方法
*/
//调用方法对象的invoke()方法
method.invoke(p,"zhang",25);
}
}
注解:定义标记简化书写。
特点:
将运行时出现问题体现编译时期:@Override
它就是程序中的一个标记。
定义格式:
@interface 注解名称{
//注解属性。
属性类型 属性名();
属性类型 属性名() default 类型对应的值;
}
注解内部有一个默认的属性value。
属性类型:8种基本数据类型,String ,Class,数组,enum,Annotation
注解可以加载包,类,成员,局部。
注解有一个声明周期:
是通过一个注解来体现的。
@Retention(RetentionPolicy.RUNTIME)
RetentionPolicy是一个枚举类型。
有三个值:
CLASS:默认的。编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释
RUNTIME:编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取
SOURCE:编译器要丢弃的注释
注解如何来获取:
通过反射的形式。类的注解获取类所属Class对象。
方法注解要获取Method对象。
什么时候用注解呢?
配置信息较为简单可以将其配置在注解上。
方便于类在反射的是使用该配置信息。这样就不用在对配置信息文件进行读写操作。
注解也有一定义的局限性。
将值直接定义在程序内部。