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

Posted

技术标签:

【中文标题】为啥不能在 Java 中将类声明为静态?【英文标题】:Why are you not able to declare a class as static in Java?为什么不能在 Java 中将类声明为静态? 【发布时间】:2011-04-04 18:56:24 【问题描述】:

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

【问题讨论】:

反问:如果您将***类声明为static,您期望的效果是什么? 不,你不能,除了静态内部类。但是,你想用它来实现什么? @Joachim Sauer:嗯,C# 将static 类解释为abstract final,即它们不能被实例化,也不能被扩展。这意味着它们只能包含静态成员,这对于只包含辅助方法的类很有用。 @bcat 这对于 C# 来说是正确的,但是 java 类可以是抽象的或最终的,不能同时是两者。为了防止类被实例化,可以声明一个私有构造函数。 @JoachimSauer 很简单,我很想强制类中的所有成员都是静态的(甚至可能必须在每个方法或属性上声明)。 【参考方案1】:
public class Outer 
   public static class Inner 

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

来自 JLS:

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

这里:

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

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

【讨论】:

如果不是内部的,为什么叫它InnerNested 会是一个不那么令人困惑的选择。【参考方案2】:

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

但是对于***类,语言设计者想不出关键字有什么用,所以是不允许的。

【讨论】:

+1 尽管第一个短语不准确。正如 JLS 所说:“内部类是一个嵌套类,它没有显式或隐式声明为静态的。” (只是术语,我知道...) 虽然***类不能声明为static,但有时可以这样做是有意义的。例如,仅包含静态辅助方法的类实例化没有意义,但 Java 语言不会阻止您这样做。您可以通过声明默认构造函数private 使该类对其他类不可实例化(实际上是“静态”),该构造函数禁止实例化,因为没有可见的构造函数。【参考方案3】:

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

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();

来源:

Oracle tutorial on nested classes

关于同一主题:

Java: Static vs non static inner class Java inner class and static nested class

【讨论】:

+1 尽管第一个短语不准确。正如教程所述,“非静态嵌套类称为内部类”。 (JLS:“内部类是没有显式或隐式声明为静态的嵌套类。”) 你肯定是对的;但我不明白这是如何回答问题的 @Carlos Heuberger,你说得对,我更新了帖子。 @Joeri Hendrickx,问题是,“为什么不能将一个类声明为静态的......?”,他们可以,并且[在这里阅读我的帖子]。它解释了静态类的用法以及为什么它们必须是嵌套类。 这里给出的解决方案很好......但我仍然想知道你们没有从逻辑上解释静态类在java中是不可能的......一些OOPs概念解释将是正确的答案。我正在等待它 没错,但是当您开始问自己“静态类”是什么时,您正在考虑的问题通常会自行解决。在 java 中,静态元素意味着您可以在没有封闭类的实例的情况下访问/调用它;如果您将关键字应用于类本身,这可能意味着什么?你的意图是什么?你会期待什么?既然你已经知道它可能是什么,我很确定它要么是“没有意义”,要么是“牵强附会”(这是有道理的,但最终它只是一个选择已完成)。【参考方案4】:

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

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

初学者单身信息here.

警告:

如果您正在考虑使用 单例模式,全力抵抗 你的力量。它是最简单的之一 要理解的设计模式,可能 最受欢迎的,绝对是 受虐最多。 (来源:如上链接的 JavaRanch)

【讨论】:

【参考方案5】:

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

public enum MyUtilities ;
   public static void myMethod();

【讨论】:

枚举作为一种类型是一种特定的期望:它是一组枚举项。将它用于“实用程序类”,否则您可以只拥有一个带有私有构造函数的类,这在语义上是令人困惑的。 @VisionarySoftwareSolutions 对我来说,这种特殊性表明没有此类的实例,而不是间接地使创建类的实例成为不可能。【参考方案6】:

我认为这就像喝一杯咖啡一样简单! 看看这个。 我们在定义类时不显式使用 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);
    

【讨论】:

我认为我们可以通过引用静态类定义而不是仅仅使用静态关键字作为限定符来将此类类视为静态类。 一定要创建一个私有构造函数,否则你可以说new StaticClass(),这并没有多大意义。使用私有构造函数,它不会允许它的实例。【参考方案7】:

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

像这样声明你的类:

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();
...

【讨论】:

它不是静态的,而是包含静态属性。如果你写 public final int ECodeOauthUnknown = 0x10;它不再是静态的了。 如果有人想知道这里发生了什么,这与“静态类”的 C# 定义相匹配 - msdn.microsoft.com/en-us/library/79b3xss3%28v=vs.90%29.aspx 。鉴于“静态类”的 Java 定义,所有非内部类都是静态的(参见同级答案)。 除了@user1883212 是对的之外,我什至会说这个答案让读者感到困惑,私有构造函数在这里很重要,而实际上根本不重要。 在 .NET 世界中,如果一个类被标记为 abstract 和 final(C# 中 static class 声明的效果),编译器甚至不允许代码声明该类型的变量,也不将其用作泛型类型参数。仅仅在一个类中缺少可访问的构造函数,否则这些构造函数可以被实例化或继承,这并不妨碍声明该类型的变量,也不排除将其用作泛型类型参数。 这个答案完全不正确。私有构造函数与它无关。代码只是一个只有静态属性和方法的类的示例。它与静态类无关。【参考方案8】:

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

public final class <class name>

   //static constants
   //static memebers

【讨论】:

【参考方案9】:

如果使用静态类的好处不是实例化对象和使用方法,那么只需将类声明为公共的,并将此方法声明为静态的。

【讨论】:

【参考方案10】:

除了 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();
    

【讨论】:

【参考方案11】:

所以,我来晚了,但这是我的两分钱 - 从哲学上补充 Colin Hebert 的答案。

从高层次上讲,您的问题涉及对象和类型之间的区别。虽然有许多汽车(对象),但汽车类(类型)只有一个。将某些东西声明为静态意味着您正在“类型”空间中操作。只有一个。***类关键字已经在“类型”空间中定义了一个类型。因此“公共静态类 Car”是多余的。

【讨论】:

是的。换句话说,***类默认是静态的,所以不需要关键字。 好吧,我想补充一下 Warren Dew 所说的——“在访问静态成员时,***类默认是静态的”。 被低估的答案。强制类中的每个方法都是静态的并且构造函数私有的新关键字会很好。我不会将其命名为静态的,因为这会让人感到困惑。 @G_V 尽管 java 可以创造出这样一个怪物,但 Java 几乎不遗余力地让愚蠢的事情变得困难。一般来说,静态是一个坏主意,静态类是可怕的(比本身被认为是反模式的单例更糟糕)。许多人不理解这一点,因此给它一个关键字将是一个非常糟糕的主意。相反,我们让不好的事情变得困难,然后就这样吧。请注意,也没有“Singleton”关键字。并且没有 Property 关键字。这些都会导致糟糕的代码(尽管人们仍然大量使用属性,Java 不妨支持它们)【参考方案12】:

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

public class whatever 
    static class innerclass 
    

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

【讨论】:

“静态内部”在术语上是矛盾的。 “静态”和“内部”是相互排斥的。您要查找的词是“嵌套”,而不是“内部”。【参考方案13】:

我们在 java 中编写的所有代码都进入了一个类。每当我们运行一个类时,JVM 都会实例化一个对象。 JVM 可以创建多个对象,根据定义,静态意味着您对所有对象拥有相同的副本集。

因此,如果 Java 在您运行程序时允许***类是静态的,它会创建一个对象并继续覆盖相同的内存位置。

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

这就是 Java 摆脱***类的静态的原因。

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

【讨论】:

内部类与外部类相关联,这就是它们可以是静态的原因,因为您需要依赖不同的对象。 您的意思是“这就是它们是静态的原因”。【参考方案14】:

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

【讨论】:

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

以上是关于为啥不能在 Java 中将类声明为静态?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能只用前向声明 C++ 声明一个类的静态成员?

为啥 main() 不能在 C 中声明为静态的?

为啥我们不能在(非静态)内部类(Java 16 之前)中使用静态方法?

我可以在Java中的静态成员函数中声明一个静态变量吗?

为啥我不能在 .net 核心中将静态属性与通知绑定?

Java中的静态类