Java反射

Java反射机制

反射是java的动态机制,它允许我们在程序【运行期间】再确定要实例化的对象,调用的方法或操作的属性。该机制可以大大提高代码的灵活性和可拓展性,但是也随之带来了较低的程序运行效率和更多的系统开销,因此程序不应当过度利用反射机制。

import java.lang.reflect.Method;
import java.util.Scanner;

/**
 * Java反射机制:
 * 反射是java的动态机制,它允许我们在程序【运行期间】再确定要实例化的对象,
 * 调用的方法或操作的属性。该机制可以大大提高代码的灵活性和可拓展性,
 * 但是也随之带来了较低的程序运行效率和更多的系统开销,因此程序不应当过度利用反射机制。
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        /**
        * 获取要操作的类对象
         * class类的实例:
         *  该实例用于表示JVM加载的类,当JVM加载一个类时,就会实例化一个class对象与之对应,
         *  并且每个被加载的类有且仅有一个class的实例与之绑定,通过该class实例我们可以了解到
         *  其表示的类的一切信息(类名,多少个方法,多少个构造器,多少个属性等)
         *
         *  获取一个类对象的方式:
         *  1.类名.class
         *  Class cls = String.class
         *  Class cls = int.class
         *  注意:基本类型获取类对象仅有上述方式
         *
         *  2.  Class.forName(String className)
         *  基于类的完全限定名(包名.类名)加载一个类
         *  Class cls = Class.forName("java.lang.String");
         *
         *  3:ClassLoader类加载器形式
        */
//        Class cls = String.class;
        System.out.println("请输入类的完全限定名:");
        Scanner scanner = new Scanner(System.in);

        Class cls = Class.forName(scanner.nextLine());

        System.out.println(cls.getName());      //获取类对象表示的类的完全限定名 java.lang.String
        System.out.println(cls.getSimpleName());    //仅获取类名  String

        /**
         * Method类的实例用于表示某个类上的一个方法,
         * 通过方法对象可以得知该方法的一切信息(访问修饰符,返回值类型,方法名,参数列表等)
         * 还可以通过方法对象类调用该方法
         */
        Method[] methods = cls.getMethods();    //获取类对象所表示的类的所有公开方法(包含从超类继承的)
        for (Method m:methods) {
            System.out.println(m.getName());
        }

    }
}

Person类

/**
 * 使用当前类测试反射机制
 */
public class Person {
    private String name = "张三";
    private int age = 22;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void sayHello() {
        System.out.println(name + ":hello!");
    }

    public void sayHi() {
        System.out.println(name + ":hi!");
    }

    public void dance() {
        System.out.println(name + "正在跳舞");
    }

    public void sing() {
        System.out.println(name + "正在唱歌");
    }

    public void watchTV() {
        System.out.println(name + "正在看电视");
    }

    public void playGame() {
        System.out.println(name + "正在打游戏");
    }

    public void say(String info) {
        System.out.println(name + "说:" + info);
    }

    public void say(String info, int count) {
        for (int i = 0; i < count; i++) {
            System.out.println(name + "说:" + info);
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

利用反射机制实例化对象

无参

import java.util.Scanner;

/**
 * 利用反射机制实例化对象
 */
public class ReflectDemo02 {
    public static void main(String[] args) throws Exception {
        Person person = new Person();     //无参构造
        System.out.println(person);
        /**
         * 加载需要实例化对象的类的类
         */
//        Class cls = Class.forName("com.example.reflect.Person");
        System.out.println("请输入类的完全限定名:");
        Scanner scanner = new Scanner(System.in);

        Class cls = Class.forName(scanner.nextLine());
        /**
         * 类对象提供了方法:newInstance()
         * 可以利用其表示的类的公开的无参构造器实例化
         */
        Object o = cls.newInstance();
        System.out.println(o);
    }
}

有参

import java.lang.reflect.Constructor;

/**
 * 使用指定构造器实例化对象
 */
public class ReflectDemo03 {
    public static void main(String[] args) throws Exception {
        Person person = new Person("李四", 66);
        System.out.println(person);

        Class cls = Class.forName("com.example.reflect.Person");
        /**
         * 通过类对象获取其表示的类的某个指定的构造器
         * cls.getConstructor()
         *
         * Constructor类的每一项实例用于表示某个类上的某一个构造器
         */
        Constructor constructor = cls.getConstructor(String.class, int.class);
        Object obj = constructor.newInstance("张三",28);
        System.out.println(obj);
    }
}

变长参数

import java.util.Arrays;

/**
 * JDK5之后推出了一个新特性:变长参数
 */
public class ArgsDemo {
    public static void main(String[] args) {
        /**
         * 变长参数是编译器认可的,最终会被编译器改为数组
         * 传参时改为:
         * dosome(new String[]{"a", "b", "c", "d", "e"})
         */
        dosome("red");
        dosome("a", "b");
        dosome("a", "b", "c", "d", "e");
    }

    /**
     * 变长参数在一个方法中必须是最后一个参数
     */
    public static void dosome(String... strings) {
        System.out.print(strings.length + "  ");
        System.out.println(Arrays.toString(strings));
    }
}

使用反射机制调用方法

无参

import java.lang.reflect.Method;
import java.util.Scanner;

/**
 * 使用反射机制调用方法
 */
public class ReflectDemo04 {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        person.dance();

        reflecttest1();
    }

    private static void reflecttest1() throws Exception {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入类的完全限定名:");
        Class cls = Class.forName(sc.nextLine());
        Object o = cls.newInstance();

        System.out.println("请输入需要调用的方法:");
        Method method = cls.getMethod(sc.nextLine());
        method.invoke(o);
    }

    private static void extracted() throws Exception {
        //实例化
        Class cls = Class.forName("com.example.reflect.Person");
        Object o = cls.newInstance();       //Person o = new Person();

        /*
        * 调用方法
        */
        //通过类对象获取要调用方法的方法对象(Method对象)
        Method method = cls.getMethod("dance");     //dance方法
        //通过方法对象来调用该方法
        method.invoke(o);   //person.dance();
    }
}

有参

import java.lang.reflect.Method;

/**
 * 使用反射机制调用方法
 */
public class ReflectDemo05 {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        person.say("work");
        person.say("red",1);

        Class<?> cls = Class.forName("com.example.reflect.Person");
        Object o = cls.newInstance();

        Method method1 = cls.getMethod("say", String.class);
        method1.invoke(o,"test_method");

        Method method2 = cls.getMethod("say", String.class, int.class);
        method2.invoke(o,"张三",2);
    }
}

利用反射机制访问私有方法

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 利用反射机制访问私有方法
 */
public class ReflectDemo06 {
    public static void main(String[] args) throws Exception {
        /**
         * getMethods()和getMethod()
         * 可以获取类对象所表示的类的所有公开方法(包含从超类继承的),无法访问私有的
         *
         * getDeclaredMethod()和getDeclaredMethods()
         * 可以获取被类定义的方法(包含私有方法),无法获取超类继承的方法
         */

        Class cls = Class.forName("com.example.reflect.Person");
        Object o = cls.newInstance();

        System.out.println(Arrays.toString(cls.getDeclaredMethods()));

        Method method = cls.getDeclaredMethod("privat");
        method.setAccessible(true);     //强行打开访问权限
        method.invoke(o);
        method.setAccessible(false);    //用后应及时关闭访问权限
    }
}

利用反射机制调用类中所有无参方法

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 利用反射机制调用Person类中所有无参方法
 * Method上定义了 int getParameterCount()方法,
 * 该方法可以获取当前Method表示的方法中有多少个参数
 */
public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("com.example.reflect.Person");
        Object o = cls.newInstance();

        Method[] methods = cls.getDeclaredMethods();
        for (Method m : methods) {
            /**
             * m.getModifiers() == Modifier.PUBLIC
             * 判断方法是否为public类型
             */
            if (m.getParameterCount() == 0 && m.getModifiers() == Modifier.PUBLIC) {
                m.invoke(o);
            }
        }
    }
}

实例化与当前类在同一个包中的所有类

import java.io.File;

/**
 * 实例化与当前类在同一个包中的所有类
 */
public class Test2 {
    public static void main(String[] args) throws Exception {
        File file = new File(
                Test2.class.getResource(".").toURI()    //获取当前类所在包的路径
        );
        String fqn = Test2.class.getPackage().getName();    //获取当前类的完全限定名

        File[] files = file.listFiles();
        for (int i = 0; i < files.length; i++) {
            String name = files[i].getName();
            String type = name.split("\\.")[1];
            String filename = name.split("\\.")[0];
            if ("class".equals(type)) {
                Class cls = Class.forName(fqn + "." + filename);
                Object o = cls.newInstance();
                System.out.println(o);
            }
        }

    }
}

注解反射

注解创建

无参

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 注解   JDK8后引入的一个新特性,我们可以利用注解辅助反射机制。
 * 注解使用前需要先定义.
 * Java中有几个内置的注解是来为我们自定义的注解添加某些特性的:
 *
 * @Target()    用于说明我们定义的注解所能标注的位置
 * ElementType.TYPE     类上
 * ElementType.METHOD   方法上
 * ElementType.FIELD    属性上
 *
 * @Retention()     用于说明当前注解的保留级别(有3个可选值)
 * RetentionPolicy.RUNTIME      注解会被保留在字节码文件中,且可以被反射机制访问
 * RetentionPolicy.CLASS        注解会被保留在字节码文件中,但是不可被反射机制访问。这些也是注解的默认保留级别
 * RetentionPolicy.SOURCE       注解仅保留在源码文件中
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoRunClass {

}

有参

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoRunMethod {
    /**
     * 注解中可以添加参数,添加格式为:
     * 参数类型 参数名() [default 默认值]
     * default可以为参数设定默认值,在使用注解不传递参数时采取默认值。
     *
     * 当注解只有一个参数时,参数名称建议选取"value",这样在使用注解时便于传递参数,
     * 这时调用注解例如:@AutoRunMethod(3)
     *
     * 正常使用注解时,参数传递格式为:@AutoRunMethod(参数名 = 参数值),
     * 例如:@AutoRunMethod(value = 1),参数顺序可以与定义时不一致
     */
    int value() default 1;
}

判断类是否被标注

/**
 * 反射中的注解操作
 */
public class ReflectDemo07 {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("com.example.reflect.Person");

        /**
         * 判断当前cls所表示的类是否被注解AutoRunClass标注
         */
        if (cls.isAnnotationPresent(AutoRunClass.class)){
            System.out.println("被标注了");
        }else {
            System.out.println("没被标注");
        }
    }
}

获取注解参数

import com.example.reflect.annotations.AutoRunMethod;

import java.lang.reflect.Method;

/**
 * 获取注解参数
 */
public class ReflectDemo08 {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("com.example.reflect.Person");
        Method method = cls.getDeclaredMethod("playGame");
        if (method.isAnnotationPresent(AutoRunMethod.class)){
            //获取该方法对象所表示的方法上的特定注解
            AutoRunMethod annotation = method.getAnnotation(AutoRunMethod.class);
            //通过注解对象获取参数value的值
            int value = annotation.value();
            System.out.println(value);
        }
    }
}

实例化注解标注类

import com.example.reflect.annotations.AutoRunClass;

import java.io.File;

/**
 * 实例化与当前类在同一个包下被@AutoRunClass标注类
 */
public class Test3 {
    public static void main(String[] args) throws Exception {
        File file = new File(
                Test3.class.getResource(".").toURI()    //获取当前文件的路径
        );
        String fqn = Test3.class.getPackage().getName();    //获取当前文件的完全限定名

        /**
         * 添加过滤器获取该目录中的所有字节码文件
         * 返回出.class文件
         */
        File[] files = file.listFiles((File f) -> {
            return f.getName().endsWith(".class");
        });

        for (File f : files) {
            String fileName = f.getName();      //获取文件名
            String className = fileName.substring(0, fileName.indexOf("."));    //获取类名

            Class<?> cls = Class.forName(fqn + "." + className);
            /**
             * 判断当前类是否被注解AutoRunClass标注
             */
            if (cls.isAnnotationPresent(AutoRunClass.class)) {
                Object o = cls.newInstance();
                System.out.println(o);
            }


        }

    }
}

自动调用注解标注的方法

import com.example.reflect.annotations.AutoRunClass;
import com.example.reflect.annotations.AutoRunMethod;

import java.io.File;
import java.lang.reflect.Method;

/**
 * 自动调用与当前类在同一个包下被注解@AutoRunClass标注的类里面,
 * 被注解@AutoRunMethod标注的方法
 */
public class Test4 {
    public static void main(String[] args) throws Exception {
        File file = new File(
                Test4.class.getResource(".").toURI()    //获取当前文件路径
        );
        String fqname = Test4.class.getPackage().getName();     //获取当前文件的完全限定名

        /**
         * 添加过滤器获取该目录中的所有字节码文件
         * 返回出.class文件
         */
        File[] files = file.listFiles((File f) -> {
            return f.getName().endsWith(".class");
        });

        for (File f : files) {
            String filename = f.getName();  //获取当前文件文件名
            String classname = filename.substring(0, filename.indexOf("."));

            Class cls = Class.forName(fqname + "." + classname);
            /**
             * 判断类是否被注解@AutoRunClass标注
             */
            if (cls.isAnnotationPresent(AutoRunClass.class)) {
                Object o = cls.newInstance();
                System.out.println(o);

                Method[] methods = cls.getDeclaredMethods();
                for (Method m : methods) {
                    /**
                     * 判断方法是否被注解@AutoRunMethod标注
                     */
                    if (m.isAnnotationPresent(AutoRunMethod.class)) {
                        m.invoke(o);
                    }
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值