【问题标题】:Immutable Class [duplicate]不可变类 [重复]
【发布时间】:2013-09-21 11:17:14
【问题描述】:

我知道如何创建 immutable class 。我创建了以下 .

public class Employee {

    private final int id;
    private final String name;
    private final int salary;

    public Employee(int id, String name, int salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }
}

很少有文章还建议,你将你的类声明为final,甚至Effective JAVA书说“将你的方法标记为final,这样它们就不会被覆盖” 。但我不明白为什么我需要在类或setter 方法上使用final,当字段被声明为privatefinal 时?

或者文章和 EFFECTIVE JAVA 建议另一种方法!!!

【问题讨论】:

    标签: java string immutability


    【解决方案1】:

    正如其他人解释的那样,它是为了防止子类改变父类的行为。引用 Effectice Java

    确保类不能被扩展。这样可以防止粗心或 恶意子类损害 通过表现得好像对象的状态发生了变化来分类。预防 子类化通常是通过将类设为 final 来完成的,但是 我们稍后会讨论另一种选择。

    这是一个例子:

    public class Manager extends Employee {
    
        public Manager(int id, String name, int salary) {
            super(id, name, salary);
        }
    
        @Override
        public String getName() {
            return "doppelganger";
        }
    
        public static void main(String[] args) {
            Employee e = new Manager(0, "Eric", 100); //e should be immutable right!
            System.out.println(e.getName()); // prints "doppelganger", I thought employee was immuatble!?
        }
    }
    

    【讨论】:

      【解决方案2】:

      创建类immutable 和声明类为final 具有不同的含义。如果您创建类final,则意味着您不能覆盖您的方法中的任何功能(方法),这与immutablity 不同。 即使您将field 设置为最终结果,我仍然可以extend 您的class,并覆盖其他方法,例如在您的方法getName 您返回employee name,我可以覆盖该方法并且我可以使method 返回employee name + employee id

      看一个例子:

      public class SubEmployee extends Employee{
      
       public String getName(){
           return "Darth Vader";
      
          }
      }
      

      来自 Java 文档Strategy for Defining Immutable Objects

         Don't allow subclasses to override methods. The simplest way to do 
      this is to declare the class as final. A more sophisticated approach is to make the
      constructor private and construct instances in factory methods.
      

      【讨论】:

        【解决方案3】:

        如果您不将 Employee 类设为 final 或将其上的所有方法设为 final,我可以编写一个可变的 MyEmployee 类。然后我可以将它传递给任何采用 Employee 的方法。如果您的代码依赖于 Employee 是不可变的这一事实,那么当 ID 更改时会非常惊讶,因为它是 MyEmployee,而不仅仅是 Employee。

        public class MyEmployee extends Employee {
        
            private final int id;
        
            public MyEmployee(int id, String name, int salary) {
                super(id, name, salary);
                this.id = id;
            }
        
            public int getId() {
                return this.id;
            }
        
            public void setId(final int id) {
                this.id = id;
            }
        

        【讨论】:

          【解决方案4】:

          首先您需要了解最终访问和私有访问之间的区别。当您将方法声明为 Private 时,这并不意味着您不能覆盖它。类上的 final 关键字使类不可访问,而方法上的方法使非重写和变量上的常量作为常量。最好在 setter 上使用 Final 关键字,以避免其他任何使用它的类的无意更改。

          【讨论】:

          • 你能给出一个可以覆盖私有方法的示例代码吗?私人成员不是继承的,我认为不可能覆盖。请分享示例代码。
          • 不幸的是,声明为 final 的类有时更难以进行单元测试。并非所有的单元测试框架都可以有效地模拟最终类,并且覆盖测试错误的方法也几乎是不可能的。 final 在未经 junit 测试的旧代码中尤其令人讨厌...
          猜你喜欢
          • 1970-01-01
          • 2013-02-11
          • 2015-09-05
          • 2012-01-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多