首页 > 其他分享 >JTCR-枚举、装箱和注解-10

JTCR-枚举、装箱和注解-10

时间:2024-04-18 16:13:39浏览次数:24  
标签:JTCR 常量 10 枚举 使用 类型 注解 方法

枚举

枚举定义了一个数据类型和该数据类型允许的若干个值,这些值为命名常量。一个枚举实例的值必须是定义的值。
Java 中,枚举是类类型,可以有构造器、方法和实例变量,甚至实现接口。但不能使用 new 实例化。

enum Name {
  value1, value2, ...
}

// 定义
Name n = Name.value1;

// 比较
n == Name.value2

// case 语句中使用了 value, 而不是 Name.value,因为隐式指定了类型。
switch (n) {
 case value1:
 
 case value2:
}

枚举中定义的值称为枚举常量,隐式被 public static final 修饰。上述代码段中值的类型为 Name。

枚举可以在 switch 语句中作为 case 子句的条件。

枚举包含了两个预定义的方法:
public static type[] values() 方法返回枚举常量组成的数组。
public static type valueOf(String) 方法返回与字符串同名的枚举常量。

枚举定义了构造器后,当声明这个枚举时,所有的枚举常量会调用构造器初始化,具体的初始化调用在枚举定义中。

enum A {
  // 在定义中调用构造器初始化
  var1(10), var2(15), var3;
  
  private int value;
  
  A(int v) {
    value = v;
  }
  // 可以重载构造器
  A() {
    value = -1;
  }
  
  int getValue() {
    return value;
  }
}

// 声明时初始化所有枚举常量
A va;
// 调用方法
A.var1.getValue();

枚举常量是枚举对象,枚举不能作为超类,也不能继承任何类。

所有枚举默认继承自 java.lang.Enum。这个枚举中定义了一些方法,其中三个如下

  • final int ordinal():返回调用该方法的枚举常量在枚举定义中的顺序值(ordinal value),从 0 开始。
  • final int compareTo(type e):如果调用该方法的枚举常量的顺序值小于传入的枚举常量,返回负值;如果顺序值相等,返回 0;如果顺序值大于,返回正值。参与比较的两个枚举常量的类型必须相同。
  • equals():比较枚举常量和任意类型对象的相等性。仅当两个变量引用同一枚举类型中同一枚举常量时判定相等,返回 true。如果两个对象属于不同的枚举类型,顺序值相同,不会判定为相等。

== 可以比较两个枚举引用的相等性。

类型包装器

类型包装器是类类型,与基本数据类型对应,对应方式为基本数据类型的首字母大写。目的之一是有些数据结构允许存储的元素类型必须为类类型,不能直接存储基本数据类型,为解决这个问题而提出。

从 JDK9 开始,Character、Boolean、数值类型的构造器被废弃,使用 static Character valueOf(char) 方法获得 Character 对象,使用 char charValue() 方法获得 char 值。
使用 static Boolean valueOf(boolean)static Boolean valueOf(String) 方法获得 Boolean,传入的字符串包含不分大小写的 "true" 则为 true,否则为 false。使用 boolean booleanValue() 方法获得 boolean 值。

所有数值类型包装器都继承自抽象类 Number,各数值类型提供的方法如上一段类似,传入的字符串如果不包含有效数字会抛出异常。

所有包装器都重写了 toString() 方法,输出对应的基本类型的值。

将基本类型封装到对应的包装类称为 boxing;将包装类中的值提取出来,转成基本类型称为 unboxing。

自动装箱(autoboxing)

从 JDK5 开始,自动装箱和自动拆箱(auto-unboxing)就存在。自动装箱指一个基本类型的值自动转换成对应类型的包装类;自动拆箱过程与自动装箱相反,包装类自动转换成基本类型。

// 自动装箱、自动拆箱
Integer i = 100;
int s = i;

自动装箱/拆箱可能在方法参数传递、方法返回、表达式计算、条件判断时发生。

手动将可表示范围大的数值类型拆箱成可表示范围小的数值类型时,如果值超出了范围,会发生截断,造成错误。自动拆箱可以预防这种错误。

在不必要的时候不要使用自动装箱、拆箱,因为需要开销。

注解

在源文件中嵌入不改变程序行为的补充信息称为注解(annotation)。

// 保留策略的使用
@Retention(RetentionPolicy.RUNTIME)
@interface Ann {
  String str();
  int v();
}

// 使用注解
@Ann(str="val", v=1)
public static void m() {
 // body
}

@interface 告知编译器定义的是一个注解类型,注解的成员都为方法,不需要定义方法体。这些方法的使用类似于一般类中的属性。

注解不能使用 extends 子句,但每个注解都扩展了 Annotation 接口,这个接口中 annotationType() 方法返回一个 Class 对象,该对象表示调用的注解。

任何类型的定义都可以使用注解,比如类、方法、属性、枚举常量、注解等。

使用注解时初始化成员,直接为每个成员赋值。

保留策略(retention policy)决定注解在何时被去除。Java 在 java.lang.annotation.RetentionPolicy 枚举中定义了三个常量,表示注解的生存期。

  • SOURCE:注解在源代码中存在,在编译时去除。
  • CLASS:注解在 .class 文件中存在,在运行时去除。
  • RUNTIME:注解直到运行时依然存在。

局部变量的注解不能在 .class 文件中存在。

使用反射获得注解

class Out {
  @Ann(str="val", v=1)
  public static void m() {
    Out o = new Out();
    try {
      Class<?> c = o.getClass();
      // 如果方法有参数,如 name(int),调用方式为:c.getMethod("name", int.class)
      // 找不到方法抛出异常
      Method m = c.getMethod("m");
      // 找不到注解返回 null
      Ann a = m.getAnnotation(Ann.class);

      // 获得注解成员的值,语法与方法类似
      System.out.println(a.str() + ", " + a.v());
    } catch (NoSuchMethodException e) {
      System.out.println("method not found");
    }
  }

  public static void main(String[] args) {
    m();
  }
}

Annotation[] getAnnotations() 方法返回与调用对象关联的所有注解对象。

// 注解成员定义默认值
// 使用注解时没有赋值就使用默认值
@interface Ann {
  String str() default "str";
  int v() default -1;
}

标记注解是没有任何成员的注解,使用时不需要在后面加上小括号,也可以加上。

isAnnotationPresent(Class<?>) 方法判断调用对象是否和传入的注解类型关联,若是返回 true,否则返回 false。

单成员注解的成员命名为 value 时,使用这个注解直接在小括号中写入值即可,不需要使用“变量=值”的形式。如果多成员注解中,只有成员 value 没有默认值,其他所有成员都有默认值,也可以使用单成员注解的方式赋值。但如果给多个成员赋值,需要显式写出变量和值的对应关系。

内建注解
@Retention:仅在定义注解时使用,指定注解的保留策略。
@Documented:标记接口,在定义注解时使用,表示注解文档化。
@Target:在定义注解时使用,指定该注解可以和哪些类型关联。成员是一个数组,数组元素是 ElementType 枚举常量。

常量 注解可以与之关联的类型
ANNOTATION_TYPE 另一个注解
CONSTRUCTOR 构造器
FIELD 属性
LOCAL_VARIABLE 局部变量
METHOD 方法
MODULE 模块
PACKAGE
PARAMETER 参数
TYPE 类、接口、枚举
TYPE_PARAMETER 类型参数
TYPE_USE type use
// 使用方式示例
@Target({ElementType.FIELD, ElementType.METHOD})

@Inherited:标记注解,仅在定义注解时使用。修饰的注解如果和超类关联,则这个注解也和子类关联。
@Override:标记注解,仅对方法使用。被修饰的方法必须重写,如果没有重写,则发生编译错误。
@Deprecated:表示某类型的定义已过时且不再推荐使用。
@FunctionalInterface:标记注解,用于接口。被注解的接口为函数式接口。函数式接口是仅包含一个抽象方法的接口,用于 lambda 表达式。如果被注解的接口不是函数式接口,则发生编译错误。
@SafeVarargs:标记注解,用于方法和构造器。表示和变参相关的非安全行为没有发生,用于 suppress 未检查警告。
@SuppressWarnings:抑制编译器可能发出的一或多个警告,被抑制的警告以名称的形式传入该注解。

类型注解

非定义形式的注解称为类型注解。类型注解可以让工具检查代码防止产生错误。类型注解必须使用 ElementType.TYPE_USE作为 @Target 的参数。

类型注解可用于注解 throws 中的异常、方法中的 this、方法返回类型(void 类型除外)、数组的维数等。从 JDK8 开始,可以显式地在方法中将 this 作为方法的第一个参数,类型为方法所在的类。这样做不会改变方法签名,仅在使用类型注解时才需要显式将 this 作为方法参数。

判断注解具体注解的是什么,由该注解的 @Target 的值决定。

重复注解

JDK8 开始,重复注解指可以对同一个元素重复使用相同的注解。允许重复使用的注解必须使用 @Repeatable 修饰。为了使用重复注解,必须有一个作为重复注解容器的注解存在,这个注解的成员是类型为重复注解的数组,用于保存重复注解。

@Repeatable(Bb.class)
@interface Aa {
  String str() default "str";
  int v() default -1;
}

@interface Bb {
  Aa[] value();
}

class Out{
    @Aa
    @Aa(str="second", v=99)
    public static void m() {
      Out o = new Out();
      try {
        Class<?> c = o.getClass();
        Method rm = c.getMethod("m");
        // 传入的是作为容器的注解
        Annotation a = rm.getAnnotation(Bb.class);
        // 输出 @Bb(value={@Aa(...), @Aa(...)})
        System.out.println(a);
      } catch (NoSuchMethodException e) {
        System.out.println("method not found");
      }
    }

    public static void main(String[] args) {
      m();
    }
}

获得重复注解的另一种方式是使用 default <T extends Annotation> T[] getAnnotationsByType(Class<T>) 方法,返回以重复注解为元素的数组。重写上述有:

Annotation[] arr = m.getAnnotationsByType(Aa.class);

限制

注解之间不能继承。

定义注解时作为成员的方法的参数须为空,方法的返回类型可以是内建类型、String、Class、enum、另一个注解类型、或合法类型的数组。

成员方法不能使用 throws 子句。

参考

[1] Herbert Schildt, Java The Complete Reference 11th, 2019.

标签:JTCR,常量,10,枚举,使用,类型,注解,方法
From: https://www.cnblogs.com/xdreamc/p/16388568.html

相关文章

  • 【GUI软件】小红书按关键词采集笔记详情,支持多个关键词,含笔记正文、转评赞藏等,爬了102
    一、背景介绍1.1爬取目标熟悉我的小伙伴都了解,我之前开发过2款软件:【GUI软件】小红书搜索结果批量采集,支持多个关键词同时抓取!【GUI软件】小红书详情数据批量采集,含笔记内容、转评赞藏等,支持多笔记同时采集!现在介绍的这个软件,相当于以上2个软件的结合版,即根据关键词爬取......
  • 1050 螺旋矩阵
    和力扣上一道题差不多,不过的当时没写出来,这次出来了。注释写好了。#include<bits/stdc++.h>usingnamespacestd;constintinf=0x3f3f3f3f;#definelllonglongintarr[100010];inta[10010][10010];intdx[]={0,1,0,-1};intdy[]={1,0,-1,0};intmain(){ in......
  • 前端【小程序】10-小程序基础篇【事件对象】
    事件处理事件对象前面已经介绍过小程序事件监听的语法:bind:事件类型=事件回调,但是小程序的事件回调不支持传参数,因此要将模板中的数据传递到事件回调中就必须要通过事件对象来实现。小程序事件回调函数的第1个参数即为事件对象,事件对象中包括了一些有用的信息:index.......
  • JTCR-多线程-09
    基于进程和线程的多任务,其最小的调度单位分别是进程和线程。在基于线程的环境中,单个进程可以同时处理不同的任务,每个线程共享地址空间。基于线程的多任务和基于进程的相比,开销小。相互间的通信和上下文切换开销不同。Java的线程模型Java的运行时系统使用多线程,当某一个线程......
  • SpringBoot 3.1.10 整合Mybatis-plus(快速学会)
    一、简介1、什么是Mybatis-plus?Mybatis-Plus(简称MP)是一个Mybatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。官网:https://baomidou.com/2、Mybatis-plus特性无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑损耗小:启动......
  • Alibaba Cloud Linux 3.2104 LTS 安装mysql5.7.39
    1上传mysql安装包到linux服务器tar-zxvfmysql-5.7.39-linux-glibc2.12-x86_64.tar.gzmvmysql-5.7.39-linux-glibc2.12-x86_64mysql5.72创建mysql用户groupaddmysqluseradd-gmysql-s/sbin/nologinmysqlchown-Rmysql:mysqlmysql5.7 ......
  • JTCR-异常处理-08
    异常处理基础try{//可能产生异常的代码块}catch(ExceptionTypeex){//处理异常}catch(ExceptionTypeex){//处理异常}...finally{//无论是否发生异常,必须执行的代码块}异常类型所有异常类型的超类是Throwable,该类有两个直接子类,一个是Excepti......
  • JTCR-包和接口-07
    包包用于划分类的命名空间,使得不同包中的同名类不会冲突。Java使用文件夹存储包,文件夹名和包名一致。Java运行时系统从当前目录中、CLASSPATH变量定义的值、-classpath指定的值这三种途径寻找包。包和成员访问可访问性private无修饰符protectedpublic同一个......
  • JTCR-深入了解方法和类-05
    方法重载一个类中存在多个同名方法,这些方法的形参类型或数量不同的现象称为方法重载。同名方法的返回值类型在判断是否构成重载时不予考虑。方法重载是支持多态的方式之一。当调用同名方法时,Java根据传入方法的实参类型、数量和顺序确定某个唯一精确匹配的方法,然后调用该方法;如......
  • JTCR-继承-06
    继承基础classA{inti;voidm(){//body}}classBextendsA{intk;voidn(){//body}}没有类可以成为其自身的超类(superclass)。子类不能访问超类中的private成员。超类类型变量可以引用派生自该超类的子类对象,但是使用该变量只......