Java的静态概念与C#的不同之处是什么?

我正在阅读Josh Bloch的书“ Effective Java” ,他建议在构建具有大量成员的对象时使用构建器设计模式。 从我所看到的不是香草设计模式,而是看起来像他的变化。 我更喜欢它的外观,并试图在我正在编写的C#Web应用程序中使用它。 这是用Java编写的代码并且工作得很好

public class Property { private String title; private String area; private int sleeps = 0; public static void main(String[] args) { Property newProperty = new Property.Builder("Test Property").Area("Test Area").Sleeps(7).build(); } private Property(Builder builder) { this.title = builder.title; this.area = builder.area; this.sleeps =builder.sleeps; } public static class Builder{ private String title; private String area; private int sleeps = 0; public Builder (String title){ this.title = title; } public Builder Area(String area){ this.area = area; return this; } public Builder Sleeps(int sleeps){ this.sleeps = sleeps; return this; } public Property build() { return new Property(this); } } } 

当我把它放入我认为是C#的等价物时

  public class Property { private String title; private String area; private Property(Builder Builder) { title = Builder.title; area = Builder.area; } public static class Builder { // Required parameters private String title; private String area; // Optional parameters private int sleeps = 0; public Builder(String val) { this.title = val; } public Builder Area(String val) { this.area = val; return this; } public Builder Sleeps(int val) { this.sleeps = val; return this; } public Property build() { return new Property(this); } } } 

然后我得到编译器警告。 他们中的大多数“无法在静态类中声明实例成员”。

所以我的问题首先是我错过了什么? 如果我错过了某些东西,我可以按照Josh Bloch推荐的方式进行,但是在C#中,最后,这一点也很重要,这是否是线程安全的?

如果您将Builder创建为顶级类(因为它与Java中的完全相同),我认为您可以实现几乎相同的效果,并创建一个工厂方法来接收构建器以保持构造函数私有(这反过来会让你根据需要返回子类实例)。

关键是让构建器执行创建对象所需的步骤。

所以(不太了解C#你可以试试这样的东西)

 // My naive C# attempt:P public class Property { public static void main( String []args ) { Property p = Property.buildFrom( new Builder("title").Area("area").Etc() ) } public static Property buildFrom( Builder builder ) { return new Propert( builder ); } private Property ( Builder builder ) { this.area = builder.area; this.title = builder.title; // etc. } } public class Builder { public Builder ( String t ) { this.title = t; } public Builder Area( String area ) { this.area = area; return this; } // etc. } 

将Builder作为静态内部属性类的重点是在两者之间创建一个高耦合(就好像它们在哪里一样)。 这就是为什么Builder中的构建方法调用私有“Property”构造函数的原因。

可能在C#中,您可以使用备用工件来创建相同的耦合。

Java中的public static class意味着您定义了一个静态嵌套类。 这意味着它在逻辑上包含在另一个类中,但它的实例可以存在而不需要引用它的外部类。 非静态嵌套类称为“内部类”,它的实例只能存在于外部类的实例中。

在C#中, static class是无法实例化的类,因此不能包含任何非静态成员。 在Java中没有与此构造等效的直接语言级别,但您可以通过仅提供私有构造函数来轻松地防止Java类的实例化。

简短的Java回顾:

  • 在另一个类中定义的所有类都是“嵌套类”
  • 嵌套非static的类称为内部类
  • 内部类的实例只能与外部类的实例相关
  • static嵌套类没有单独的名称
  • static嵌套类在很大程度上独立于其外部类(某些特权访问除外)。

如果一些C#guru告诉我们如何在C#/ .NET中处理内部/嵌套类,我会很高兴。

saua有正确的答案,但我想特别清楚你的例子:

在C#版本中,您应该从内部类中删除static关键字。 它与Java版本的含义不同,实际上它在Java版本中的作用是C#中内部类的正常行为。

在Java中,嵌套类默认与其包含类的特定实例相关联。 嵌套类的实例可以访问包含实例的变量和方法。 如果嵌套类具有“static”关键字,则它不与外部类的实例关联。 从这个意义上说,Bloch在Builder类中使用“static”关键字。

“静态”意味着在C#中应用于嵌套类时会有所不同。 我不知道你在C#中使用什么关键字,或者即使它是必要的。 您是否尝试将静态关键字从类定义中删除?

在Java类定义中使用“static”在Effective Java的第18项中讨论。

我不确定Java在静态类声明中做了什么,但在C#中,静态类只有类级别的成员,并且根据定义,不能实现到实例中。 这就像Class和Module之间的旧VB差异。

我不知道为什么C#会抱怨,但我可以说代码是线程安全的。 如果您同时创建两个或多个Property实例,每个实例都在自己的线程中,则不会遇到任何问题。

我将尝试删除static关键字。 正如其他人已经建议的那样,我的另一个想法是将构建器类创建为顶级类。

要回答有关如何在C#中获取Java内部类行为的几条评论,似乎需要在内部类的构造函数中传递对封闭类的引用(从快速的Google – C#可能已添加了该function) 。

 public class Outer { ... void SomeMethod() { Inner workerBee=new Inner(this); } ... class Inner private Outer outer; { Inner(Outer out) { outer=out; } } } 

所以C#只是明确地暗示了Java的作用,包括显式需要引用来访问外部类的成员。

就个人而言,我从来没有喜欢Java外部类成员的隐式访问,因为它似乎太容易绊倒并意外地破坏封装 – 我几乎总是将我的内部类创建为静态并将它们传递给外部类。

假设您的类具有与构建器成员对应的公共可设置属性,则不需要在C#中使用Bloch的构建器模式。 您可以使用对象初始化器

 public class Property { public String Title {get; set}; public String Area {get; set}; public int Sleeps {get; set}; public static void main(String[] args) { Property newProperty = new Property {Title="Test Property", Area="Test Area", Sleeps=7}; } } 

如果您需要更多封装,这将无法实现。