jjzjj

Java 在构造函数中设置私有(private)字段

coder 2024-03-17 原文

常见的设计实践是将实例变量设为私有(private),并使用公共(public) getter 和 setter 来访问它们。但我多次在 Internet 上看到代码示例,其中的构造函数直接将值分配给私有(private)实例变量,而不是使用构造函数内部的 setter。我错过了什么吗?

public class Person{
    private String name;

    public Person(String name){
        //is this right, seems like the whole encapsulation purpose is defeated
        this.name = name;

        //shouldn't this be used
        setName(name);
    }

    public String getName(){
        return this.name;
    }

    public void setName(String name){
        this.name = name;
    }
}

最佳答案

你没有遗漏任何东西。你做什么完全取决于你的情况。但是,考虑一下:

在 setter 中进行参数验证是很常见的。例如,假设我有一个类,其字段可以包含 0 到 10 的值(“抛出”对于下面的异常类型是不必要的,但为了清楚起见,我将其包括在内):

public class Example {
    private int value; 
    public Example () {
    }
    public final int getValue () {
        return value;
    } 
    public final void setValue (int value) throws IllegalArgumentException { 
        if (value < 0 || value > 10)
            throw new IllegalArgumentException("Value is out of range.");
    }
}

在这里,setValue() 验证“值”以确保它遵守规则。我们有一个不变量,声明“不存在具有超出范围值的示例”。现在假设我们想要创建一个带有值的构造函数。你可以这样做:

public class Example {
    ...
    public Example (int value) {
        this.value = value;
    }
    ...
}

如您所见,有一个问题。语句 new Example(11) 会成功,现在存在一个违反我们规则的 Example。但是,如果我们在构造函数中使用setter,我们也可以方便地将所有参数验证添加到构造函数中:

public class Example {
    ...
    public Example (int value) throws IllegalArgumentException {
        setValue(value); // throws if out of range
    }
    ...
}

所以这样做有很多好处。

现在,仍然存在您可能希望直接赋值的情况。其一,也许你没有可用的 setter(尽管我认为创建私有(private)或包私有(private) setter 仍然是可取的,出于上述原因,必要时用于反射/bean 支持,以及为了在更复杂的代码中简化验证).

另一个原因可能是你有一个构造函数,它以某种方式提前知道将分配有效值,因此不需要验证并且可以直接分配变量。不过,这通常不是跳过使用 setter 的令人信服的理由。

但是,总而言之,尽可能在任何地方使用 setter 通常是个好主意,这通常会导致代码更清晰、更清晰,随着复杂性的增加更易于维护。

你看到的大多数直接设置变量的例子只是人们“懒惰”——如果情况允许,这是完全可以接受的(也许你正在编写一个快速测试程序或应用程序,不想实现例如,一群二传手)。只要您牢记大局并且只在适当的时候“偷懒”,这就没有错。

我想根据此处的其他一些答案添加一些内容:如果您覆盖子类中的 setter ,并且您设置的数据破坏了基类假定的不变量,那么应该制作相关的 setter final 或基类不应该做出这些假设。 如果重写 setter 破坏了基类不变量,那么手头就有一个更大的问题。

您会注意到上面示例中的 getter/setter 是最终的。这是因为我们的规则是“任何 Example 必须有一个从 0 到 10 的值”。因此,该规则扩展到子类。如果我们没有该规则并且如果 Example 可以取任何值,那么我们就不需要最终 setter 并且可以允许子类覆盖。

希望对您有所帮助。

关于Java 在构造函数中设置私有(private)字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18034360/

有关Java 在构造函数中设置私有(private)字段的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  5. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  6. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  7. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  8. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  9. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  10. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

随机推荐