如何在java中使用日期字段使类不可变?

时间:2015-08-06 04:37:54

标签: java immutability

我创建了一个带有日期字段的不可变类。如何确保即使是日期字段也是不可变的,因为即使您将日期字段设为最终,您仍然可以在以后为其分配不同的值?

8 个答案:

答案 0 :(得分:9)

getDate()方法中,返回new Date()个实例,而不是相同的实例。

public Date getDate() {
    // Not correct.
    return this.date; // This will make your class mutable.

    // Instead use, 
    return new Date(this.date.getTime()); // This will make sure your date field cannot be changed.
}

答案 1 :(得分:2)

这是具有不可变HAS-A日期对象的Bean(类)的示例。

 import java.util.Date;


public class MyBean {

    private Date date; // Immutable Date Step 1 Make Private

    public MyBean(Date date)
    {
         // Immutable Date Step 2 If Set through Constructor then get a specialised (sub class) Date.
        this.date= getImmutableDate(date);  // THIS METHOD RETURNS AN IMMUTABLE DATE
    }

    public MyBean(){} // Allow Default Constructor

    public Date getDate() {
        return date;
    }

     // Immutable Date Step 3- Allow setting of date only once!!
    public void setDate(Date date) {
        if(this.date==null)
        {
            this.date= getImmutableDate(date);  
        }
    }

    /* Override all Setter methods of Date class. So even if user gets reference of Date Object it is not the original date object
     * it would be a modified date object whose all setter methods do nothing*/
    private Date getImmutableDate(Date date)
    {
        /* This is an Anonymous Inner Class that extends java.util.Date class, it overrides all the setter methods
         * making the date object IMMUTABLE( i.e setXXX has no effect)
         * */
        date =new Date(date.getTime()){
            private static final long serialVersionUID = 1L;
            @Override
            public void setYear(int year) {}

            @Override
            public void setMonth(int month) {}

            @Override
            public void setDate(int date) {}                

            @Override
            public void setHours(int hours) {}

            @Override
            public void setMinutes(int minutes) {}

            @Override
            public void setSeconds(int seconds) {}



@Override
        public void setTime(long time) {}

    };
    return date;
}

}

答案 2 :(得分:1)

以下是immutable

Java类的简单示例
public final class Employee{  
    final String pancardNumber;  
    public Employee(String pancardNumber){  
        this.pancardNumber=pancardNumber;  
    }  
    public String getPancardNumber(){  
       return pancardNumber;  
    }
}

上面的类是不可变的,因为:

  1. 该类的实例变量是最终的,即我们无法更改 创建对象后的值。
  2. 该类是最终的,因此我们无法创建子类。
  3. 没有setter方法,即我们有 没有更改实例变量值的选项。
  4. 这些点使这个类成为不可变的。如果是Date属性,您可以使用构造函数为每个新对象设置日期并导入org.joda.time.DateTime类。这是一个比java.util.Date更好的版本,因为它是不可变的。使用java.util.Date会很危险,因为它是一个可变类,我们无法控制调用线程(可能会修改它)。这是一个例子。

    public final class Bill {
    
        private final int amount;
        private final DateTime dateTime;
    
        public Bill(int amount, DateTime dateTime) {
            this.amount = amount;
            this.dateTime = dateTime;
        }
        public int getAmount() {
            return amount;
        }
        public DateTime getDateTime() {
            return dateTime;
        }
    }  
    

答案 3 :(得分:0)

使用防御性复制。这意味着如果您必须将日期传递给其他类,例如通过方法参数或从方法返回,您应该复制。

制作日期副本很简单:

new Date(myDate.getting())

答案 4 :(得分:0)

识别可变实例变量(如date或hashmap)返回具有所有可变对象的复制内容的新对象。无需额外的努力就可以安全地返回不可变的变量。

见下面的例子:

import java.util.Date;

public final class ImmutableClass
{

    /**
    * Integer class is immutable as it does not provide any setter to change its content
    * */
    private final Integer immutableField1;
    /**
    * String class is immutable as it also does not provide setter to change its content
    * */
    private final String immutableField2;
    /**
    * Date class is mutable as it provide setters to change various date/time parts
    * */
    private final Date mutableField;

    //Default private constructor will ensure no unplanned construction of class
    private ImmutableClass(Integer fld1, String fld2, Date date)
    {
        this.immutableField1 = fld1;
        this.immutableField2 = fld2;
        this.mutableField = new Date(date.getTime());
    }

    //Factory method to store object creation logic in single place
    public static ImmutableClass createNewInstance(Integer fld1, String fld2, Date date)
    {
        return new ImmutableClass(fld1, fld2, date);
    }

    //Provide no setter methods

    /**
    * Integer class is immutable so we can return the instance variable as it is
    * */
    public Integer getImmutableField1() {
        return immutableField1;
    }

    /**
    * String class is also immutable so we can return the instance variable as it is
    * */
    public String getImmutableField2() {
        return immutableField2;
    }

    /**
    * Date class is mutable so we need a little care here.
    * We should not return the reference of original instance variable.
    * Instead a new Date object, with content copied to it, should be returned.
    * */
    public Date getMutableField() {
        return new Date(mutableField.getTime());
    }

    @Override
    public String toString() {
        return immutableField1 +" - "+ immutableField2 +" - "+ mutableField;
    }
}

了解更多详情: http://www.javainterviewpoint.com/make-class-immutable-java/

答案 5 :(得分:0)

java.time

其他答案在显示修复对象中的值的策略时是正确的。

我还建议你使用现代的 java.time 类而不是可怕的遗留类。代替Date,使用Instant。代替Calendar,使用ZonedDateTime

java.time 类被设计为不可变对象。 plus…minus…to…等方法with都会产生一个新鲜的物体,保留原始物体。这些类没有 setter 方法。

额外提示:在您自己的不可变类中,您可能会发现遵循 java.time 类建立的方法命名模式很有用。

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

使用符合JDBC driver或更高版本的JDBC 4.2,您可以直接与数据库交换 java.time 对象。不需要字符串也不需要java.sql。* classes。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 6 :(得分:0)

唯一的方法。 创建一个自定义的DateClass和Overrider set **方法,并且不为该方法提供任何功能。

答案 7 :(得分:0)

您可以克隆日期对象,使其不能被修改

public Date getDate (){
         return (Date) this.date.clone ();
}