【问题标题】:When is it appropriate to assign values to an instance variable in Java?什么时候适合在 Java 中为实例变量赋值?
【发布时间】:2020-04-12 06:40:56
【问题描述】:

这是一个关于最佳实践的问题。在采用面向对象的方法时,我想出了三种不同的方法来做同样的事情。在我未经训练的眼中,它们似乎都没有“错误”,但我知道每种语言和风格都有其最佳实践,我想知道这三种方式中的任何一种是否违反了一些我尚未学习的“最佳实践”。

方式一:(先声明,然后在构造函数中赋值)

public class CCipher {

    private String alphabet;
    private String shiftedAlphabet;
    private int mainKey;

    public CCipher(int key){

        mainKey = key;
        alphabet = "abcdefghijklmnopqrstuvwxyz";
        shiftedAlphabet = alphabet.substring(mainKey) 
                        + alphabet.substring(0, mainKey);
    }

方式2:(同时声明和赋值)

public class CCipher {

    private String alphabet = "abcdefghijklmnopqrstuvwxyz";
    private String shiftedAlphabet;
    private int mainKey;

    public CCipher(int key){

        mainKey = key;
        shiftedAlphabet = alphabet.substring(mainKey) 
                        + alphabet.substring(0, mainKey);
    }

方式3:(有些东西在非get/set方法中初始化)

public class CCipher {

    private String alphabet;
    private String shiftedAlphabet;
    private int mainKey;

    public CCipher(int key){

        mainKey = key;
        alphabet = "abcdefghijklmnopqrstuvwxyz";

    }

    public String encrypt(String input){
        shiftedAlphabet = alphabet.substring(mainKey) 
                        + alphabet.substring(0, mainKey);
        // ... code to encrypt input ...
    }

    public String decrypt(String input){
        shiftedAlphabet = alphabet.substring(26 - mainKey) 
                + alphabet.substring(0, 26 - mainKey);
        // ... code to decrypt input
    }
}

就我个人而言,对于这个特定的家庭作业,我真的最喜欢第三种方式,因为它符合我要解决的问题的逻辑。但是错了,好吧错了……

【问题讨论】:

  • 当CCipher 对象初始化时,您的第三个方法将shiftedAlphabet 保留为null;这可能最终会给使用它的人带来问题,并期望该值不是null。其他两个主要是个人喜好。
  • 对于第三种方式,shiftedAlphabet 只在分配给它的方法内部使用,因此不需要它是一个字段;最好将其设为局部变量。
  • 为什么不将alphabet = "abcdefghijklmnopqrstuvwxyz"; 声明为private static final String?以后有可能改吗?
  • 你需要一个 mainKey 字段吗?除了在构造函数中,它似乎没有在任何地方使用。
  • 嗨@NickAth,我怀疑它以后会改变,除非我自发地学习俄语。我还没有了解“final”,尽管我的 IDE 一直在催我使用它。

标签: java oop instance-variables


【解决方案1】:

第二个版本似乎还可以。但是常量确实是静态的最终字符串。

public class CCipher {

    private static final String ALPHABET = "abcdefghijklmnopqrstuvwxyz";
    private final String shiftedAlphabet;
    private final int mainKey;

    public CCipher(int key) {
        mainKey = key;
        shiftedAlphabet = ALPHABET.substring(mainKey) 
                        + ALPHABET.substring(0, mainKey);
    }

Christopher Schneider 指出,在加密和解密中使用了不同的移位字母。作为现实中的 CCipher 对象,可能会加密或解密,使其成为局部变量。

需要两个不同的非最终延迟初始化字段,这很麻烦。

public class CCipher {

    private static final String ALPHABET = "abcdefghijklmnopqrstuvwxyz";
    //private final String shiftedEncryptAlphabet;
    //private final String shiftedDecryptAlphabet;
    private final int mainKey;

    public CCipher(int key) {
        mainKey = key;
        shiftedAlphabet = ALPHABET.substring(mainKey) 
                        + ALPHABET.substring(0, mainKey);
    }

    public String encrypt(String input){
        String shiftedAlphabet = alphabet.substring(mainKey) 
                    + alphabet.substring(0, mainKey);
        // ... code to encrypt input ...
    }

    public String decrypt(String input){
        String shiftedAlphabet = alphabet.substring(26 - mainKey) 
            + alphabet.substring(0, 26 - mainKey);
        // ... code to decrypt input
    }

【讨论】:

  • 正是我要说的。如果属性没有改变,标记它们final并在构造函数中初始化。
  • @ChristopherSchneider 确实如此。即使在 3 中,mainKey 似乎也是固定的。因此准备常数,使一切都是最优的。
  • 我错过了这个,因为它是一个类属性而不是一个局部变量,但看起来shiftedAlphabet 是一个不断变化的变量。它可能应该是两个变量,例如shiftedAlphabetEncrypt 和 Decrypt
  • @ChristopherSchneider 我监督了这一点。那么局部变量可能是最好的,因为同一个实例不太可能同时进行加密和解密。
  • @JoopEggen 谢谢。我正在考虑使用您所有答案的组合。保留alphabet 并使其成为最终版本。摆脱 shiftAlphabet 变量并使其成为本地变量。让mainKey由构造函数填写...
【解决方案2】:

关于alphabet - 如果它永远不会改变,第二个 sn-p 可能最接近最佳实践,但它仍然不完全存在 - 它应该是 private static final "constant":

public class CCipher {   
    private static final String alphabet = "abcdefghijklmnopqrstuvwxyz";
    // ...
}

关于 shiftedAlphabet - 第三个 sn-p 肯定不太有利(尽管在技术上不是“错误”) - 在每次调用 encrypt 或 decrypt 时,您重新计算不受以下影响的 shiftedAlphabet input 以任何方式。这可能没有错,但很浪费(换句话说——作为一名老师,我肯定会为此扣分,即使代码确实有效)。

总结一下 - 第二个 sn-p 可能是三个中最好的,但我会将 alphabet 的修饰符修复为 private static final。

【讨论】:

  • 好吧,它不一定被“重新计算”,因为它从未在构造函数中被初始化或何时被声明。这就是我喜欢这种方式的原因,因为每次解密都需要移位字母,而加密需要完全不同的移位字母。也许解决方案(来自对问题的评论)只是让 shiftAlphabet 在使用它的方法中成为局部变量?
  • 我还没有了解“final”,尽管我的 IDE 一直在提醒我使用它并带有警告突出显示。我想推迟,但既然你提到它,我会跳过一点:)
  • @rocksNwaves 大多数读者,包括我在内,都忽略了这样一个事实,即您的第三个示例表明您实际上需要两种不同版本的移位字母表:一种用于解密,另一种用于加密。所以使用两个局部变量,或者使用两个(最终)字段。但不要使用单个字段并在每次调用其中一种方法时更改值。这使得代码不是线程安全的,而且非常混乱。
  • @JBNizet 这对我来说很有意义!这就是我现在要做的,谢谢!
猜你喜欢
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多