2011-3-9(java的传值方式)

本文通过实例解析了Java中向JSONArray填充JSON对象时常见的错误及其原因,并提供了正确的实现方法。

    以前在书上看到过,java的基础数据类型的传值是值传递,而非基础类型的传值为引用传值(传的是放数据的对象的地址)。对java的传值方式没有很深刻的理解。通过这次犯的错误,使我对java的传值方式理解了一点。

 

我是想把一条一条的记录通过jo放入到jsonArr中。

错误代码:

 

 

JSONObject jo = new JSONObject();

for (i = 1; i < bbsTagOptionList.size()+1; i++) {
                BbsSubject bs = (BbsSubject) bbsTagOptionList.get(i-1);
                Long bbsSubjectId = bs.getId();
                String name = bs.getName();
                jo.put("bbsSubjectId", bbsSubjectId);
                jo.put("name", name);
                jsonArr.put(i, jo);
            }

打印输出后,jsonArr中所有的数据都跟最后一条数据一样(jsonArr[0]==jsonArr[1]==jsonArr[2]),很不明白。

只好求助师姐,师姐很快发现了问题的所在。jsonArr.put(i,jo);只是把jo的地址传进了jsonArr中。而我写的错误代码中只声明了一个JsonArray对象,当然jsonArr中的放的都是同一个地址,当然每条值根据地址找到的都是最后一次放入jo中的值。

 

 

正确代码:

for (i = 1; i < bbsTagOptionList.size()+1; i++) {
                BbsSubject bs = (BbsSubject) bbsTagOptionList.get(i-1);
                Long bbsSubjectId = bs.getId();
                String name = bs.getName();

                JsonObject jo=new JsonObject();
                jo.put("bbsSubjectId", bbsSubjectId);
                jo.put("name", name);
                jsonArr.put(i, jo);
            }

<think>我们正在讨论的问题是:为什么在使用`@JsonFormat(pattern = "yyyy-MM-dd")`注解时,日期显示为包含时间部分(如`2025-08-15 00:00:00.000`)? 根据引用[1]和引用[2]的内容,我们知道`@JsonFormat`是Jackson库提供的注解,用于指定日期字段在序列化(Java对象转JSON)时的格式。但是,如果日期字段在Java中是`java.util.Date`或`java.sql.Date`类型,它们本质上包含时间信息(即使我们只关心日期部分)。当我们使用`@JsonFormat(pattern = "yyyy-MM-dd")`时,我们期望只显示日期部分(如`2025-08-15`),但有时却显示为完整的时间格式(如`2025-08-15 00:00:00.000`),这可能是由于以下原因: 1. **注解未生效**:可能由于配置问题,Jackson没有使用指定的格式进行序列化。 2. **时区问题**:如果未指定时区,Jackson可能使用默认时区(UTC),导致日期转换时出现偏差(如引用[1]中提到的夏令时问题),但这里更直接的问题是格式不对。 3. **实际类型问题**:如果字段是`java.util.Date`,它包含日期和时间。当我们只指定日期格式时,时间部分会被忽略,但序列化后仍然会显示为`00:00:00`(如果时间部分为0)?实际上,按照指定的格式,应该只显示日期部分。 然而,问题描述中显示的是包含时间部分,这显然与期望不符。这通常是因为: - 可能没有正确使用`@JsonFormat`注解,或者Jackson的配置覆盖了注解。 - 可能同时存在其他格式化配置(如全局配置)与注解冲突。 引用[3]中提到,可以在yaml配置文件中设置全局的日期格式: ```yaml jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 ``` 如果全局配置了日期格式(包含时间部分),那么即使使用`@JsonFormat(pattern = "yyyy-MM-dd")`,也会被全局配置覆盖。 因此,解决这个问题的步骤: 1. **检查全局配置**:查看是否在application.yml或application.properties中配置了Jackson的全局日期格式。如果全局格式包含时间部分,那么需要移除全局配置或者通过注解覆盖全局配置(注解优先级更高)。 2. **确保注解正确使用**:在需要只显示日期的字段上,使用`@JsonFormat(pattern = "yyyy-MM-dd")`,并指定时区(避免时区转换问题),如: ```java @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private Date birthday; ``` 3. **检查字段类型**:如果可能,使用`java.time.LocalDate`(Java8及以上)代替`java.util.Date`,因为`LocalDate`只包含日期部分,不包含时间。这样即使不指定格式,序列化时默认也是`yyyy-MM-dd`(但为了明确,最好还是指定格式)。 如果使用`LocalDate`类型,并且正确使用注解,就不会有时间部分出现。 4. **检查Jackson的版本和配置**:确保Jackson库的版本支持`@JsonFormat`注解,并且没有其他自定义配置覆盖了注解。 示例代码: 使用`java.time.LocalDate`: ```java public class User { @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate birthday; // 其他字段及getter/setter } ``` 使用`java.util.Date`(需要指定时区): ```java public class User { @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private Date birthday; } ``` 5. **检查序列化工具**:确保使用的是Jackson进行序列化。如果项目中同时有多个JSON库(如Fastjson),可能会发生冲突,导致注解不生效。 引用[4]提到,`@JSONField`是Fastjson的注解,而`@JsonFormat`是Jackson的注解。如果项目中使用的是Fastjson,那么`@JsonFormat`可能不会生效,需要使用`@JSONField(format="yyyy-MM-dd")`。 因此,总结可能的原因: - 原因1:全局Jackson配置覆盖了注解的格式。 - 原因2:字段类型为`java.util.Date`,且没有正确指定时区,导致序列化时使用了默认格式(包含时间)。 - 原因3:使用了不支持`@JsonFormat`的JSON库(如Fastjson)进行序列化。 解决方案: - 方案1:移除Jackson的全局日期格式配置,或者确保全局配置与注解一致。 - 方案2:在注解中明确指定时区(如`timezone="GMT+8"`)。 - 方案3:将字段类型改为`java.time.LocalDate`(推荐,因为它只表示日期)。 - 方案4:如果使用Fastjson,改用`@JSONField`注解。 最后,如果问题仍然存在,可以检查序列化过程是否真的经过了Jackson,或者是否有其他拦截器修改了日期格式。 下面是一个完整的示例,展示如何正确使用注解: 实体类(使用`java.util.Date`): ```java import com.fasterxml.jackson.annotation.JsonFormat; import java.util.Date; public class User { @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private Date birthday; // getter and setter } ``` 或者在配置文件中设置全局格式(但注意,全局格式会应用到所有日期字段,如果有些字段需要不同的格式,则仍需使用注解): ```yaml spring: jackson: date-format: yyyy-MM-dd # 全局设置日期格式为只有日期 time-zone: GMT+8 ``` 注意:全局设置后,所有日期字段都会按照这个格式序列化,如果某个字段需要显示时间,就需要在该字段上单独使用`@JsonFormat`指定其他格式。 因此,根据具体需求选择全局配置或注解配置。 希望这个解释能帮助您解决问题。</think>### 为什么使用 `@JsonFormat(pattern = "yyyy-MM-dd")` 时日期显示包含时间部分? 当使用 `@JsonFormat(pattern = "yyyy-MM-dd")` 注解后日期仍显示为 `2025-08-15 00:00:00.000` 格式,主要源于以下三个核心原因: --- #### 1. **Java 日期类型的本质问题** ⚙️ Java 的 `java.util.Date` 或 `java.sql.Date` **本质是时间戳**,包含完整的日期和时间信息(精确到毫秒)。即使你只想表示日期,底层仍然存储为 `2025-08-15 00:00:00.000` 格式。 **示例代码**: ```java // 即使只设置日期,底层仍包含时间部分 Date date = new Date(125, 7, 15); // 2025-08-15 00:00:00.000 ``` --- #### 2. **序列化时的格式覆盖** 🔄 若项目中存在 **全局 Jackson 配置**(如 `application.yml`),它会覆盖字段级别的 `@JsonFormat` 注解: ```yaml # application.yml(全局配置优先于注解) jackson: date-format: yyyy-MM-dd HH:mm:ss # 强制所有日期带时间 ``` **冲突优先级**: `全局配置` > `@JsonFormat注解` > `Jackson默认行为` --- #### 3. **时区未显式声明引发表观错误** 🌐 未指定 `timezone` 属性时,Jackson 默认使用 **UTC 时区** 序列化。如果系统时区是 `GMT+8`,会导致: ```java // 假设系统时间:2025-08-15 08:00:00 (GMT+8) @JsonFormat(pattern = "yyyy-MM-dd") // 无时区声明 private Date date; // 序列化结果(UTC时间):2025-08-14 16:00:00 -> 显示为前一日 ``` --- ### 解决方案 ✅ #### 方法 1:强制清除时间部分(推荐) 改用 `java.time.LocalDate` 类型(Java 8+),它**仅存储日期**: ```java import java.time.LocalDate; @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate birthday; // 存储为纯日期 2025-08-15 ``` #### 方法 2:显式声明时区 ```java @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private Date birthday; // 解决时区偏差 ``` #### 方法 3:检查并调整全局配置 ```yaml # application.yml(与注解保持一致) jackson: date-format: yyyy-MM-dd # 全局仅显示日期 time-zone: GMT+8 # 指定时区 ``` #### 方法 4:前端格式化辅助 若无法修改后端,在前端处理: ```javascript // JavaScript 示例 const dateOnly = new Date(fullDateStr).toISOString().split(&#39;T&#39;)[0]; // "2025-08-15" ``` --- ### 关键总结 | 问题根源 | 解决方案 | 效果 | |-------------------------|-----------------------------------|--------------------------| | `Date` 类型包含时间 | 改用 `LocalDate` | 纯日期存储 | | 全局配置覆盖注解 | 检查/修改 `application.yml` | 确保格式一致 | | 时区未声明导致偏移 | 添加 `timezone = "GMT+8"` | 避免日期跳变 | | 序列化机制默认行为 | 前端二次格式化 | 临时补救方案 | > **最佳实践**:Java 8+ 项目统一使用 `java.time` 包(`LocalDate`/`LocalDateTime`),避免统 `Date` 类的设计缺陷[^1][^3]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值