微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

尝试通过将 4 年添加到既定日期来创建新日期时,两个日期都会更改 (GregorianCalendar)

如何解决尝试通过将 4 年添加到既定日期来创建新日期时,两个日期都会更改 (GregorianCalendar)

完全公开,这是作业,但只是作业的一小部分,我无法弄清楚为什么它不起作用。这是作业文本:

创建一个 CollegeStudent 类。这个类将包含数据字段 包含学生的名字、姓氏、注册日期和 预计毕业日期,使用 GregorianCalendar 类为每个 日期。为每个字段提供 get() 和 set() 方法。还提供一个 需要名字和姓氏以及注册日期的构造函数, 并将项目毕业日期设置为恰好四年后 注册。将类保存为 CollegeStudent.java。

创建一个交互式应用程序,提示用户输入两个数据 大学生对象。提示用户输入名字、姓氏、 每个的注册月份、注册日和注册年份 CollegeStudent,然后实例化对象。显示所有 值,包括预计的毕业日期。保存 应用程序作为 TestCollegeStudent.java

我已经能够做它要求的所有事情,除了当我尝试计算毕业日期时,它也会在注册日期值上增加 4 年。这是我的大学生课程:

import java.util.GregorianCalendar;

public class CollegeStudent {

    String firstName;
    String lastName;
    GregorianCalendar enrollmentDate;
    GregorianCalendar graduationDate;
    
    
    // Constructor requiring first name,last name,and enrollment date
    public CollegeStudent(String first,String last,GregorianCalendar enrollment) {
        firstName = first;
        lastName = last;
        enrollmentDate = enrollment;
        
        // Set graduationDate to enrollmentDate,then add 4 years
        graduationDate = enrollment;
        graduationDate.add(GregorianCalendar.YEAR,4);
    }
    // Get and Set firstName
    public void setFirstName(String first) {
        firstName = first;
    }
    public String getFirstName() {
        return firstName;
    }
    
    // Get and Set lastName
    public void setLastName(String last) {
        lastName = last;
    }
    public String getLastName() {
        return lastName;
    }
    
    // Get and Set enrollmentDate
    public void setEnrollmentDate(GregorianCalendar enrollment) {
        enrollmentDate = enrollment;
    }
    public GregorianCalendar getEnrollmentDate(){
        return enrollmentDate;
    }
    
    // Get and Set graduationDate
    public void setGraduationDate(GregorianCalendar graduation) {
        graduationDate = graduation;
    }
    public GregorianCalendar getGraduationDate() {
        return graduationDate;
    }

}

我的 TestCollegeStudent.java 显示注册日期和毕业日期,并且它们都显示用户输入的初始注册日期 4 年后的相同日期。如果删除将 4 年添加到毕业日期的行,它们都显示为初始注册日期。我觉得我遗漏了一些非常简单的语法问题,但我一直无法弄清楚它是什么。

解决方法

这是由于构造函数中的以下赋值而发生的:

graduationDate = enrollment;

此赋值使 graduationDate 引用 Calendar 正在被 enrollment 引用的同一个实例,因此通过任何引用带来的实例更改将导致结果为两个引用都相同。

你可以通过下面的例子来理解:

import java.util.Calendar;
import java.util.GregorianCalendar;

public class Main {
    public static void main(String[] args) {
        Calendar enrollment = Calendar.getInstance();
        Calendar graduationDate = enrollment;
        System.out.println(enrollment.getTime());
        System.out.println(graduationDate.getTime());

        graduationDate.add(GregorianCalendar.YEAR,4);
        System.out.println(enrollment.getTime());
        System.out.println(graduationDate.getTime());
    }
}

输出:

Sat Jan 16 15:31:29 GMT 2021
Sat Jan 16 15:31:29 GMT 2021
Thu Jan 16 15:31:29 GMT 2025
Thu Jan 16 15:31:29 GMT 2025

为了处理这种情况,graduationDate 需要引用被引用实例的副本(克隆)enrollment 以便通过引用带来的任何更改,graduationDate 只会适用于克隆。

import java.util.Calendar;
import java.util.GregorianCalendar;

public class Main {
    public static void main(String[] args) {
        Calendar enrollment = Calendar.getInstance();
        Calendar graduationDate = (Calendar)enrollment.clone();// You have to do this
        System.out.println(enrollment.getTime());
        System.out.println(graduationDate.getTime());

        graduationDate.add(GregorianCalendar.YEAR,4);
        System.out.println(enrollment.getTime());
        System.out.println(graduationDate.getTime());
    }
}

输出:

Sat Jan 16 15:30:34 GMT 2021
Sat Jan 16 15:30:34 GMT 2021
Sat Jan 16 15:30:34 GMT 2021
Thu Jan 16 15:30:34 GMT 2025

顺便说一下,java.util 的日期时间 API 及其格式化 API SimpleDateFormat 已经过时且容易出错。建议完全停止使用它们并切换到 modern date-time API

查看 Trail: Date Time 以获取使用 java.time API(现代日期时间 API)的分步教程和示例。

,

问题是,当您执行 graduationDate = enrollment 时,毕业日期现在指向注册对象,并且您对其中任何一个所做的每个更改都会反映在另一个对象上,因为它们相同 对象。

您真正想要的是创建一个基于另一个日历的日历,它应该是 graduationDate = (GregorianCalendar)enrollment.clone();

,

此线程中已经有一个很好的答案。我正在添加我的贡献。问题的主要来源是这行,其中毕业日期指的是入学

<table class="row"> <tr> <td class="column"></td> <td class="column"></td> <td class="column"></td> </tr> </table>

你也可以试试这个:

graduationDate = enrollment
,

java.time

对于你的作业,它可能不会去,但其他人都应该使用 java.time,现代 Java 日期和时间 API,用于日期工作。 而且!使用 java.time 几乎不可能出现您所询问的错误。

    LocalDate enrollmentDate = LocalDate.of(2021,Month.JANUARY,4);
    LocalDate graduationDate = enrollmentDate.plusYears(4);
    
    System.out.format("Enrolled: %s. Projected graduation: %s.%n",enrollmentDate,graduationDate);

输出为:

注册时间:2021-01-04。预计毕业时间:2025-01-04。

走向需求的边界

如果你想教你的老师如何做到这一点,并且仍然保持字段类型为 GregorianCalendar 的要求...... (1) 我不能说这在你的学校是否可取。 (2) 将是一个折衷,即没有理想的解决方案,既有java.time的优点,又有API混合和不必要的转换的缺点。这是:

public class CollegeStudent {

    String firstName;
    String lastName;
    GregorianCalendar enrollmentDate;
    GregorianCalendar graduationDate;
    
    // Constructor requiring first name,last name,and enrollment date
    public CollegeStudent(String first,String last,int enrollmentYear,int enrollmentMonth,int enrollmentDay) {
        firstName = first;
        lastName = last;
        ZonedDateTime enrollmentZdt
                = LocalDate.of(enrollmentYear,enrollmentMonth,enrollmentDay)
                        .atStartOfDay(ZoneId.systemDefault());
        enrollmentDate = GregorianCalendar.from(enrollmentZdt);
        
        // Add 4 years to enrollmentZdt,then convert so it can be assigned to graduationDate
        ZonedDateTime graduationZdt = enrollmentZdt.plusYears(4);
        graduationDate = GregorianCalendar.from(graduationZdt);
    }
    
    // Getters and setters …
}

尝试一下:

    CollegeStudent student = new CollegeStudent("Wes","Hampton",2021,1,16);
    System.out.println("Enrolled:      " + student.getEnrollmentDate().toZonedDateTime());
    System.out.println("Will graduate: " + student.getGraduationDate().toZonedDateTime());

在我的时区输出:

Enrolled:      2021-01-16T00:00+01:00[Europe/Copenhagen]
Will graduate: 2025-01-16T00:00+01:00[Europe/Copenhagen]

链接

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。