入门java的第n天---反射

反射与注解:

什么是反射?

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。. 这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。. 反射被视为动态语言的关键

反射的使用
 反射第一步:获取要操作的类的类对象
 类对象:Class类
 JVM(java虚拟机)每当加载一个类时(读取要操作的类的字节码文件),就会实例化一个Class的实例来表示刚加载的这个类。在JVM内部每个被加载的类都有且只有一个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类加载形式获取类对象
 */
       String name = cls.getName();//获取类名(完全限定名)
        System.out.println(name);
        name = cls.getSimpleName();//仅获取类名
        System.out.println(name);
//列如:
 Scanner scanner=new Scanner(System.in);
        System.out.println("请输入一个类名:");
        String className=scanner.nextLine();
        Class cls=Class.forName(className);

        String name = cls.getName();//获取类名(完全限定名)
        System.out.println(name);
        name = cls.getSimpleName();//仅获取类名
        System.out.println(name);
        /*
            通过类对象获取其表示的类的所有公开方法
            Method类:方法对象
            该类的每一个实例用于表示某个类中的某个方法
         */
        Method[] methods=cls.getMethods();
        for (Method method:methods){
            System.out.println(method.getName());
        }
使用反射机制实例化对象
1.加载类对象                  调用的包名.类名
  Class cls=Class.forName("reflect.Person");
    
//2.Class提供了一个方法:newInstance()方法,可以调用其表示的类的公开的无参构造进行实例化
    Object o=cls.newInstance();
//列如:
    Scanner scanner=new Scanner(System.in);
        while (true){
            System.out.println("请输入一个类名:");
            String className=scanner.nextLine();
            Class cls=Class.forName(className);
            Object o=cls.newInstance();
            System.out.println(o);
        }
获取类的公开方法:
 /*
通过类对象获取其表示的类的所有公开方法
Method类:方法对象
该类的每一个实例用于表示某个类中的某个方法
*/
 Method[] methods=cls.getMethods();
for (Method method:methods){
            System.out.println(method.getName());
        }
获取构造器:
Class cls=Class.forName("reflect.Person");
        //Constructor类的每一个实例用于表示一个构造方法
// Constructor c=cls.getConstructor();//不传参获取的就是无参构造器
        Constructor c=cls.getConstructor(String.class);//Person(String name)
        Object o=c.newInstance("王五");//new Person("王五")
        System.out.println(o);
        Constructor cs=cls.getConstructor(String.class,int.class);
        Object oc=cs.newInstance("132131w",126);
        System.out.println(oc);
调用方法:
Scanner scanner=new Scanner(System.in);
        System.out.println("请输入类名:");
        String className=scanner.nextLine();
        System.out.println("请输入方法名:");
        String methodName=scanner.nextLine();
        //1.加载类对象
        Class cls=Class.forName(className);
        //2.实例化
        Object obj=cls.newInstance();//使用默认构造器实例化对象,Person p=new Person
        //根据类对象获取要操作的方法对象
        Method method=cls.getMethod(methodName);
        //调用方法
        method.invoke(obj);//p.sayGoodBye



        //调用一个参数的方法
        Class cls=Class.forName("reflect.Person");
        Object obj=cls.newInstance();
        Method method=cls.getMethod("say",String.class);
        method.invoke(obj,"大家好~~~");

        //调用两个的参数方法
        Method method1=cls.getMethod("say", String.class, int.class);
        method1.invoke(obj,"今天周末",2);
调用私有方法(一般不要使用):
 Class cls=Class.forName("reflect.Person");
        Object obj=cls.newInstance();
        /*
            Method getDeclaredMethod(String method,Class...args);
            获取Class表示的类自身定义的一个方法(不含从超类继承的,含本类重写的方法)

             Method[] getDeclaredMethods();
            获取Class表示的类自身定义的所有方法(不含从超类继承的,含本类重写的方法)

         */
        Method method=cls.getDeclaredMethod("dosome");
        /*
            Method提供的方法:
            int getModifiers()
            可以获取当前方法的访问修饰符
            返回的int值不需要记住具体的数字,可以从Modifier来的畅想进行对应即可
         */
        if (method.getModifiers()== Modifier.PRIVATE){//判断该方法是否为private方法
            method.setAccessible(true);//强行打开访问
        }

        method.invoke(obj);//p.dosome()
在反射机制中判定是否有被某个注解标注的类
public static void main(String[] args) throws URISyntaxException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        File dir=new File(
                ReflectDemo7.class.getResource(".").toURI()
        );
        File[] subs=dir.listFiles(f->f.getName().endsWith(".class"));
        for (File file:subs) {
            String fileName=file.getName();
            String className=fileName.substring(0,fileName.indexOf("."));
            Class cls=Class.forName("reflect."+className);
            //判断当前类是否被注解@AutoRunClass标注过
//            boolean tf=cls.isAnnotationPresent(AutoRunClass.class);
//            System.out.println(className+"是否被标注"+tf);
            if (cls.isAnnotationPresent(AutoRunClass.class)){
                Object o=cls.newInstance();
                Method[] methods=cls.getDeclaredMethods();
                for (Method method:methods) {
                    if (method.isAnnotationPresent(AutoRun.class)){
                        AutoRun ar=method.getAnnotation(AutoRun.class);
                        int value=ar.value();
                        System.out.println("@AutoRun("+value+")");
                        System.out.println("自动调用"+cls.getName()+"的方法"+method.getName()+"()");
                        method.setAccessible(true);
                        method.invoke(o);
                    }
                }
            }

        }
    }
调用含有s的无参方法
/**
 * 自动调用当前类Text所在包中所有的类中名字含有s的无参的public方法
 */
public class Text {
    public static void main(String[] args) throws URISyntaxException {
        File file=new File(Text.class.getResource(".").toURI());
        System.out.println(file.getAbsolutePath());
        File[] subs=file.listFiles(f->f.getName().endsWith(".class"));
        for (File sub:subs) {
            String fielName=sub.getName();
            String className=fielName.substring(0,fielName.indexOf("."));
            System.out.println("类名"+className);

            try {
                Class cls = Class.forName("reflect."+className);
                Object obj=cls.newInstance();
                Method[] methods=cls.getDeclaredMethods();
                for (Method method:methods) {
                    if (method.getModifiers()== Modifier.PUBLIC
                            && method.getParameterCount()==0){
                        System.out.println("自动执行"+cls.getName()+"的方法"+method.getName()+"()");
                        method.invoke(obj);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }
}
调用别的类的main方法:
/*
            Test2.class.getResource(".").toURI()
            //这里的"."当前目录指定是Test2所在的包

            Test2.class.getClassLoader().getResource(".").toURI()
            //这里的"."是当前类Test2所在的包的根包位置

         */
        //定位包: map包
        File dir=new File(
                Text2.class.getClassLoader().getResource("./map").toURI()
        );
        System.out.println(dir.getAbsolutePath());
        File[] subs=dir.listFiles(f->f.getName().endsWith(".class"));
        for (File sub:subs) {
            String fileName=sub.getName();
            String className=fileName.substring(0,fileName.indexOf("."));
            try {
                Class cls = Class.forName("map."+className);
                System.out.println("准备执行"+cls.getName()+"的main方法");
                Method method=cls.getMethod("main",String[].class);
                method.invoke(null,(Object)new String[]{});
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                System.out.println("没有main方法");
            } catch (Exception e) {
                e.printStackTrace();
            }
            }
        }
    }

调用在同一包含有s的无参方法:
/*
            Test2.class.getResource(".").toURI()
            //这里的"."当前目录指定是Test2所在的包

            Test2.class.getClassLoader().getResource(".").toURI()
            //这里的"."是当前类Test2所在的包的根包位置

         */
        //定位包: map包
        File dir=new File(
                Text2.class.getClassLoader().getResource("./map").toURI()
        );
        System.out.println(dir.getAbsolutePath());
        File[] subs=dir.listFiles(f->f.getName().endsWith(".class"));
        for (File sub:subs) {
            String fileName=sub.getName();
            String className=fileName.substring(0,fileName.indexOf("."));
            try {
                Class cls = Class.forName("map."+className);
                System.out.println("准备执行"+cls.getName()+"的main方法");
                Method method=cls.getMethod("main",String[].class);
                method.invoke(null,(Object)new String[]{});
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                System.out.println("没有main方法");
            } catch (Exception e) {
                e.printStackTrace();
            }
            }
        }
    }

注解:
/**
 * 注解的声明使用关键字 @interface
 *
 * 声明一个注解后,通常会使用java内置的两个注解来说明当前注解的一些特征:
 * @Retention注解用于声明我们定义的注解的保留级别
 *  有三个可选值:
 *      RetentionPolicy.SOURCE  仅保留在源代码中,编译后的class文件中没有该注解
 *      RetentionPolicy.CLASS   注解保留在字节码文件中,但是反射机制不能使用它
 *      RetentionPolicy.RUNTIME 注解保留在字节码文件中,并且可以被反射机制调用
 *      @Retention不指定时,默认级别为CLASS
 *
 * @Target注解用于声明我们定义的注解可以在哪里被标注
 *   对应的可选值有很多,都在ElementType上有所定义
 *   例如:
 *   ElementType.TYPE  在类上可以使用当前注解
 *   ElementType.METHOD 在方法上可以使用当前注解
 *   ....
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AutoRunClass {
     /*
        可以为注解声明参数
        语法:
            类型 参数名() [default 默认值]
            注:如果当前注解只有一个参数时,参数名通常使用value。这样的好处是,使用该直接时为
            这个参数赋值可以写成:@AutoRun(3)
            否则,如果参数名不叫value,例如叫count.那么使用时必须写为:@AutoRun(count=3)
     */
    int value() default 1;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值