Java基础:面向对象编程8

server/2024/10/20 21:03:56/

1 Java 注解

1.1 概念

  • 定义:注解(Annotation)是在 Java 1.5 时引入的概念,同 classinterface 一样,属于一种类型。
  • 作用:注解提供了一系列数据用来装饰程序代码(类、方法、字段等),但注解并不是所装饰代码的一部分,它对代码的运行效果没有直接影响,由编译器决定该执行哪些操作。

1.2 注解的生命周期策略

  • 定义:定义在 RetentionPolicy 枚举中。
  • 类型
    • SOURCE:在源文件中有效,被编译器丢弃。
    • CLASS:在编译器生成的字节码文件中有效,但在运行时会被处理类文件的 JVM 丢弃。
    • RUNTIME:在运行时有效。这是注解生命周期中最常用的一种策略,它允许程序通过反射的方式访问注解,并根据注解的定义执行相应的代码。

1.3 注解的类型

  • 定义:定义在 ElementType 枚举中。
  • 类型
    • TYPE:用于类、接口、注解、枚举。
    • FIELD:用于字段(类的成员变量),或者枚举常量。
    • METHOD:用于方法。
    • PARAMETER:用于普通方法或者构造方法的参数。
    • CONSTRUCTOR:用于构造方法。
    • LOCAL_VARIABLE:用于变量。
    • ANNOTATION_TYPE:用于注解。
    • PACKAGE:用于包。
    • TYPE_PARAMETER:用于泛型参数。
    • TYPE_USE:用于声明语句、泛型或者强制转换语句中的类型。
    • MODULE:用于模块。

1.4 代码示例

1.4.1 编写JsonField 注解

java">/*** @package: com.yunyang.javabetter.oop.annotation* @description: 自定义JsonField 注解* @author: Yunyang* @date: 2024/10/16  14:18* @version:1.0**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonField {public String value() default "";
}

分析:

  • JsonField 注解的生命周期是 RUNTIME,也就是运行时有效。
  • JsonField 注解装饰的目标是 FIELD,也就是针对字段的。
  • 创建注解需要用到 @interface 关键字。
  • JsonField 注解有一个参数,名字为 value,类型为 String,默认值为一个空字符串。
  • value 允许注解的使用者提供一个无需指定名字的参数。举个例子,我们可以在一个字段上使用 @JsonField(value = “沉默王二”),也可以把 value = 省略,变成 @JsonField(“沉默王二”)。
  • default ""允许我们在一个字段上直接使用 @JsonField,而无需指定参数的名和值。

1.4.2 编写Writer

假设有一个 Writer 类,他有 3 个字段,分别是 age、name 和 bookName,后 2 个是必须序列化的字段。就可以这样来用 @JsonField 注解。

java">/*** @package: com.yunyang.javabetter.oop.annotation* @description: Writer类* @author: Yunyang* @date: 2024/10/16  14:26* @version:1.0**/
public class Writer {private int age;@JsonField("writerName")private String name;@JsonFieldprivate String bookName;public Writer(int age, String name, String bookName) {this.age = age;this.name = name;this.bookName = bookName;}// getter / setter@Overridepublic String toString() {return "Writer{" +"age=" + age +", name='" + name + '\'' +", bookName='" + bookName + '\'' +'}';}
}

分析:

  • name 上的 @JsonField 注解提供了显式的字符串值。
  • bookName 上的 @JsonField 注解使用了缺省项。

1.4.3 编写序列化类 JsonSerializer

java">/*** @package: com.yunyang.javabetter.oop.annotation* @description: 序列化类 JsonSerializer* @author: Yunyang* @date: 2024/10/16  14:27* @version:1.0**/
public class JsonSerializer {/*** serialize() 方法是用来序列化对象的,它接收一个 Object 类型的参数* @param object* @return* @throws IllegalAccessException*/public static String serialize(Object object) throws IllegalAccessException {Class<?> objectClass = object.getClass();Map<String, String> jsonElements = new HashMap<>();// objectClass.getDeclaredFields()// 通过反射的方式获取对象声明的所有字段,然后进行 for 循环遍历for (Field field : objectClass.getDeclaredFields()) {// 通过 field.setAccessible(true) 将反射对象的可访问性设置为 true,供序列化使用field.setAccessible(true);// 通过 isAnnotationPresent() 判断字段是否装饰了 JsonField 注解if(field.isAnnotationPresent(JsonField.class)){// 如果是的话,调用 getSerializedKey() 方法,以及获取该对象上由此字段表示的值,并放入 jsonElements 中jsonElements.put(getSerializedKey(field), (String) field.get(object));}}return toJsonString(jsonElements);}/*** getSerializedKey() 方法用来获取字段上注解的值,如果注解的值是空的,则返回字段名* @param field* @return*/private static String getSerializedKey(Field field) {String annotationValue = field.getAnnotation(JsonField.class).value();if(annotationValue.isEmpty()){return field.getName();} else {return annotationValue;}}/*** toJsonString() 方法借助 Stream 流的方式返回格式化后的 JSON 字符串* @param jsonMap* @return*/private static String toJsonString(Map<String, String> jsonMap) {String elementsString = jsonMap.entrySet().stream().map(entry -> "\"" + entry.getKey() + "\":\"" + entry.getValue() + "\"").collect(Collectors.joining(","));return "{" + elementsString + "}";}}

1.4.4 测试类 JsonFieldTest

java">/*** @package: com.yunyang.javabetter.oop.annotation* @description: 测试类 JsonFieldTest* @author: Yunyang* @date: 2024/10/16  14:42* @version:1.0**/
public class JsonFieldTest {public static void main(String[] args) throws IllegalAccessException {Writer writer = new Writer(18, "zhangsan", "Java进阶之路");System.out.println(JsonSerializer.serialize(writer));}
}

运行结果:

java">{"bookName":"Java进阶之路","writerName":"zhangsan"}

分析:

  • Writer 类的 age 字段没有装饰 @JsonField 注解,所以没有序列化
  • Writer 类的 name 字段装饰了 @JsonField 注解,并且显示指定了字符串“writerName”,所以序列化后变成了 writerName
  • Writer 类的 bookName 字段装饰了 @JsonField 注解,但没有显式指定值,所以序列化后仍然是 bookName

2 Java 枚举

2.1 概念

  • 定义:枚举(enum)是 Java 1.5 时引入的关键字,表示一种特殊类型的类,继承自 java.lang.Enum

2.2 新建枚举 PlayerType

java">public enum PlayerType {TENNIS,FOOTBALL,BASKETBALL
}

2.2.1 反编译后的字节码

java">public final class PlayerType extends Enum
{public static PlayerType[] values(){return (PlayerType[])$VALUES.clone();}public static PlayerType valueOf(String name){return (PlayerType)Enum.valueOf(com/cmower/baeldung/enum1/PlayerType, name);}private PlayerType(String s, int i){super(s, i);}public static final PlayerType TENNIS;public static final PlayerType FOOTBALL;public static final PlayerType BASKETBALL;private static final PlayerType $VALUES[];static {TENNIS = new PlayerType("TENNIS", 0);FOOTBALL = new PlayerType("FOOTBALL", 1);BASKETBALL = new PlayerType("BASKETBALL", 2);$VALUES = (new PlayerType[] {TENNIS, FOOTBALL, BASKETBALL});}
}

2.2.2 Java 编译器对枚举的隐式工作

  • 继承:枚举类隐式继承自 java.lang.Enum
  • 构造方法:编译器会为枚举生成一个私有的构造方法。
  • 静态变量和数组:编译器会为枚举生成静态变量和数组来存储枚举常量。
  • 静态块:编译器会使用静态块来初始化静态变量和数组。
  • 静态方法:编译器会提供 values()valueOf(String name) 等静态方法。

2.3 枚举的作用域

  • 内部类:枚举可以定义在一个类的内部,作用域限定于外部类中。
java">public class Player {private PlayerType type;public enum PlayerType {TENNIS,FOOTBALL,BASKETBALL}public boolean isBasketballPlayer() {return getType() == PlayerType.BASKETBALL;}public PlayerType getType() {return type;}public void setType(PlayerType type) {this.type = type;}
}

分析:

PlayerType 就相当于 Player 的内部类

2.4 枚举的比较

  • 使用 == 运算符:由于枚举是 final 的,可以使用 == 运算符比较两个枚举是否相等。
  • 不使用 equals() 方法
    • == 运算符在比较时不会抛出 NullPointerException
    • == 运算符在编译时会检查类型匹配,而 equals() 方法不会。

2.5 枚举与 switch 语句

  • 用法:枚举可以用于 switch 语句,与基本数据类型的用法一致。
  • 示例
java">switch (playerType) {case TENNIS:return "网球运动员费德勒";case FOOTBALL:return "足球运动员C罗";case BASKETBALL:return "篮球运动员詹姆斯";case UNKNOWN:throw new IllegalArgumentException("未知");default:throw new IllegalArgumentException("运动员类型: " + playerType);}

2.6 枚举与带参数的构造方法

如果枚举中需要包含更多信息的话,可以为其添加一些字段,比如下面示例中的 name,此时需要为枚举添加一个带参的构造方法,这样就可以在定义枚举时添加对应的名称了。

  • 示例
java">public enum PlayerType {TENNIS("Tennis"),FOOTBALL("Football"),BASKETBALL("Basketball");private String name;PlayerType(String name) {this.name = name;}public String getName() {return name;}
}

2.7 EnumSet

  • 定义EnumSet 是专门针对枚举类型的 Set 接口的实现类,非常高效。
  • 创建:不能使用 new 关键字创建 EnumSet,可以使用静态工厂方法。
  • 示例
java">/*** @package: com.yunyang.javabetter.oop.enumdemo* @description:  EnumSet* @author: Yunyang* @date: 2024/10/16  15:28* @version:1.0**/
public class EnumSetTest {public enum PlayerType{TENNIS,FOOTBALL,BASKETBALL}public static void main(String[] args) {EnumSet<PlayerType> enumSetNone = EnumSet.noneOf(PlayerType.class);System.out.println(enumSetNone);EnumSet<PlayerType> enumSetAll = EnumSet.allOf(PlayerType.class);System.out.println(enumSetAll);}
}

运行结果:

java">[]
[TENNIS, FOOTBALL, BASKETBALL]

分析:

使用 noneOf() 静态工厂方法创建了一个空的 PlayerType 类型的 EnumSet;使用 allOf() 静态工厂方法创建了一个包含所有 PlayerType 类型的 EnumSet。

2.8 EnumMap

  • 定义EnumMap 是专门针对枚举类型的 Map 接口的实现类,效率比 HashMap 高。
  • 创建:可以使用 new 关键字创建 EnumMap
  • 示例
java">/*** @package: com.yunyang.javabetter.oop.enumdemo* @description: EnumMap* @author: Yunyang* @date: 2024/10/16  15:33* @version:1.0**/
public class EnumMapTest {public enum PlayerType {TENNIS("网球"),FOOTBALL("足球"),BASKETBALL("篮球");private String name;PlayerType(String name) {this.name = name;}}public static void main(String[] args) {EnumMap<PlayerType, String> enumMap = new EnumMap<>(PlayerType.class);enumMap.put(PlayerType.BASKETBALL,"篮球运动员");enumMap.put(PlayerType.FOOTBALL,"足球运动员");enumMap.put(PlayerType.TENNIS,"网球运动员");System.out.println(enumMap);System.out.println(enumMap.get(PlayerType.BASKETBALL));System.out.println(enumMap.get(PlayerType.FOOTBALL));System.out.println(enumMap.get(PlayerType.TENNIS));System.out.println(enumMap.containsKey(PlayerType.TENNIS));}
}

运行结果:

java">{TENNIS=网球运动员, FOOTBALL=足球运动员, BASKETBALL=篮球运动员}
篮球运动员
足球运动员
网球运动员
true

2.9 枚举实现单例

2.9.1 概念

  • 单例模式:保证一个类仅有一个对象,并提供全局访问点。
  • Java 标准库有一些类就是单例,比如说 Runtime 这个类

2.9.2 volatile、synchronized关键字实现单例

java">/*** @package: com.yunyang.javabetter.oop.enumdemo* @description: volatile、synchronized关键字实现单例* @author: Yunyang* @date: 2024/10/16  15:38* @version:1.0**/
public class Singleton {private volatile static Singleton singleton;private Singleton() {}public static Singleton getSingleton() {if(singleton == null){synchronized (Singleton.class){if(singleton == null){singleton = new Singleton();}}}return singleton;}
}

2.9.3 枚举实现单例

java">/*** @package: com.yunyang.javabetter.oop.enumdemo* @description: 枚举实现单例* @author: Yunyang* @date: 2024/10/16  15:40* @version:1.0**/
public enum EasySingleton {INSTANCE;
}
  • 优点:枚举默认实现了 Serializable 接口,Java 虚拟机保证该类为单例。

3 思维导图

在这里插入图片描述
在这里插入图片描述

4 参考链接

  1. Java注解,请别小看我
  2. Java枚举:小小enum,优雅而干净

http://www.ppmy.cn/server/133446.html

相关文章

基于MATLAB的交通标志的识别

一、背景 随着交通技术的日益完善和交通工具的多样化发展&#xff0c;交通安全成为当前最热门的问 题&#xff0c;道路交通关系着人们的生命以及财产安全。 交通标志的识别是保证交通安全的一个重要环节。交通标识包含丰富的道路交通信 息&#xff0c;为驾驶员提供警示、指示…

C++ 11 的 codecvt 与编码转换

1 编码与乱码 乱码产生的主要原因是编码与字符集不匹配&#xff0c;这种不匹配时怎么造成的呢&#xff1f;首先要来了解一下编码和字符集的关系。 1.1 编码与字符集 由于标准的英文 ASCII 已经成了全球标准&#xff0c;每台电脑的 BIOS 里存着一份标准 ASCII 表&#xff08;…

基于K8S的StatefulSet部署mysql主从

StatefulSet特性 StatefulSet的网络状态 拓扑状态&#xff1a;应用的多个实例必须按照某种顺序启动&#xff0c;并且必须成组存在&#xff0c;例如一个应用中必须存在一 个A Pod和两个B Pod&#xff0c;且A Pod必须先于B Pod启动的场景 存储状态&#xff1a;应用存在多个实例…

python——pyecharts数据可视化堆叠面积图

堆叠面积图具有以下几个重要作用&#xff1a; 一、展示总量与分量关系 堆叠面积图可以清晰地展示多个数据系列的总量以及各个分量在总量中所占的比例。通过不同颜色或阴影的区域&#xff0c;你可以直观地看出每个数据系列对整体的贡献程度。例如&#xff0c;在分析公司不同业…

LLAMA2入门(一)-----预训练

Llama 2 是预训练和微调的LLM系列&#xff0c;Llama 2 和 Llama 2-Chat 模型的参数规模达到 70B。Llama 2-Chat 模型专门为对话场景进行了优化。 这是一个系列的文章&#xff0c;会分别从LLAMA2的预训练&#xff0c;微调&#xff0c;安全性等方面进行讲解。 1.数据来源 数据…

Java_EE 网络编程(TCP与UDP通信)

传输控制协议&#xff08;TCP&#xff0c;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议&#xff0c;由IETF的RFC 793 定义。 TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机…

基于Springboot+Vue的民宿管理系统(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 在这个…

Lua字符串

软考鸭微信小程序 过软考,来软考鸭! 提供软考免费软考讲解视频、题库、软考试题、软考模考、软考查分、软考咨询等服务 Lua作为一种轻量级、高效的脚本语言&#xff0c;在字符串处理方面提供了丰富的功能和灵活的操作方式。字符串在Lua中是一系列的字节&#xff0c;可以包含任意…