java-反射-Class类走读

背景

反射是java的一大特性,所有的java框架或多或少都会使用到反射。Class类型是java反射中最核心的概念之一,下面阐述一下。

Class原理

在java的世界,所有内容皆是对象,这样能有一些特殊的操作(对比c语言)。其中根本的一个概念就是Class(类类型)。类也有自己的类型。

实战class获取

类型的获取有三种方式:

  • MyDemo.class,通过类直接获取
  • new MyDemo().getClass(),通过对象获取
  • Class.forname(String),通过string来获取

只有这三种方法,而且也全部覆盖了所有的需求。细想一下,我们如果知道类的话,可以直接通过类来获取。如果在运行时,我们获得了一个对象,而我们又不知道它的类,我们同样可以通过对象获取。再有就是最终极的方案,只要我们知道类的全路径,就可以去获取,Class.forname,不过这种获取方法,需要捕获异常,毕竟我们传的全路径参数可能是不对的嘛。。。

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(MyDemo.class);
        System.out.println(new MyDemo().getClass());
        System.out.println(Class.forName("MyDemo").toString());
    }
}

输出如下:

class MyDemo
class MyDemo
class MyDemo

三种方法获得的都一样

Class应用

获取到class对象,大家都知道么个对象里面都应该用属性、方法,那么这个Class对象的属性和方法都是来干嘛的?答案是,用来获取一个类的信息。

获取

package classdemo;

public class Main {
    public Main() {
        class MainDefinedClass {

        }
    }
    public static void main(String[] args) throws NoSuchMethodException {
        Class demoClass = MyDemo.class;
        // 获取类的注解
        System.out.println(demoClass.getAnnotation(MyAnnotationDemo.class));
        // 获取类的所有注解,包括父类的
        System.out.println(demoClass.getAnnotations().toString());
        // 获取按照java规范的输出格式
        System.out.println(demoClass.getCanonicalName());
        // getClasses得到该类及其父类所有的public的内部类
        System.out.println(demoClass.getClasses());
        // getDeclaredClasses得到该类所有的内部类,除去父类的
        System.out.println(demoClass.getDeclaredClasses());
        // 获取类加载器
        System.out.println(demoClass.getClassLoader());
        // 返回数组类型中的元素的类型(说白了,数组类型是另外一个类型了,通过个class和getClass获取的是整体的类型,如果只想获取元素类型,那就用下面的)
        System.out.println(new Integer[]{1, 2}.getClass().getComponentType());
        // 根据参数列表获取构造函数(如果没有就抛出异常)
        System.out.println(demoClass.getConstructor());
        // 获取所有构造函数
        System.out.println(demoClass.getConstructors());
        // 获取所有public的构造函数
        System.out.println(demoClass.getDeclaredConstructors());
        // 获取所有注解,不包括父类的
        System.out.println(demoClass.getDeclaredAnnotations());
        // 获取所有方法,不包括父类的
        System.out.println(demoClass.getDeclaredMethods().length);
        // 获取所有属性,不包括父类的(去掉Declare就可以同时获取父类的属性了)
        System.out.println(demoClass.getDeclaredFields());
        // 获取内部类的声明出处的类
        System.out.println(demoClass.getDeclaringClass());
        System.out.println(MyDeclaringDemo.class.getDeclaringClass());
        // 该类是在那个类中定义的, 比如直接定义的内部类或匿名内部类
        System.out.println(demoClass.getEnclosingClass());
        System.out.println(MyDeclaringDemo.class.getEnclosingClass());
        // 该类是在哪个构造函数中定义的,比如构造方法中定义的匿名内部类
        new MyDeclaringDemo();
        // 该类是在哪个方法中定义的,比如方法中定义的匿名内部类
        System.out.println(MyDeclaringDemo.class.getEnclosingMethod());
        // 获取所有实现的接口的类型(即Type,这个类包含泛型信息)
        System.out.println(demoClass.getGenericInterfaces().length);
        System.out.println(MyDeclaringDemo.class.getGenericInterfaces().length);
        // 获取所有实现的接口类(即Class类,这个类不含有泛型信息)
        System.out.println(demoClass.getInterfaces().length);
        // 获取包名
        System.out.println(demoClass.getPackage());
        // 获取方法列表
        System.out.println(demoClass.getMethods().length);
        // 返回修饰符,是一个int的值,这个int的定义在java.lang.reflect.Modifier中定义
        System.out.println(demoClass.getModifiers());
        // 暂时不太知道。。。
        System.out.println(demoClass.getProtectionDomain());
        //getResource是java.lang.Class的方法,也就是由字节码对象调用。
        //getResource接受一个字符串参数,如果以”/”开头,就在classpath根目录下找(不会递归查找子目录),如果不以”/”开头,就在调用getResource的字节码对象所在目录下找(同样不会递归查找子目录)
        //————————————————
        //版权声明:本文为CSDN博主「crazyboy12138」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
        //原文链接:https://blog.csdn.net/crazyboy12138/article/details/80717271
        System.out.println(demoClass.getResource("/"));
        System.out.println(demoClass.getSuperclass());
        // 此类的标记,若无标记则返回 null。特别地,如果此对象表示一个基本类型或 void,则此方法返回 null。
        System.out.println(demoClass.getSigners());
        System.out.println(demoClass.getTypeParameters().length);
        System.out.println(demoClass.getAnnotatedInterfaces().length);
        // 获取类的全路径名
        System.out.println(demoClass.getTypeName());
        // 根据注解名称获取注解类
        System.out.println(demoClass.getAnnotationsByType(MyAnnotationDemo.class).length);
    }

    public static class MyDeclaringDemo implements MyInterfaceDemo {
        public MyDeclaringDemo() {
            class DefinedClass {

            }
            // 获取该类是在哪个构造方法定义的
            System.out.println(new DefinedClass().getClass().getEnclosingConstructor());
        }
    }
}

通过class能获取的信息非常立体。

  • 我是谁
  • 我是哪来的
  • 我有什么东东
  • 我能干啥
  • 等等

判断

package classdemo;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(MyDemo.class);
        System.out.println(new MyDemo().getClass());
        System.out.println(Class.forName("classdemo.MyDemo").toString());

        Class demoClass = MyDemo.class;
        // 是否是注解类
        System.out.println(demoClass.isAnnotation());
        // 是否存在一个注解
        System.out.println(demoClass.isAnnotationPresent(MyAnnotationDemo.class));
        // 是否为匿名类
        System.out.println(demoClass.isAnonymousClass());
        // 是否为匿名类
        System.out.println(new MyInterfaceDemo() {}.getClass().isAnonymousClass());
        // 是否为某类的父类
        System.out.println(demoClass.isAssignableFrom(Main.class));
        // 是否为某类的子类
        System.out.println(demoClass.isInstance(MyDemo.class));
        // 是否为成员类
        System.out.println(demoClass.isMemberClass());
        // 是否为成员类(在某个类中,再定义的类)
        System.out.println(InnerClass.class.isMemberClass());
        class LocalClass {

        }
        // 是否为局部类(局部类:在一个局部方法中定义的类)
        System.out.println(LocalClass.class.isLocalClass());
        // 是否为原始类型boolean、char、byte、short、int、long、float、double
        System.out.println(demoClass.isPrimitive());
        // 是否为java编译器引入的类(这里还不是太理解。。。。??之后看机会吧)
        System.out.println(demoClass.isSynthetic());
    }

    public class InnerClass {

    }
}

能对没个类进行全方位的属性判断,设置包括局部类、内部类、动态类(动态加载)。
其中有一个是否为java编译器引入的判断,现在还不太明白。。。

根据class创建对象

Class demoClass = MyDemo.class;
        Object object = demoClass.newInstance();
        // 通过class反射获得一个对象
        System.out.println(object.getClass());

这种创建对象的方法是反射的灵魂所在。试想一下,在new一个对象之前,并不一定知道这个类是什么,很灵活吧。

总结

单单通过自己的demo还不够,应该从更多框架中加深对Class反射的理解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值