Java 静态常量是否违反“封装”?

Java 静态常量是否违反“封装”?,java,encapsulation,Java,Encapsulation,好的,我正在使用这本书:核心Java卷I-Fundamentals 它对封装的定义如下: 封装有时被称为信息隐藏是一个关键概念 在处理对象时。从形式上讲,封装就是简单的组合 一个包中的数据和行为,并隐藏实现细节 来自对象的用户 通过在SO中搜索,我知道封装和信息隐藏是两个独立的概念,但同时使用。但是,为了这个问题,让我们坚持书中的定义,即封装==实现隐藏,因为这个问题使用了书中的示例 public class Math { . . . public static final double P

好的,我正在使用这本书:核心Java卷I-Fundamentals

它对封装的定义如下:

封装有时被称为信息隐藏是一个关键概念 在处理对象时。从形式上讲,封装就是简单的组合 一个包中的数据和行为,并隐藏实现细节 来自对象的用户

通过在SO中搜索,我知道封装和信息隐藏是两个独立的概念,但同时使用。但是,为了这个问题,让我们坚持书中的定义,即封装==实现隐藏,因为这个问题使用了书中的示例

public class Math
{
 . . .
 public static final double PI = 3.14159265358979323846;
 . . .
}
书中说这并没有破坏封装,因为它是一个常量。但是上面的代码并没有破坏书中定义的封装隐藏部分的实现,因为PI不仅对类可见,而且对程序的其余部分可见

我的问题实际上是一个可能的复制品:虽然用C++加标签,但是答案是它确实违反了与书矛盾的封装,这没什么。我理解我的问题是否因为可能的重复而结束

编辑:我将发布另一个示例代码,因为一条注释提到PI不被视为实现细节

public class System
{
 . . .
 public static final PrintStream out = . . .;
 . . .
}

我认为静态不属于OOP原则。所以它既不违反也不遵守。

我认为静态不属于OOP原则。因此,它既不违反也不遵守。

静态文字不是任何对象的一部分,它们只是分配给全局变量的数据。 因此,这不是违反封装本身,而是完全缺乏面向对象性。 OOP的方法是根本不使用全局常量,而是定义一个解决问题的对象

界面图{ 双周长; } 类圆实现图{ 私人最终双半径; @凌驾 公共双周界{ 返回此值。半径*2*float 3.1416926; } } 以下是关于该主题的更多讨论:
静态文字不是任何对象的一部分,它们只是分配给全局变量的数据。 因此,这不是违反封装本身,而是完全缺乏面向对象性。 OOP的方法是根本不使用全局常量,而是定义一个解决问题的对象

界面图{ 双周长; } 类圆实现图{ 私人最终双半径; @凌驾 公共双周界{ 返回此值。半径*2*float 3.1416926; } } 以下是关于该主题的更多讨论:
好问题。我不认为您提供的示例破坏了封装,至少不是严格意义上的

您给出的第一个示例是常量PI,第二个示例提供对系统中out常量的访问;大概是为了使用一些代码,比如System.out.PrintlHelloWorld!;。正如其他人已经提到的,PI实际上只是一个常量,常量的用户无法修改或影响该值。PI的用户仍然需要在代码中引用构成API的常量。如果PI不太可能被修改,但谁知道用户会不会受到这种变化的影响,因为他们无论如何都需要重新编译代码

考虑封装的一个有用方法是考虑违反封装需要什么。《有效Java第三版》在第16项中对此进行了很好的描述,这表明如果没有适当的封装,就无法在不更改API的情况下更改表示,就无法强制执行不变量,并且在访问字段时也无法采取辅助措施

有效Java第16项中的以下类别也明显违反了上述规定:

class Point {
  public double x;
  public double y;
}
所有字段都是公共字段,此API的用户将被迫直接使用这些字段。如果后来作者决定在可以访问或修改x或y之前添加一些验证检查,那么在不破坏现有客户机的情况下就不可能这样做。API必须进行重大修改,可能会破坏下游用户的行为

现在让我们看一下您提供的第二个示例:

public class System
{
 . . .
 public static final PrintStream out = . . .;
 . . .
}
这似乎与上面的PI示例非常相似,但有一个关键区别:所讨论的字段是PrintStream。虽然out字段本身是这个API的一个明显的部分,现在可能很难更改,因为它的公开客户端将要使用和依赖它,但PrintStream类型是一个类,它实际上是一个有趣的类:用户将引用该类上的方法。在这里,我们拥有PrintStream API中的关键功能,它可以随着时间的推移而不断发展,而不会中断使用。将来也有可能将out常量更改为out以引用不同的PrintStream子类,API的用户应该不会受到影响

希望有帮助。

好问题。我 不要认为您提供的示例破坏了封装,至少不是严格意义上的

您给出的第一个示例是常量PI,第二个示例提供对系统中out常量的访问;大概是为了使用一些代码,比如System.out.PrintlHelloWorld!;。正如其他人已经提到的,PI实际上只是一个常量,常量的用户无法修改或影响该值。PI的用户仍然需要在代码中引用构成API的常量。如果PI不太可能被修改,但谁知道用户会不会受到这种变化的影响,因为他们无论如何都需要重新编译代码

考虑封装的一个有用方法是考虑违反封装需要什么。《有效Java第三版》在第16项中对此进行了很好的描述,这表明如果没有适当的封装,就无法在不更改API的情况下更改表示,就无法强制执行不变量,并且在访问字段时也无法采取辅助措施

有效Java第16项中的以下类别也明显违反了上述规定:

class Point {
  public double x;
  public double y;
}
所有字段都是公共字段,此API的用户将被迫直接使用这些字段。如果后来作者决定在可以访问或修改x或y之前添加一些验证检查,那么在不破坏现有客户机的情况下就不可能这样做。API必须进行重大修改,可能会破坏下游用户的行为

现在让我们看一下您提供的第二个示例:

public class System
{
 . . .
 public static final PrintStream out = . . .;
 . . .
}
这似乎与上面的PI示例非常相似,但有一个关键区别:所讨论的字段是PrintStream。虽然out字段本身是这个API的一个明显的部分,现在可能很难更改,因为它的公开客户端将要使用和依赖它,但PrintStream类型是一个类,它实际上是一个有趣的类:用户将引用该类上的方法。在这里,我们拥有PrintStream API中的关键功能,它可以随着时间的推移而不断发展,而不会中断使用。将来也有可能将out常量更改为out以引用不同的PrintStream子类,API的用户应该不会受到影响



希望有帮助。

Pi是一个常数。没有可隐藏的实现。实现不只是信息吗?那么信息PI不是不再隐藏了吗?在第二种情况下:是的,它违反了封装,你通常应该避免使用常量,除了那些根据定义是常量的东西。@Taschi那么破坏封装是可以接受的吗?这本书说它很好,因为它的价值无法改变。但是封装不是我们在OOPim中必须遵守的一些原则吗?一个新手,我可能错了吗?@Taschi抱歉,我意识到我现在问的是一个完全不同的问题。我将做一个单独的postPi,它是一个常数。没有可隐藏的实现。实现不只是信息吗?那么信息PI不是不再隐藏了吗?在第二种情况下:是的,它违反了封装,你通常应该避免使用常量,除了那些根据定义是常量的东西。@Taschi那么破坏封装是可以接受的吗?这本书说它很好,因为它的价值无法改变。但是封装不是我们在OOPim中必须遵守的一些原则吗?一个新手,我可能错了吗?@Taschi抱歉,我意识到我现在问的是一个完全不同的问题。我将做一个单独的PASWELL,Java不允许您在类之外拥有常量,但是可以用至少允许OO的其他语言(比如C++、perl、python)来拥有它们。但是,java不允许您在类之外拥有常量,但是可以用至少允许OO的其他语言(如C++、Perl)来使用java。很抱歉,后面的回答是,客户端是什么意思,它们只是与类交互的东西吗?另外,你能不能帮我把这段话哑下来:你不能在不更改API的情况下更改表示,你不能强制执行不变量,当访问一个字段时,你不能执行辅助操作。我很难理解这一点,但我可以说,您的答案的主要本质是,只要在类中更改数据/数据本身的设计时,与您的类交互的客户端不会受到不利影响,我们就不会破坏封装,至少不会严格地破坏封装。但严格地说,我们正在打破第二次会议的封装example@HelloWorld我想说你说得对。让我澄清一下,这也将回答你关于重新整理引用文本的第一个问题。首先,客户机是指通过调用/使用公开的API来使用代码的任何代码。换言之:如果您设计类的方式使数据的内部表示和数据的使用能够以一种不会产生负面影响的方式进行更改
影响代码的当前和未来用户,那么就实现了封装。如果您需要更多的澄清,请告诉我。@HelloWorld我也不会太担心严格遵守定义的内容。API设计是一门艺术,我更愿意关注的是如何以一种易于他人使用且易于自己更改的方式设计代码,而不会对其他用户产生负面影响。有时,正确的设计实际上是使用像我上面展示的Point类这样的类,只要用户无法访问它,可能是在包专用类中。很抱歉,稍后的回答是,客户端是什么意思,它们只是与您的类交互的东西吗?另外,你能不能帮我把这段话哑下来:你不能在不更改API的情况下更改表示,你不能强制执行不变量,当访问一个字段时,你不能执行辅助操作。我很难理解这一点,但我可以说,您的答案的主要本质是,只要在类中更改数据/数据本身的设计时,与您的类交互的客户端不会受到不利影响,我们就不会破坏封装,至少不会严格地破坏封装。但严格地说,我们正在打破第二次会议的封装example@HelloWorld我想说你说得对。让我澄清一下,这也将回答你关于重新整理引用文本的第一个问题。首先,客户机是指通过调用/使用公开的API来使用代码的任何代码。换言之:如果您设计类的方式使对数据的内部表示和数据的使用的更改不会对代码的当前和未来用户产生负面影响,那么您就实现了封装。如果您需要更多的澄清,请告诉我。@HelloWorld我也不会太担心严格遵守定义的内容。API设计是一门艺术,我更愿意关注的是如何以一种易于他人使用且易于自己更改的方式设计代码,而不会对其他用户产生负面影响。有时,正确的设计实际上是使用像我上面展示的Point类这样的类,只要用户可能在包专用类中无法访问它。