一.什么是反射
反射是java中的动态机制,它允许我们在程序运行期间再确定对象的实例化,方法的调用, 属性的操作等。使得程序的灵活度大大提升,但是同时也带来了更多的资源开销和较低的 运行效率。 程序不能过度的依赖反射机制。
2.反射获取方式
Class 类对象 Class的每一个实例用于表示JVM中加载的一个类,并且每个被JVM加载的类都 有且只有一个Class的实例。 通过Class我们可以得知其表示的类的一切信息:类名,包名,有哪些构造器,方法 属性等。并在运行期间获取后进行相关操作。 因此反射操作的第一步就是获取要操作的类的类对象。 获取一个类的类对象方式有: 1: 类名.class 例如: Class cls = String.class; Class cls = int.class; 注:基本类型只能通过上述方式获取类对象2: Class.forName(String className) 使用Class的静态方法forName传入要加载的类的完全限定名(包名.类名) 例如: Class cls = Class.forName("java.lang.String")3:类加载器ClassLoader形式
3.常用方法
Class cls = Class.forName("reflect.Person");
//通过类对象获取其表示的String的相关信息
String name = cls.getName(); //获取包名和类名
name = cls.getSimpleName(); //获取类名
System.out.println(cls.getPackage().getName()); //获取包名
//类对象提供了方法newInstance()可以调用无参且公开的构造器实例化
Object o = cls.newInstance();
2获取对应的构造器 Person(String name,int age)
// cls.getConstructor();//不传参获取的为无参构造器
//3通过构造器实例化对象 new Person("王五",22);
Object o = cls.newInstance("王五",22);
//获取当前类对象所表示的类的所有公开方法(包含从超类继承的方法)
Method[] methods = cls.getMethods();
//获取私有方法
Method method = cls.getDeclaredMethod("secret");
//强行打开访问权限
method.setAccessible(true);
利用反射机制调用方法: invoke
1.调用无参方法
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.sayHello();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入类名:");
String className = scanner.nextLine();
System.out.println("请输入方法名:");
String methodName = scanner.nextLine();
//实例化
// Class cls = Class.forName("reflect.Person");
Class cls = Class.forName(className);
Object o = cls.newInstance();//Person o = new Person();
//获取要调用的方法
//仅传入方法名时,是获取该无参方法
// Method method = cls.getMethod("sayHello");//表示的Person的成员方法sayHello()
Method method = cls.getMethod(methodName);
method.invoke(o);//o.sayHello()
}
}
2. 调用有参方法
public class ReflectDemo5 {
public static void main(String[] args) throws Exception {
Class cls = Class.forName("reflect.Person");
Object o = cls.newInstance();
Method method = cls.getMethod("dosome",String.class);//dosome(String)
method.invoke(o,"玩游戏");//p.dosome("玩游戏");
Method method1 = cls.getMethod("dosome",String.class,int.class);
method1.invoke(o,"看电视",5);
}
}
4.反射中使用的注解
定义@AutoRunClass 注解
该注解是用来标注那些可以被反射机制自动调用的类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AutoRunClass {
}
定义注解时,我们通常会使用java内置的两个注解来加以修饰 1.@Retention 用来指定当前注解的保留级别。有三个可选值, 对应: RetentionPolicy.SOURCE 表示当前注解仅保留在源码中 RetentionPolicy.CLASS(默认值) 表示注解会保留在字节码中,但是反射机制不可用 RetentionPolicy.RUNTIME 表示保留在字节码文件中,但是可以被反射机制使用 通常我们定义的注解都会指定为RUNTIME级别,辅助反射机制的操作。2.@Target用于表示当前注解可以在什么位置上使用。可选项都定义在ElementType上 常见的有: ElementType.TYPE 在类上使用 ElementType.FIELD 在属性使用 ElementType.METHOD 在方法上使用 ...
判断是否被注解标注 : isAnnotationPresent(注解名.class)
public class ReflectDemo7 {
public static void main(String[] args) throws Exception {
//判断一个类是否有被@AutoRunClass标注
// Class cls = Class.forName("reflect.Person");
// Class cls = Class.forName("reflect.Student");
Class cls = Class.forName("reflect.Test2");
/*
出了Class之外,像Method,Filed等其他反射对象也支持isAnnotationPresent
方法,用来表示是否被指定注解标注。
比如:
Method的这个方法就是判断其表示的方法是否有被指定注解标注。
Constructor的这个方法就是判断其表示的构造器是否被指定注解标注。
*/
if(cls.isAnnotationPresent(AutoRunClass.class)){
System.out.println(cls.getName()+":被@AutoRunClass标注了!");
}else{
System.out.println(cls.getName()+":没有被@AutoRunClass标注了!");
}
}
}