枚举类型本质上也是一种类,只不过是这个类的对象是有限的、固定的几个,不能让用户随意创建。
枚举类的例子举不胜举:
星期
:Monday(星期一)…Sunday(星期天)性别
:Man(男)、Woman(女)月份
:January(1月)…December(12月)季节
:Spring(春节)…Winter(冬天)三原色
:red(红色)、green(绿色)、blue(蓝色)支付方式
:Cash(现金)、WeChatPay(微信)、Alipay(支付宝)、BankCard(银行卡)、CreditCard(信用卡)就职状态
:Busy(忙碌)、Free(空闲)、Vocation(休假)、Dimission(离职)订单状态
:Nonpayment(未付款)、Paid(已付款)、Fulfilled(已配货)、Delivered(已发货)、Checked(已确认收货)、Return(退货)、Exchange(换货)、Cancel(取消)线程状态
:创建、就绪、运行、阻塞、死亡若枚举只有一个对象, 则可以作为一种单例模式的实现方式。
枚举类的实现:
enum
关键字来快速定义枚举类型。经验之谈:
- 开发中,当需要定义一组常量时,强烈建议使用枚举类。
- 开发中,如果针对于某个类,其实例是确定个数的。则推荐将此类声明为枚举类。
在JDK5.0 之前如何声明枚举类呢?
私有化
类的构造器,保证不能在类的外部创建其对象public static final
,对外暴露这些常量对象实例变量
,应该声明为private final
(建议,不是必须),并在构造器中初始化枚举类:
package com.cn;
public class Light {
//创建红绿灯的3个实例:红 绿 黄
public static final Light RED= new Light();
public static final Light GREEN = new Light();
public static final Light YELLOW = new Light();
//提供私有的构造方法用来创建对象(默认提供的构造方法就是私有的,所以可以省略)
private Light(){
}
}
在main方法中调用枚举类对象:
package com.cn;
public class LightDemo {
public static void main(String[] args) {
Light r = Light.GREEN;//通过类名调用静态变量对象
System.out.println(r);//com.cn.Light@4eec7777
}
}
枚举类:
package com.cn;
public class Light2 {
//4.创建当前类的实例(红绿灯),需要使用public static final修饰
public static final Light2 RED = new Light2("红");
public static final Light2 GREEN = new Light2("绿");
public static final Light2 YELLOW = new Light2("黄");
//2. 声明当前类的对象的实例变量,使用private final修饰
//想要让外界只能获取不能修改,所以设置为final修饰的
private final String name;
//1. 私有化类的构造器,提供带参构造
private Light2(String name){
this.name=name;
}
//3. 提供实例变量的get方法,获取属性值
public String getName() {
return name;
}
@Override
public String toString() {
return "Light2{" +
"name='" + name + '\'' +
'}';
}
}
在main方法中调用枚举类对象:
package com.cn;
public class LightDemo2 {
public static void main(String[] args) {
Light2 r2 = Light2.GREEN;
//Light2.GREEN=null;对象是final修饰的,所以外界不能赋值
System.out.println(r2);//Light2{name='绿'}
System.out.println(r2.getName());//绿
}
}
枚举类:
package com.cn;
//2.含有抽象方法的类必须是抽象类
public abstract class Light3 {
//3.抽象类不能实例化,子类实现后必须重写所有的抽象方法(匿名子类)
public static final Light3 RED = new Light3("红") {
@Override
public void show() {
System.out.println("红");
}
};
public static final Light3 GREEN = new Light3("绿"){
@Override
public void show() {
System.out.println("绿");
}
};
public static final Light3 YELLOW = new Light3("黄"){
@Override
public void show() {
System.out.println("黄");
}
};
private final String name;
private Light3(String name){
this.name=name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Light3{" +
"name='" + name + '\'' +
'}';
}
//1.提供抽象方法
public abstract void show();
}
在main方法中调用枚举类对象:
package com.cn;
public class LightDemo3 {
public static void main(String[] args) {
Light3 r3 = Light3.GREEN;
System.out.println(r3);//Light2{name='绿'}
System.out.println(r3.getName());//绿
r3.show();//绿
}
}
发现自己定义一个枚举类,比较麻烦,所以,java就提供了枚举类供我们使用
格式:只有枚举项的枚举类
【修饰符】 enum 枚举类名{
枚举项1,枚举项2,枚举项3...;
}
注意事项:
必须在枚举类的首行
,因为是常量,所以建议大写。默认提供的是private的无参构造
,如果枚举类需要的是无参构造,就不需要声明,写常量对象列表时也不用加参数有参构造,需要手动定义
,有参构造的private可以省略,调用有参构造的方法就是在常量对象名后面加(实参列表)就可以。抽象方法
,但是枚举项必须重写该方法枚举类:
package com.cc;
//自定义的枚举类默认的父类就是Enum,因此不能再继承其他的类型,哪怕是Object
//如:public enum Light2 extends Object{ } 会报错
public enum Light {
//枚举项:创建light类的对象(枚举类的第一行必须是枚举项)
//调用的是无参构造(默认就是private修饰的)
RED,GREEN,YELLOW;
/* 查看底层源码,发现底层做了以下事情:
public final class Light extends Enum {
//创建了3个对象
public static final Light RED = new Light("RED"",0);
public static final Light GREEN = new Light("GREEN",1);
public static final Light YELLOw = new Light("YELLOW",2);
//提供了有参构造
private Light(String s, int i) {
super(s,i); //调用父类的有参构造
}
}
public abstract class Enum ... {
private final String name ;
protected Enum (String name,int ordinal) {
//会把对象的值RED赋值给name
this.name = name ;
this.ordinal = ordinal;
}
public String toString() {
//最终通过toString()方法返回name
return name;
}
}
*/
}
在main方法中调用枚举类对象:
package com.cc;
import static com.cc.Light.*;
public class LightDemo {
public static void main(String[] args) {
Light r = Light.RED;
//打印的不是地址值,说明底层源码重写了toString()
System.out.println(r);//RED
Light ll = Light.GREEN;
//测试枚举在switch中的用法
//因为里面放的是枚举项,所以case后的值必须是在枚举中出现过的,否则会报错。
switch (ll){
case RED:
System.out.println("红");
break;
case GREEN:
System.out.println("绿");//绿
break;
case YELLOW:
System.out.println("黄");
break;
}
}
}
枚举类:
package com.cc;
//自定义的枚举类默认的父类就是Enum,因此不能再继承其他的类型,哪怕是Object
//如:public enum Light2 extends Object{ } 会报错
public enum Light2 {
//1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
//调用有参构造
RED("红"),GREEN("绿"),YELLOW("黄");
/* jdk5之前的形式,在jdk5之后必须要简写为以上方式,并且位于枚举类的首行
public static final Light2 RED = new Light2("红");
public static final Light2 SUMMER = GREEN Light2("绿");
public static final Light2 AUTUMN = new YELLOW("黄");
*/
//2. 声明当前类的对象的实例变量,使用private final修饰
//想要让外界只能获取不能修改,所以设置为final修饰的
private String name;
//3. 私有化类的构造器,private可以省略
private Light2(String name){
this.name = name;
}
//4. 提供实例变量的get方法,获取属性值
public String getName() {
return name;
}
@Override
public String toString() {
return "Light2{" +
"name='" + name + '\'' +
'}';
}
}
在main方法中调用枚举类对象:
package com.cc;
public class LightDemo2 {
public static void main(String[] args) {
Light2 r2 = Light2.RED;
//打印的值不再是源码中toString返回的 RED,
// 而是自己重写后的toString方法的返回值 红
System.out.println(r2);//Light2{name='红'}
System.out.println(r2.getName());//红
}
}
枚举类:
package com.cc;
//含有抽象方法的枚举类不需要添加abstract
public enum Light3 {
//枚举项:创建light类的对象
//调用有参构造
RED("红"){
@Override
public void show() {
System.out.println("红");
}
},
GREEN("绿"){
@Override
public void show() {
System.out.println("绿");
}
},
YELLOW("黄"){
@Override
public void show() {
System.out.println("黄");
}
};
private String name;
private Light3(String name){
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Light3{" +
"name='" + name + '\'' +
'}';
}
//提供抽象类
public abstract void show();
}
在main方法中调用枚举类对象:
package com.cc;
public class LightDemo3 {
public static void main(String[] args) {
Light3 r3 = Light3.RED;
//打印的值不再是源码中toString返回的 RED,
// 而是自己重写后的toString方法的返回值 红
System.out.println(r3);//Light3{name='红'}
System.out.println(r3.getName());//红
r3.show();//红
}
}
String toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法!
static 枚举类型[] values():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值,是一个静态方法
static 枚举类型 valueOf(String name):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。
String name():得到当前枚举常量的名称。建议优先使用toString()。
int ordinal():返回当前枚举常量的次序号,默认从0开始
测试:
枚举类:
package com.cc;
public enum Light2 {
//创建枚举类对象
RED("红"),GREEN("绿"),YELLOW("黄");
private String name;
private Light2(String name){
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Light2{" +
"name='" + name + '\'' +
'}';
}
}
在main方法中调用枚举类对象:
package com.cc;
public class LightDemo2 {
public static void main(String[] args) {
Light2 r2 = Light2.RED;
//测试方法
//1.toString()
//没重写输出的是 对象名: RED
//重写后输出的是 重写后的返回值: Light2{name='红'}
System.out.println(r2);
//2.name()
//得到当前枚举常量的名称: RED 跟重不重写oString没关系
System.out.println(r2.name());
//3.values()
//静态方法,返回枚举类型的对象数组
Light2[] l = Light2.values();
for (int i=0;i<l.length;i++){
/* Light2{name='红'}
Light2{name='绿'}
Light2{name='黄'}*/
System.out.println(l[i]);
}
//4.valueOf(String name)
//返回当前枚举类中名称为objName的枚举类对象。
//如果枚举类中不存在objName名称的对象,则报错。
String objName = "YELLOW";
Light2 ll = Light2.valueOf(objName);
System.out.println(ll);//Light2{name='黄'}
//5.ordinal()
//当前对象在枚举类中第几个声明的对象,默认从0开始
System.out.println(r2.ordinal());//0
}
}
情况1:枚举类实现接口,在枚举类中重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是同一个方法。
枚举类:
package com.cc;
//1定义接口
interface Info{
void show();
}
//2枚举类实现接口
public enum Light2 implements Info{
//创建枚举类对象
RED("红"),GREEN("绿"),YELLOW("黄");
private String name;
private Light2(String name){
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Light2{" +
"name='" + name + '\'' +
'}';
}
//3重写的抽象方法
@Override
public void show() {
System.out.println("重写的抽象方法");
}
}
在main方法中调用枚举类对象:
package com.cc;
public class LightDemo2 {
public static void main(String[] args) {
Light2[] l = Light2.values();
for (int i=0;i<l.length;i++){
/* 重写的抽象方法
重写的抽象方法
重写的抽象方法*/
l[i].show();
}
}
}
情况二:让枚举类的对象分别实现接口中的抽象方法,每个对象调这个方法时输出的内容不一样。
枚举类:
package com.cc;
//1定义接口
interface Info{
void show();
}
//2枚举类实现接口
public enum Light2 implements Info{
//3.创建枚举类对象
//不在枚举类中直接重写抽象方法了,而是使用匿名子类的方式分别重写抽象方法
RED("红"){
@Override
public void show() {
System.out.println(111);
}
},GREEN("绿"){
@Override
public void show() {
System.out.println(222);
}
},YELLOW("黄"){
@Override
public void show() {
System.out.println(333);
}
};
private String name;
private Light2(String name){
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Light2{" +
"name='" + name + '\'' +
'}';
}
}
在main方法中调用枚举类对象:
package com.cc;
public class LightDemo2 {
public static void main(String[] args) {
Light2[] l = Light2.values();
for (int i=0;i<l.length;i++){
/*111
222
333*/
l[i].show();
}
}
}
总结:为了优化以前的开发模式,提出注解开发。减少了代码量,提高了注解的复用。标志是@ Annotation
package com.atguigu.java1;
import java.util.ArrayList;
import java.util.Date;
/**
* 注解的使用
*
* 1. 理解Annotation:
* ① jdk 5.0 新增的功能
*
* ② Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用 Annotation,
* 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。
*
* ③在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android
* 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗
* 代码和XML配置等。
*
* 2. Annocation的使用示例
* 示例一:生成文档相关的注解
* 示例二:在编译时进行格式检查(JDK内置的三个基本注解)
* @Override: 限定重写父类方法, 该注解只能用于方法
* @Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
* @SuppressWarnings: 抑制编译器警告
* @SafeVarargs jdk1.7出现,堆污染,不常用
* @FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用
*
* 示例三:跟踪代码依赖性,实现替代配置文件功能
* @author shkstart
* @create 2019 上午 11:37
*/
public class AnnotationTest {
public static void main(String[] args) {
Person p = new Student();
p.walk();
Date date = new Date(2020, 10, 11);//已过时,但仍然能用,源码中用@Deprecated注解修饰了
System.out.println(date);
@SuppressWarnings("unused")//加上注解警告会消失,unused属性:没有用。 里面的值可以看成是成员变量
int num = 10;//定义了一个变量没有用,在eclipse中会有一个警告:定义了变量没有用。在idea中变量名变为灰色。
@SuppressWarnings({ "unused", "rawtypes" }) //变量没有用,没有添加泛型
ArrayList list = new ArrayList();
}
}
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃饭");
}
}
interface Info{
void show();
}
class Student extends Person implements Info{
@Override//不加上注解不一定不是重写,加上注解会在编译期检查是否为重写父类的方法 如果不是则报错。
public void walk() {
System.out.println("学生走路");
}
public void show() {
}
}
自定义注解中加上元注解:
package com.atguigu.java1;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
/**
* 1.如何自定义注解:参照@SuppressWarnings定义
* ① 注解声明为:@interface
* ② 内部定义成员,通常使用value表示
* ③ 可以指定成员的默认值,使用default定义
* ④ 如果自定义注解没有成员,表明是一个标识作用。public @interface MyAnnotation {},使用时也不需要写属性值
*
* 注意:
* 如果注解有成员,在使用注解时,需要指明成员的值。
* 自定义注解必须配上注解的信息处理流程(使用反射)才有意义。
* 自定义注解通过都会指明两个元注解:Retention、Target
*
* 2.jdk 提供的4种元注解
* 元注解:对现有的注解进行解释说明的注解
* Retention:指定所修饰的 Annotation 的生命周期:SOURCE(在源文件中有效)\CLASS(默认行为, 在class文件中有效)\RUNTIME(在运行时有效)
* 只有声明为RUNTIME生命周期的注解,才能通过反射获取。
* Target:用于指定被修饰的 Annotation 能用于修饰哪些程序元素:如果不指定则代表那都可以用。
* ElementType.ANNOTATION_TYPE 应用于注释类型
* ElementType.CONSTRUCTOR 应用于构造函数
* ElementType.FIELD 应用于字段或属性
* ElementType.LOCAL_VARIABLE 应用于局部变量
* ElementType.METHOD 应用于方法级
* ElementType.PACKAGE 应用于包声明
* ElementType.PARAMETER 应用于方法的参数
* ElementType.TYPE 应用于类的元素
* *******出现的频率较低*******
* Documented:表示所修饰的注解在被javadoc解析时,保留下来。默认情况下,javadoc是不包括注解的。定义为Documented的注解必须设置Retention值为RUNTIME。
*
* Inherited:被它修饰的 Annotation 将具有继承性。如果某个类使用了被@Inherited 修饰的 Annotation, 则其子类将自动具有该注解。
* 如何证明子类继承了注解--->通过反射获取注解信息 ---到反射内容时系统讲解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
@Inherited
public @interface MyAnnotation {
//如果只有一个参数成员,建议使用参数名为value。注意这是一个属性不是方法,虽然有()。
//String value() ;//形式一:可以是任意类型的,如果value值可以指定多个可以定义为数组如:String[] value() ;
String value() default "hello";//形式二:通过default关键字指定一个默认值
}
使用注解:
package com.atguigu.java1;
public class AnnotationTest {
public static void main(String[] args) {
Person p = new Student();
p.walk();
}
}
//@MyAnnotation(value="hello")//形式一:使用注解,因为自定义注解@MyAnnotation有变量value,所以这里需要指定一个值 否则会报错。暂时随便指定个值,没有特殊含义.只有一个值可以简写为:@MyAnnotation("hello")
@MyAnnotation()//形式二:因为使用的value属性有默认值,此时不用指定,也不会报错。不想要默认值,可以进行修改如:@MyAnnotation(value="hi")
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃饭");
}
}
interface Info{
void show();
}
//student继承了person类,person添加了自定义注解@MyAnnotation(),又因为自定义注解设置了元注解@Inherited具有可继承性,所以
//student也有@MyAnnotation()注解。如何证明student继承了注解??---->通过反射
class Student extends Person implements Info{
@Override
public void walk() {
System.out.println("学生走路");
}
public void show() {
}
}
定义注解:
package com.atguigu.java1;
/**
* 如何自定义注解:参照@SuppressWarnings定义
* ① 注解声明为:@interface
* ② 内部定义成员,通常使用value表示
* ③ 可以指定成员的默认值,使用default定义
* ④ 如果自定义注解没有成员,表明是一个标识作用。public @interface MyAnnotation {},使用时也不需要写属性值
*
* 注意:
*1. 如果注解有成员,在使用注解时,需要指明成员的值。
*2. 自定义注解必须配上注解的信息处理流程(使用反射)才有意义。
*3. 自定义注解通过都会指明两个元注解:Retention、Target---详情查看3.6元注解
*
*/
public @interface MyAnnotation {
//如果只有一个参数成员,建议使用参数名为value。注意这是一个属性不是方法,虽然有()。
//String value() ;//形式一:可以是任意类型的,如果value值可以指定多个可以定义为数组如:String[] value() ;
String value() default "hello";//形式二:通过default关键字指定一个默认值
}
使用注解:
package com.atguigu.java1;
public class AnnotationTest {
public static void main(String[] args) {
Person p = new Student();
p.walk();
}
}
//@MyAnnotation(value="hello")//形式一:使用注解,因为自定义注解@MyAnnotation有变量value,所以这里需要指定一个值 否则会报错。暂时随便指定个值,没有特殊含义。只有一个值可以简写为:@MyAnnotation("hello")
@MyAnnotation()//形式二:因为使用的value属性有默认值,此时不用指定,也不会报错。不想要默认值,可以进行修改如:@MyAnnotation(value="hi")
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃饭");
}
}
interface Info{
void show();
}
class Student extends Person implements Info{
@Override
public void walk() {
System.out.println("学生走路");
}
public void show() {
}
}
类AnnotationTest:
package com.atguigu.java1;
import java.util.ArrayList;
public class AnnotationTest {
public static void main(String[] args) {
Person p = new Student();
p.walk();
}
}
//@MyAnnotation(value="hello")//形式一:使用注解,因为自定义注解@MyAnnotation有变量value,所以这里需要指定一个值 否则会报错。暂时随便指定个值,没有特殊含义.只有一个值可以简写为:@MyAnnotation("hello")
//@MyAnnotation()//形式二:因为使用的value属性有默认值,此时不用指定,也不会报错。不想要默认值,可以进行修改如:@MyAnnotation(value="hi")
//jdk 8之前的写法想要使用重复的注解:想要写多个注解,在自定义注解MyAnnotations中声明为MyAnnotation类型的数组:MyAnnotation[] value();
//@MyAnnotations({@MyAnnotation(value="hi"),@MyAnnotation(value="hi")})
//jdk 8开始想要这样使用重复的注解:
@MyAnnotation(value="hi")
@MyAnnotation(value="abc")
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃饭");
}
}
interface Info{
void show();
}
//student继承了person类,person添加了自定义注解@MyAnnotation(),又因为自定义注解设置了元注解@Inherited具有可继承性,所以
//student也有@MyAnnotation()注解。如何证明student继承了注解??---->通过反射
class Student extends Person implements Info{
@Override
public void walk() {
System.out.println("学生走路");
}
public void show() {
}
}
//类型注解的使用:
class Generic<@MyAnnotation T>{
public void show() throws @MyAnnotation RuntimeException{
ArrayList<@MyAnnotation String> list = new ArrayList<>();
int num = (@MyAnnotation int) 10L;
}
}
注解MyAnnotation:
package com.atguigu.java1;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
/**
* 1.如何自定义注解:参照@SuppressWarnings定义
* ① 注解声明为:@interface
* ② 内部定义成员,通常使用value表示
* ③ 可以指定成员的默认值,使用default定义
* ④ 如果自定义注解没有成员,表明是一个标识作用。public @interface MyAnnotation {},使用时也不需要写属性值
*
* 注意:
* 如果注解有成员,在使用注解时,需要指明成员的值。
* 自定义注解必须配上注解的信息处理流程(使用反射)才有意义。
* 自定义注解通过都会指明两个元注解:Retention、Target
*
* 2.jdk 提供的4种元注解
* 元注解:对现有的注解进行解释说明的注解
* Retention:指定所修饰的 Annotation 的生命周期:SOURCE(在源文件中有效)\CLASS(默认行为, 在class文件中有效)\RUNTIME(在运行时有效)
* 只有声明为RUNTIME生命周期的注解,才能通过反射获取。
* Target:用于指定被修饰的 Annotation 能用于修饰哪些程序元素:如果不指定则代表那都可以用。
* ElementType.ANNOTATION_TYPE 应用于注释类型
* ElementType.CONSTRUCTOR 应用于构造函数
* ElementType.FIELD 应用于字段或属性
* ElementType.LOCAL_VARIABLE 应用于局部变量
* ElementType.METHOD 应用于方法级
* ElementType.PACKAGE 应用于包声明
* ElementType.PARAMETER 应用于方法的参数
* ElementType.TYPE 应用于类的元素
* *******出现的频率较低*******
* Documented:表示所修饰的注解在被javadoc解析时,保留下来。默认情况下,javadoc是不包括注解的。定义为Documented的注解必须设置Retention值为RUNTIME。
*
* Inherited:被它修饰的 Annotation 将具有继承性。如果某个类使用了被@Inherited 修饰的 Annotation, 则其子类将自动具有该注解。
* 如何证明子类继承了注解--->通过反射获取注解信息 ---到反射内容时系统讲解
* 3.可重复注解:① 在MyAnnotation上声明@Repeatable,成员值为MyAnnotations.class
* ② MyAnnotation的Target和Retention等元注解(如:@Inherited)与MyAnnotations相同。
* 4. 类型注解写在@Target注解中:
* ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中(如:泛型声明)。
* ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
@Inherited
@Repeatable(MyAnnotations.class)//jdk 8开始想要这样使用重复的注解
public @interface MyAnnotation {
//如果只有一个参数成员,建议使用参数名为value。注意这是一个属性不是方法,虽然有()。
//String value() ;//形式一:可以是任意类型的,如果value值可以指定多个可以定义为数组如:String[] value() ;
String value() default "hello";//形式二:通过default关键字指定一个默认值
}
注解MyAnnotations:
package com.atguigu.java1;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Inherited
public @interface MyAnnotations {
MyAnnotation[] value();// jdk 8之前的写法:想要写多个注解声明为数组
}