java的反射机制

一.什么是反射

 反射是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标注了!");
        }
    }
}

 

上一篇:旋转字符串


下一篇:推导式