首页 > 其他 > 详细

3.9 枚举、注解、反射

时间:2021-04-19 11:40:39      阅读:17      评论:0      收藏:0      [点我收藏+]

9.1 枚举

9.1.1 概述

  • 简介:在JDK1.5 之前,定义常量都是:public static fianl....,很难管理,
    通过枚举可以把相关的常量分组到一个枚举类型里。
  • 作用:定义有限数量的一组同类常量

9.1.2 格式

  • 权限修饰符 enum 枚举名称 {
    实例1,实例2,实例3,实例4;
    }
    public enum Level { 
        LOW(30), MEDIUM(15), HIGH(7), URGENT(1); 
        private int levelValue; 
        private Level(int levelValue) { 
            this.levelValue = levelValue; 
        }
        public int getLevelValue() { 
            return levelValue; 
        } 
    }

9.1.3 继承

  • 每个枚举都继承自java.lang.Enum类,所以只能通过实现接口来获得抽象方法
    public interface LShow{ 
        void show(); 
    }
    public enum Level implements LShow{ 
        LOW(30){ 
            @Override public void show(){ 
                //... 
            } 
        }, MEDIUM(15){ 
            @Override public void show(){ 
                //... 
            } 
        }
        private Level(int levelValue) { 
            this.levelValue = levelValue; 
        }
        public int getLevelValue() { 
            return levelValue; 
        }
    }

9.1.4 注意事项

  1. 一旦定义了枚举,就不要修改里面的值,除非是必要的
  2. 不提供set方法,不符合枚举设计初衷
  3. 只能有private构造方法
  4. 不能有子类,因为枚举类已默认被final修饰
  5. 不能定义name属性,因为自带name属性
  6. switch中使用枚举时,直接使用常量名,不用携带类名
  7. 枚举类默认继承的是java.lang.Enum类而不是Object类

9.2 注解(Annotation)

9.2.1 概述

  • 简介:Java 注解又称 Java 标注,是 JDK5.0 引入的一种注释机制。Java 语言中的类、方法、变量、参数和包等都可以被标注。和注释不同,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

9.2.2 分类

  1. 内置注解
  2. 元注解
  3. 自定义注解

9.2.2.1 内置注解

  • 常用
  • @Override:重写
  • 定义在java.lang.Override
  • @Deprecated:废弃 *
  • 定义在java.lang.Deprecated
  • @FunctionalInterface: 函数式接口
  • Java 8 开始支持,标识一个匿名函数或函数式接口。
  • SuppressWarnings:抑制编译时的警告信息。
  • 定义在java.lang.SuppressWarnings
    @SuppressWarnings("unchecked") //抑制单类型的警告]
    @SuppressWarnings("unchecked","rawtypes") //抑制多类型的警告 
    @SuppressWarnings("all") // 抑制所有类型的警告

9.2.2.2 元注解

作用

  • 作用在其他注解的注解

分类

  • @Retention
    • 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented
  • 标记这些注解是否包含在用户文档中 javadoc。
  • @Target
  • 标记这个注解应该是哪种 Java 成员。
  • @Inherited
  • 标记这个注解是自动继承的
    1. 子类会继承父类使用的注解中被@Inherited修饰的注解
      2. 接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没
      有 被@Inherited修饰
      3. 类实现接口时不会继承任何接口中定义的注解

9.2.2.3 自定义注解

注解架构

技术分享图片

1. Annotation与RetentionPolicy 与ElementType 。

  • 每1个Annotation对象,都会有唯一的RetentionPolicy,至于ElementType属性,则有 1~n个。

2. 常用ElementType(注解的用途类型)

    TYPE /* 类、接口(包括注释类型)或枚举声明 */ 
    FIELD /* 字段声明(包括枚举常量) */ 
    METHOD /* 方法声明 */

3. RetentionPolicy(注解作用域策略)

  1. SOURCE:Annotation 仅存在于编译器处理期间
  2. CLASS:编译器将Annotation存储于类对应的.class文件中,它是Annotation的默认行为。
  3. RUNTIME:编译器将 Annotation 存储于 class 文件中,并且可由JVM读入

定义格式

    @interface 自定义注解名{}

注意事项

  1. 定义的注解,自动继承了java.lang,annotation.Annotation接口
  2. 注解中的每一个方法,实际是声明的注解配置参数
  • 方法的名称就是 配置参数的名称
  • 方法的返回值类型,就是配置参数的类型。只能是:基本类型/Class/String/enum
  1. 可以通过default来声明参数的默认值
  2. 如果只有一个参数成员,一般参数名为value
  3. 注解元素必须要有值,我们定义注解元素时,经常使用空字符串、0作为默认值。
    @Documented 
    @Target(ElementType.TYPE)  //可作用于类中
    @Retention(RetentionPolicy.RUNTIME) 
    public @interface MyAnnotation1 { 
        String value() default " ";
        int name() default 0;
    }
    
    //调用注解
    @MyAnnotational(value="xixi",name="haha")
    class Demo1{
        void add(){
          //xxxx
        }
    }

9.3 反射

9.3.1 概述

  • 运行状态中,获取任意一个类的结构 , 创建对象 , 得到方法,执行方法

9.3.2 类加载器

  1. BootstrapClassLoader(引导启动类加载器):
  • 嵌在JVM内核中的加载器,用C++编写,主要负载加载JAVA_HOME/lib下的类库,引导启动类加载器无法被应用程序直接使用。
  1. ExtensionClassLoader(扩展类加载器):
  • 用JAVA编写,主要加载JAVA_HOME/lib/ext目录中的类库。父加载器是BootstrapClassLoader
  1. App ClassLoader(应用类加载器)
  • 负责加载应用程序classpath目录下的所有jar和class文 件。父加载器为Ext ClassLoader

9.3.2.1 加载模型:双亲委派模型

  • 类通常是按需加载,即第一次使用该类时才加载。由于有了类加载器,Java运行时系统不需要知道文件与 文件系统。
  • 双亲委派模型:如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求 转交给父类加载器去完成。每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的 启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类) 时,子类加载器才会尝试自己去加载
  • 委派的好处就是避免有些类被重复加载

9.3.2.2 给项目添加resource root目录

  • 新建Directory并命名为source-->右键Mark Directory as选择Resources Root

通过类加载器加载资源文件

  • 默认加载的是src路径下的文件,但是当项目存在resource root目录时,就变为了加载
    resource root下的文件了。
    public static void main(String[] args) throws IOException {
        InputStream is = Demo1.class.getClassLoader().getResourceAsStream("a.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String s = br.readLine();
        System.out.println(s);
        br.close();
    }

9.3.2.2 Class对象

  • 要想了解一个类,必须先要获取到该类的字节码文件对象.在Java中,每一个字节码文件,被夹在到内存后,都存在一个对应的Class类型的对象

获得Class对象的方式

//1. 知道类的名称,且类已存在(包名.类名.class)
    Class<Demo1> dd = Demo1.class;
//2. 类的对象已经存在(Class 对象.getClass())
    Demo1 d=new Demo1();
    Class<Demo1> aClass = (Class<Demo1>) d.getClass();
//3. 知道类的名称(Class.forName(包名+类名))
    Class<Demo1> abClass = (Class<Demo1>)        
    Class.forName("com.kaikeba.Test.Unit4Test.NineTest");
  • 如果类在内存中不存在, 则会加载到内存
  • 如果类已经在内存中存在, 则会重复利用
  • 一个class文件 在内存中不会存在两个类对象

获取构造方法

     String name;
    int age;

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

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    Class<Person> aClass = 
         (Class<Person>)Class.forName("com.kaikeba.Test.Unit4Test.NineTest.Person");
    //获得无参构造方法
    Constructor<Person> c = aClass.getConstructor();
    //实例化对象
    Person p = c.newInstance();

    //获得含参构造方法
    Constructor<Person> c2 = aClass.getConstructor(String.class, int.class);
    //实例化对象
    Person p2 = c2.newInstance("kobe", 12);

    //获得所有权限的构造方法,对私有属性进行操作
    Constructor<Person> c3 = aClass.getDeclaredConstructor(String.class);
    //如果flag为true 则表示忽略访问权限检查 !(可以访问任何权限的方法)
    c3.setAccessible(true);
    Person p3 = c3.newInstance("john");

获取方法

    //获得类的方法
    Method setName = aClass.getMethod("setName", String.class);
    //参数1:哪个对象要执行该方法
    //参数2:调用方法时传递的参数
    setName.invoke(p, "张三");
    System.out.println(p);

获取属性

    Field name = aClass.getDeclaredField("name");
    name.setAccessible(true);
    name.set(p, "李四");
    System.out.println(p);

获取注解

    //根据类型获取类/属性/方法的注解对象
    注解类型 对象名 = (注解类型) c.getAnnotation(注解类型.class);
    
    //获取类/属性/方法的全部注解对象
    Annotation[] annotations01 = Class/Field/Method.getAnnotations(注解类型.class); 
    for (Annotation annotation : annotations01) { 
        System.out.println(annotation); 
    }

9.4 内省

  • 基于反射 , java所提供的一套应用到JavaBean的API
  • bean类格式
    1. 一个定义在包中的类
    2. 拥有无参构造器
    3. 所有属性私有,提供get/set方法
    4. 实现了序列化接口

3.9 枚举、注解、反射

原文:https://www.cnblogs.com/ly411/p/14675383.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!