为什么不能在Java中将类声明为静态类?


459

为什么不能在Java中将类声明为静态类?


72
反问:如果您声明一个顶级类为,您期望的效果是static什么?
约阿希姆·绍尔

3
不,您不能,除了静态内部类。但是,您想要实现什么?
manolowar 2010年

60
@Joachim Sauer:嗯,C#将static类解释为abstract final,即,它们不能被实例化并且不能被扩展。这意味着它们只能包含静态成员,这对于仅包含辅助方法的类很有用。
bcat

30
@bcat对于C#是正确的,但是Java类可以是抽象的或最终的,而不是两者都可以。为了防止实例化一个类,可以声明一个私有构造函数。
洛伦佐·波利多里

7
@JoachimSauer很简单,我很想强迫类中的所有成员都是静态的(甚至必须在每个方法或属性上声明)。
hmartinezd 2014年

Answers:


475

只有嵌套的类可以是静态的。这样,您可以使用嵌套类而无需外部类的实例。

class OuterClass{
    public static class StaticNestedClass{
    }

    public class InnerClass{
    }

    public InnerClass getAnInnerClass(){
        return new InnerClass();
    }

    //This method doesn't work
    public static InnerClass getAnInnerClassStatically(){
        return new InnerClass();
    }
}

class OtherClass{
    //Use of a static nested class:
    private OuterClass.StaticNestedClass staticNestedClass = new OuterClass.StaticNestedClass();

    //Doesn't work
    private OuterClass.InnerClass innerClass = new OuterClass.InnerClass();

    //Use of an inner class:
    private OuterClass outerclass= new OuterClass();
    private OuterClass.InnerClass innerClass2 = outerclass.getAnInnerClass();
    private OuterClass.InnerClass innerClass3 = outerclass.new InnerClass();
}

资料来源:

在同一主题上:


3
尽管第一个词不准确,但+1。如本教程所述,“非静态嵌套类称为内部类”。(JLS:“内部类是未显式或隐式声明为静态的嵌套类。”)
user85421,2010年

74
您当然是对的;但我看不出这如何回答问题
Joeri Hendrickx

2
@Carlos Heuberger,您是对的,我更新了帖子。@Joeri Hendrickx,问题是,“为什么不能将类声明为静态..?”,所以可以,并且[在这里阅读我的文章]。这是关于静态类的用法以及为什么它们必须是嵌套类的解释。
科林·赫伯特

1
这里给出的解决方案很好...但是我仍然想知道y ppl并没有在逻辑上解释说java中不可能有静态类。.一些OOPs概念解释会是正确的答案。我正在等待
Punith Raj

9
没错,但是当您开始问自己“静态类”是什么时,您正在考虑的问题通常会自行解决。在java中,静态元素意味着您可以在没有封闭类实例的情况下访问/调用它。如果将关键字应用于类本身,那可能意味着什么?你的意图是什么?您会期待什么?既然您已经知道了它的可能,那么我很确定它要么不是“很没有道理”,要么是“牵强附会”(这是有道理的,但最终这只是一个选择已完成)。
科林·赫伯特

39

默认情况下,顶级类是静态的。内部类默认情况下是非静态的。您可以通过将内部类显式标记为静态来更改它们的默认值。由于是顶级,所以顶级类不能具有非静态语义,因为没有父类可以引用。因此,无法更改顶级类的默认设置。


14
»顶级类默认情况下是静态的。«这是最佳答案。它们是静态的,因为您不需要任何实例来引用它们。可以从任何地方引用它们。它们在静态存储中(如C存储类中一样)。-正如其他人指出的那样(Iain Elder在对另一个答案的评论中),语言设计者本可以允许static顶级类上的关键字表示并强制其只能包含静态成员,而不能实例化;但是,这可能会使人感到困惑,static因为嵌套类的含义不同。
Lumi 2014年

35

所以,我来晚了,但是这是我的两分钱-从哲学上讲增加了科林·赫伯特的回答。

从高层次上讲,您的问题涉及对象和类型之间的差异。尽管有许多汽车(对象),但只有一种汽车类别(类型)。将某些事物声明为静态意味着您正在“类型”空间中进行操作。只有一个。顶级class关键字已经在“类型”空间中定义了一种类型。结果,“公共静态类汽车”是多余的。


1
是。换句话说,顶级类默认情况下是静态的,因此不需要关键字。
沃伦·露2014年

1
好吧,我还要补充沃伦·德(Warren Dew)所说的:“访问静态成员时,默认情况下,顶级类是静态的”。
德克斯特2014年

1
被低估的答案。一个新的关键字可以强制类中的每个方法都是静态的,并且构造函数private会很好。我不会将其命名为静态,因为这很令人困惑。
G_V 2014年

@G_V尽管Java可以创建这样的怪物,但是Java几乎淘汰了它使愚蠢的事情变得困难的方式。通常,静态是一个坏主意,静态类太可怕了(比单例本身更糟糕的是反模式)。许多人不理解这一点,因此给它一个关键字将是一个非常糟糕的主意。取而代之的是,我们使不好的事情变得困难,而就此解决。请注意,也没有“ Singleton”关键字。且没有Property关键字。这些都会导致错误的代码(尽管人们仍然使用Properties太多,以至于Java也可能会支持它们)
Bill K

29

具有私有构造函数的类是静态的。

像这样声明您的课程:

public class eOAuth {

    private eOAuth(){}

    public final static int    ECodeOauthInvalidGrant = 0x1;
    public final static int    ECodeOauthUnknown       = 0x10;
    public static GetSomeStuff(){}

}

您可以不经初始化就使用:

if (value == eOAuth.ECodeOauthInvalidGrant)
    eOAuth.GetSomeStuff();
...

3
它不是静态的,但包含静态属性。如果您编写public final int ECodeOauthUnknown = 0x10; 它不再是静态的。
user1883212 2013年

9
如果有人想知道这里发生了什么,则此匹配“静态类”的C#定义-msdn.microsoft.com/zh-cn/library/79b3xss3%28v=vs.90%29.aspx。给定Java对“静态类”的定义,所有非内部类都是静态的(请参见同级答案)。
Calum

1
除了@ user1883212是正确的之外,我什至会说这个答案使读者感到困惑,在这里私有构造函数在某种程度上很重要,而实际上一点也不重要。
tlwhitec

在.NET世界中,如果将一个类标记为抽象和最终标记(static class在C#中声明的效果),则编译器甚至不会允许代码声明该类型的变量,也不会将其用作泛型类型参数。类中仅缺少可访问的构造函数,否则可以实例化或继承该构造函数并不排除声明该类型的变量或将其用作通用类型参数。
超级猫

这个答案是完全错误的。私有构造函数与此无关。该代码仅是类的示例,仅包含静态属性和方法。它与静态类无关。
罗恩侯爵

13

当然可以,但是只能是内部嵌套的类。在那里,这意味着嵌套类的实例不需要外部类的封闭实例。

但是对于顶级类,语言设计人员无法想到与该关键字有关的任何有用信息,因此是不允许的。


尽管第一个词不准确,但+1。正如JLS所述:“内部类是未显式或隐式声明为静态的嵌套类。” (仅是术语,我知道...)
user85421 2010年

7
尽管无法声明顶级类static,但有时可以声明。例如,只包含静态帮助器方法的类没有被实例化的意义,但是Java语言并没有阻止您这样做。您可以通过声明默认构造函数来使该类对于其他类来说是不可实例化的(并且实际上是“静态的”),private因为默认构造函数禁止实例化,因为没有可见的构造函数。
伊恩·塞缪尔·麦克莱恩

12

您可以通过声明没有实例的枚举类型来创建实用程序类(不能创建实例)。即,您具体是在声明没有实例。

public enum MyUtilities {;
   public static void myMethod();
}

25
作为类型的枚举是一种特定的期望:它是一组枚举的项目。在其他情况下,只有带有私有构造函数的类才可以将其用于“实用程序类”,这在语义上是令人困惑的。
有远见的软件解决方案

5
@VisionarySoftwareSolutions对我而言,这种特殊性表示没有此类的实例,而不是间接地使得无法创建类的实例。
彼得·劳瑞

8
public class Outer {
   public static class Inner {}
}

...可以声明为静态-只要它是成员类。

从JLS:

成员类可能是静态的,在这种情况下,它们无法访问周围类的实例变量;或者它们可以是内部类(第8.1.3节)。

和这里:

static关键字可以在非内部类T的主体内修改成员类型C的声明。其作用是声明C不是内部类。正如T的静态方法在其主体中没有T的当前实例一样,C也没有T的当前实例,也没有任何词法包围的实例。

静态关键字对于顶级类没有任何意义,仅因为顶级类没有封闭类型。


如果不是内部原因,为什么要调用它InnerNested本来不会那么混乱的选择。
罗恩侯爵,

5

如上所述,一个类不能为静态,除非它是另一个类的成员。

如果要设计一个“不能有多个实例的类”,则可能需要研究“单人”设计模式。

初学者Singleton信息在这里

警告:

如果您想使用单例模式,请全力以赴。它是最容易理解的DesignPatterns之一,可能是最受欢迎的,而且肯定是最滥用的。 (来源:上面链接的JavaRanch)


4

除了Java如何定义静态内部类之外,还有根据C#world [1]定义的静态类。静态类是仅具有静态方法(函数)的类,它旨在支持过程编程。这样的类并不是真正的类,因为该类的用户仅对帮助器函数感兴趣,而对创建该类的实例不感兴趣。尽管C#支持静态类,但是Java中不存在这种直接支持。但是,您可以使用枚举来模仿Java中的C#静态类,以使用户永远无法创建给定类的实例(即使使用反射)[2]

public enum StaticClass2 {
    // Empty enum trick to avoid instance creation
    ; // this semi-colon is important

    public static boolean isEmpty(final String s) {
        return s == null || s.isEmpty();
    }
}

3

我们用Java编写的所有代码都归为一类。每当我们运行类时,JVM都会实例化一个对象。JVM可以创建许多对象,根据定义,静态意味着您具有到所有对象的相同副本集。

因此,如果Java在每次运行程序时都允许顶级类为静态,则它将创建一个Object并继续覆盖相同的Memory Location。

如果您每次运行时都只是替换对象,那么创建它的意义何在?

因此,这就是Java放弃了用于顶级类的静态方法的原因。

可能有更具体的原因,但这对我来说很合乎逻辑。


3
内部类与外部类相关联,这就是它们可以静态的原因,因为您要依赖于另一个对象。
user2626445

1
您的意思是“这就是它们不能静态的原因”。
罗恩侯爵,

2

内部类只能是静态的。以下代码可以正常工作:

public class whatever {
    static class innerclass {
    }
}

静态内部类的要点是它们没有对外部类对象的引用。


1
“静态内部”是一个矛盾。“静态”和“内部”是互斥的。您要查找的单词是“嵌套”,而不是“内部”。
罗恩侯爵,

1

我认为这和喝一杯咖啡一样容易!看看这个。定义类时,我们不会显式使用static关键字。

public class StaticClass {

    static private int me = 3;
    public static void printHelloWorld() {
       System.out.println("Hello World");
    }



    public static void main(String[] args) {
        StaticClass.printHelloWorld();
        System.out.println(StaticClass.me);
    }
}

这不是静态类的定义吗?我们只使用绑定到一个类的函数。请注意,在这种情况下,我们可以在该嵌套中使用另一个类。看这个:

class StaticClass1 {

    public static int yum = 4;

    static void  printHowAreYou() {
        System.out.println("How are you?");
    }
}

public class StaticClass {

    static int me = 3; 
    public static void printHelloWorld() {
       System.out.println("Hello World");
       StaticClass1.printHowAreYou();
       System.out.println(StaticClass1.yum);
    }



    public static void main(String[] args) {
        StaticClass.printHelloWorld();
        System.out.println(StaticClass.me);
    }
}

我认为我们可以通过引用静态类定义而不是仅使用static关键字作为限定符来将此类视为静态类。
Erfankam 2012年

确保创建一个私有的构造函数,否则您将能够说出来new StaticClass(),那实际上没有多大意义。对于私有构造函数,它将不允许其实例。
grinch 2012年

1

可以PlatformUI在Eclipse中查看具有静态方法和私有构造函数的类,而它们本身是最终的。

public final class <class name>
{
   //static constants
   //static memebers
}

0

如果使用静态类的好处不是实例化对象并使用方法,则只需将该类声明为public并将此方法声明为static。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.