在java中扩展不可实例化类

在java中扩展不可实例化类,java,Java,我阅读了Joshua Bloch的《有效Java》,并从应用程序中删除了“常量接口反模式”。诀窍是使用构造函数为私有的不可实例化的util类,并将所有常量定义为“publicstaticfinal” 我必须扩展这个常量util类。我只能在将构造函数更改为protected时执行此操作 有人能提出更好的办法吗 public class Constants { private Constants () {} // Prevent instantiation public static

我阅读了Joshua Bloch的《有效Java》,并从应用程序中删除了“常量接口反模式”。诀窍是使用构造函数为私有的不可实例化的util类,并将所有常量定义为“publicstaticfinal”

我必须扩展这个常量util类。我只能在将构造函数更改为protected时执行此操作

有人能提出更好的办法吗

public class Constants {
    private Constants () {} // Prevent instantiation
    public static final String MyString = "MyString";
}

public class MyConstants extends Constants {
    private MyConstants () {} // Compiler error : Implicit super constructor Constants() is not visible.
    public static final String MySecondString = "MySecondString";
}

我认为将构造函数更改为protected没有任何错误


我也不认为使用接口保存常量有什么问题。

使用
protected
关键字有问题吗?对我来说,这似乎是一个务实的解决方案


我必须说(另外)使用接口来保存常量并没有特别的问题。使用
静态导入
使它们在客户端类中可用。不过,我不主张实现它。

通常不应该扩展这些常量类。你能给我们提供一个更具体的例子来说明你在做什么吗

通常,当常数相关时,您希望将它们分组在一起,例如,特定功能组件的数学常数或配置参数名称


如果这些常量真的是相关的,那么您是否可以将它们添加到原始类中?或者,是否有任何理由不能为常数创建一个单独的类?

< p>如果类在同一个包中,并且希望禁止非包类继承,请考虑使用默认访问:

public class Constants {
    Constants () {} // Prevent instantiation
    public static final String MyString = "MyString";
}

我通常会这样做:

public abstract class Constants {
    // ...constants...
    public Constants () {
        throw new UnsupportedOperationException();  // prevent instantiation
    }
}
通过这种方式,可以扩展该类以创建派生的实用程序类,但任何(误导的)实例化该类的尝试都将失败。我希望java.util.Collections是这样定义的,这样就不必为其他实用程序方法定义Collections2(或类似的)

顺便说一句,给定一个抽象类,“protected”和“public”实际上对构造函数意味着相同的含义。仅仅保护构造函数实际上没有任何好处,因为尽管有“保护”,任何人仍然可以轻松创建类的实例:


我使用约书亚·布洛赫推荐的方法

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public static class Math {

        private Math() {
            throw new AssertionError();
        }

        public static final int COUNT = 12;
    }

    public static class Strings {

        private Strings() {
            throw new AssertionError();
        }

        public static final String LOREM = "Lorem";
    }

}
常量
类和嵌套类

  • 无法扩展
  • 无法实例化

如果我需要按类型对常量进行分组,我只会使用嵌套类。请记住,每个嵌套类都必须抛出一个
AssertionError

为什么必须扩展包含常量的类?“当一个类实现一个接口时,它就成为该类公共API的一部分。实现细节不应该泄露到公共API中。”。有关更多详细信息,请参见有效Java第17项:)我可以理解这种情绪,但我相信很多人都在绞尽脑汁,试图为可能存在冲突的需求找到最好的折衷方案,而其他人则继续努力完成任务。Java语言文化已经成功地陷入了一个由模式、约定和限制组成的混乱网络中,我不确定最终是否有助于提高生产率。但这当然只是我个人的观点,我认为争议较少的是,诸如来自有效Java的“规则”与公共使用库和工具包的相关性要比单一使用的内部项目的相关性大得多。对于Sun、Apache和其他高度可见的项目来说,提高标准是非常重要的。我的观点是,不同的环境可能需要放松一点。我的回答肯定没有多大作用,我会删除它,但Pascal的评论是有用的和相关的,所以我将把它留给未来读者可能的启迪。关于有效的Java和公共使用库的公平点。不过,您的意思是,实现一个接口只是为了更容易地引用其中定义的常量也可以吗?(或者正如Brian Agnew在回答中所说的?)“为了避免这种情况,人们有时会将静态成员放入接口并从该接口继承。这是一个坏主意。事实上,这是一个坏主意,以至于有了一个名称:常量接口反模式(参见有效的Java项目17)。问题是,一个类对另一个类的静态成员的使用只是一个实现细节。当一个类实现一个接口时,它将成为该类的公共API的一部分。实现细节不应泄漏到公共API中。“@Brian你无法阻止它,这就是问题所在。你不能因为某人没有正确使用你的API而责怪他(API有问题,不是API的用户)。我没有意识到我在责怪任何人,我confess@Brian是的,如果你不实施它,那没关系。但是有人会的,这就是问题所在(如果可能的话,它会发生)。这就是为什么我认为API不应该给出这种可能性,而应该避免使用常量接口。我也同意Enum。@Carl我的经验是,公司项目/应用程序中也会出现“有人会”的情况,尤其是大型项目和分布式团队中,开发人员的技能参差不齐(我从未见过我会想到的事情)。所以,不,我不会让门打开,如果我能关上它。但你当然有权不同意,没错。我甚至认为我们不需要扩展常量类。代码是遗留的,我会修复它。非常感谢。使用枚举可以消除代码中的许多噪音。
public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public static class Math {

        private Math() {
            throw new AssertionError();
        }

        public static final int COUNT = 12;
    }

    public static class Strings {

        private Strings() {
            throw new AssertionError();
        }

        public static final String LOREM = "Lorem";
    }

}