java的反射机制

Java反射机制在运行时提供判断对象所属类、构造对象、访问成员变量和方法的能力。虽然提高了灵活性,降低了耦合,但也存在性能损耗和逻辑模糊的问题。通过反射,可以调用无参或有参方法,并结合注解实现自动调用特定类。
摘要由CSDN通过智能技术生成

什么是反射

 反射是java中的动态机制,它允许我们在程序运行期间再确定对象的实例化,方法的调用,
 属性的操作等。使得程序的灵活度大大提升,但是同时也带来了更多的资源开销和较低的
 运行效率。
 程序不能过度的依赖反射机制。

java反射机制提供了什么功能?

1. 在运行时能够判断任意一个对象所属的类
2. 在运行时构造任意一个类的对象
3. 在运行时判断任意一个类所具有的成员变量和方法
4. 在运行时调用任一对象的方法
5. 在运行时创建新类对象

运用反射的优缺点


优点:
    反射提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提前硬编码目标类
缺点:
   (1)性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
   (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标注了!");
        }
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值