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

时间:2009-02-04 18:26:41

标签: c# java static

我正在阅读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#中,最后,这个也很重要,这个线程安全吗?

9 个答案:

答案 0 :(得分:13)

Java中的

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

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

简短的Java回顾:

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

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

答案 1 :(得分:3)

我认为如果您将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#中,您可以使用替代工件来创建相同的耦合。

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

public class Outer 
{

...
void SomeMethod() {
    Inner             workerBee=new Inner(this);
    }
...

    class Inner
    private Outer outer;
    {
    Inner(Outer out) {
        outer=out;
        }
    }
}

因此,C#只是明确了Java的含义,包括显式需要引用来访问外部类的成员。

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

答案 8 :(得分:0)

假设您的类具有与构建器成员对应的公共可设置属性,则不需要在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};

    }
}

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