Java基础:面向对象编程8

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 注解

/*** @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 注解。

/*** @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

/*** @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

/*** @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));}
}

运行结果:

{"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

public enum PlayerType {TENNIS,FOOTBALL,BASKETBALL
}

2.2.1 反编译后的字节码

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 枚举的作用域

  • 内部类:枚举可以定义在一个类的内部,作用域限定于外部类中。
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 语句,与基本数据类型的用法一致。
  • 示例
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,此时需要为枚举添加一个带参的构造方法,这样就可以在定义枚举时添加对应的名称了。

  • 示例
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,可以使用静态工厂方法。
  • 示例
/*** @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);}
}

运行结果:

[]
[TENNIS, FOOTBALL, BASKETBALL]

分析:

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

2.8 EnumMap

  • 定义EnumMap 是专门针对枚举类型的 Map 接口的实现类,效率比 HashMap 高。
  • 创建:可以使用 new 关键字创建 EnumMap
  • 示例
/*** @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));}
}

运行结果:

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

2.9 枚举实现单例

2.9.1 概念

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

2.9.2 volatile、synchronized关键字实现单例

/*** @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 枚举实现单例

/*** @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.mzph.cn/web/56112.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git配置以及如何删除git

你努力学习和充实自己&#xff0c;除了提升自身的价值&#xff0c;最实际的是当遇到有喜欢的人和事的时候&#xff0c;除了一片真心&#xff0c;还有拿得出手的东西 作用 记录开发的历史&#xff0c;每次记录就是一个版本&#xff0c;而且可以回到历史的某个版本可以实现多人合…

浅谈普通学历编码学生代码编程之路--24程序员节

#1024程序员节 | 征文# 今夕已是2024年&#xff0c;楼主是一名大四学生 &#xff0c;即将进入社会&#xff0c;曾经总是拿码农来开程序员的玩笑 &#xff0c;也是也是幻想着成为一名码农啊&#xff0c;先说说个人学习Java之路 &#xff0c;从步入大学开始就是主学Java&#xff…

【MyBatis】MyBatis缓存原理详解

目录 一、简介 二、缓存类介绍 2.1 PerpetualCache 2.2 LruCache 2.3 BlockingCache 三、CacheKey 3.1 总结&#xff1a;二级缓存命中条件 四、一级缓存 五、二级缓存 5.1 二级缓存如何组装这些装饰器&#xff1f;&#xff08;解析SQL映射文件中的标签&#xff0c;初…

2025青海选调生报名指南及照片要求

第一步&#xff1a;用户信息注册&#xff0c;仔细阅读公告内容 第二步&#xff1a;人脸识别认证、上传照片 第三步&#xff1a;确认基本信息、照片确认 第四步&#xff1a;填写报考信息&#xff0c;请务必于11月5日18:00前提交 第五步&#xff1a;打印报名表&#xff0c;下载《…

.net framework 3.5sp1插件怎么安装

以下是在不同操作系统电脑上安装.NET Framework 3.5 SP1 的几种常见方法&#xff1a; 一、Windows 10 及以上操作系统&#xff1a; 1.在线安装&#xff08;需要网络连接稳定&#xff09;&#xff1a; 按键盘上的 Windows 键&#xff0c;键入 “Windows 功能”&#xff0c;然…

Linux网络编程(五)-什么是TCP/IP协议族全面解读

1.什么是TCP/IP协议族 在了解TCP和UDP之前&#xff0c;我们先了解TCP/IP协议族&#xff0c;首先这个协议族的的由来&#xff0c;在一开始很多电脑表达一个消息的方法可谓是多种多样&#xff0c;因为它们运行着完全不同的操作系统&#xff0c;这就像有不同口音&#xff0c;说不…

【9712】基于springboot+vue的校园台球厅人员与设备管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 项目描述 本次设计任务是要设计一个校园台球厅人员与设备管理系统…

基于java+springboot的大型超市数据处理系统

文章目录 前言技术介绍功能介绍核心代码数据库参考 系统效果图 前言 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;大型超市数据处理系统当然不能排除在外。大型超市数据处理系统是在实际应用…

SpringBoot框架实战:打造宠物用品电商平台

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

SpringCloud之注册中心Consul使用详解

SpringCloud之注册中心Consul使用详解 在上个月我们知道 Eureka 2.X 遇到困难停止开发了&#xff0c;但其实对国内的用户影响甚小&#xff0c;一方面国内大都使用的是 Eureka 1.X 系列&#xff0c;另一方面 Spring Cloud 支持很多服务发现的软件&#xff0c;Eureka 只是其中之…

深入探索Python集合(Set)的高效应用:数据处理、性能优化与实际案例分析

文章目录 前言&#x1fa81;一、 定义集合1.1 使用大括号 {} 定义集合1.2 使用 set() 函数定义集合 &#x1fa81;二、添加元素2.1 使用 add() 方法2.2 使用 update() 方法 &#x1fa81;三、移除元素3.1 使用 remove() 方法3.2 使用 discard() 方法3.3 使用 pop() 方法3.4 使用…

【氮化镓】低温对p-GaN HEMT迁移率、阈值电压和亚阈值摆幅的影响

本期分享一篇低温对p-GaN HEMT 迁移率、阈值电压和亚阈值摆幅影响进行表征和建模的研究论文。文章作者Shivendra Kumar Singh、Thien Sao Ngo、Tian-Li Wu(通讯作者)和Yogesh Singh Chauhan,分别来资源中国台湾阳明交通大学国际半导体技术学院、印度理工学院坎普尔分校电气工…

缓存常见问题:缓存穿透、雪崩、击穿及解决方案分析

1. 什么是缓存穿透&#xff0c;怎么解决&#xff1f; 缓存穿透是指用户请求的数据在缓存中不存在即没有命中&#xff0c;同时在数据库中也不存在&#xff0c;导致用户每次请求该数据都要去数据库中查询一遍。如果有恶意攻击者不断请求系统中不存在的数据&#xff0c;会导致短时…

西南交通大学计算机软件专业上岸难度分析

C哥专业提供——计软考研院校选择分析专业课备考指南规划 西南交通大学计算机科学与技术2024届考研难度整体呈现"稳中有升"的态势。学硕实际录取33人&#xff0c;复试分数线362分&#xff0c;复试录取率71.74%&#xff1b;专硕&#xff08;计算机技术&#xff09;实际…

【数据结构笔记】408二叉树、堆、AVL、图、拓扑排序

文章目录 堆和二叉树一、定义与性质二、结构特点三、应用场景四、查找效率解释荷兰围棋问题拓扑排序的树 逆拓扑排序邻接表的存储 二叉树、二叉平衡树、图刷题笔记 堆和二叉排序树是数据结构中两种不同的树状结构&#xff0c;它们之间存在显著的区别。以下是对这两种数据结构的…

通过SSH远端免密登录执行脚本,修改最新5分钟生成文件权限

通过SSH远端免密登录执行脚本&#xff0c;修改最新5分钟生成文件权限 一、准备工作二、脚本内容三、使用脚本四、注意事项 在日常的系统管理中&#xff0c;经常需要对远程服务器上的文件进行操作。本文将介绍如何通过SSH远端免密登录&#xff0c;执行一个脚本来查找某目录下最新…

半导体材料ERP系统在生产计划管理方面的应用

在科技日新月异的今天&#xff0c;半导体材料作为信息技术的基石&#xff0c;其生产效率与质量管理直接关系到整个产业链的竞争力。为了精准把控生产流程&#xff0c;优化资源配置&#xff0c;半导体行业正积极引入高科技的ERP(企业资源计划)系统&#xff0c;特别是在生产计划管…

关于vue3中如何实现多个v-model的自定义组件

实现自定义组件<User v-model"userInfo" v-model:gender"gender"></User> User组件中更改数据可以同步更改父组件中的数据&#xff1a; 1 父组件&#xff1a; <User v-model"userInfo" v-model:gender"gender">&…

LabVIEW程序员可以从哪几个方面提升自己?有没有详细的路线图?

作为一名LabVIEW程序员&#xff0c;要在快速发展的技术领域保持竞争力并不断提升自己&#xff0c;需要从多个方面进行持续的学习和实践。下面我将为你详细说明LabVIEW程序员提升自己的几个关键方向&#xff0c;并给出具体的成长路线图。 1. 夯实基础&#xff1a;掌握LabVIEW的…

【D3.js in Action 3 精译_035】4.1 D3 中的坐标轴的创建(下篇):坐标轴与轴标签的具体实现

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…