Java 当试图通过在已确定日期上添加4年来创建新日期时,两个日期都会更改(GregoriaCalendar)

Java 当试图通过在已确定日期上添加4年来创建新日期时,两个日期都会更改(GregoriaCalendar),java,gregorian-calendar,Java,Gregorian Calendar,完全公开,这是家庭作业,但只是作业的一小部分,我不明白为什么它不起作用。以下是作业文本: 创建一个大学生班。此类将包含数据字段 包含学生的名字、姓氏、注册日期和 计划毕业日期,使用GregorianCalendar类 日期为每个字段提供get()和set()方法。还提供 需要姓名和注册日期的构造函数, 并将毕业日期定在四年后 入学人数。将类另存为CollegeStudent.java 创建一个交互式应用程序,提示用户输入两个用户的数据 大学生物品。提示用户输入名字、姓氏、, 每个月的注册月、注册

完全公开,这是家庭作业,但只是作业的一小部分,我不明白为什么它不起作用。以下是作业文本:

创建一个大学生班。此类将包含数据字段 包含学生的名字、姓氏、注册日期和 计划毕业日期,使用GregorianCalendar类 日期为每个字段提供get()和set()方法。还提供 需要姓名和注册日期的构造函数, 并将毕业日期定在四年后 入学人数。将类另存为CollegeStudent.java

创建一个交互式应用程序,提示用户输入两个用户的数据 大学生物品。提示用户输入名字、姓氏、, 每个月的注册月、注册日和注册年 然后实例化对象。显示所有 值,包括预计毕业日期。拯救 应用程序名为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;
    }

}

My TestCollegeStudent.java同时显示注册日期和毕业日期,它们都显示用户输入的初始注册日期4年后的同一日期。如果我删除了在毕业日期上增加4年的行,它们都显示为初始注册日期。我觉得我遗漏了一些非常简单的语法问题,但我还没有弄清楚它是什么。

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


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

问题在于,当您执行
graduationDate=注册时,
graduationDate现在指向注册对象,您对其中任何一个对象所做的每一次更改都将反映在另一个对象上,因为它们是相同的对象


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

发生这种情况是因为构造函数中有以下赋值:

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
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
为了处理这种情况,
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: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
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
SimpleDataFormat
已经过时,并且容易出错。建议完全停止使用,并切换到

  • 无论出于何种原因,如果您必须坚持使用Java6或Java7,您可以使用哪个backport将大部分Java.time功能移植到Java6&7
  • 如果您正在为Android项目工作,并且您的Android API级别仍然不符合Java-8,请检查并确认

查看了解使用java.time API(现代日期时间API)的分步教程和示例。

之所以发生这种情况,是因为构造函数中有以下赋值:

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
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
为了处理这种情况,
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: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
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
SimpleDataFormat
已经过时,并且容易出错。建议完全停止使用,并切换到

  • 无论出于何种原因,如果您必须坚持使用Java6或Java7,您可以使用哪个backport将大部分Java.time功能移植到Java6&7
  • 如果您正在为Android项目工作,并且您的Android API级别仍然不符合Java-8,请检查并确认

查看了解使用java.time API(现代日期时间API)的分步教程和示例。

此线程中已经有一个很好的答案。我在补充我的贡献。问题的主要来源是这一行,其中GraducationDate指的是注册

graduationDate=入学

您也可以尝试以下方法:

//将GraducationDate设置为enrollmentDate,然后添加4年
毕业日期=新的GregorianCalendar();//新对象
graduationDate.setTime(enrollmentDate.getTime());//更新时间
毕业日期。添加(Gregoriacalendar.YEAR,4);//加年

t中已经有了一个很好的答案