Java中的静态类

1150

Java中是否存在类似于static class的东西?

这样的类是什么意思?静态类的所有方法都需要是static吗?

反过来也一样吗?如果一个类只包含静态方法,那么该类也必须是静态的吗?

静态类有什么好处?


6
你可能会对https://dev59.com/7nA65IYBdhLWcg3w4CwL感兴趣。 - Ishtar
静态类基本上用于将类分组在一起。 - MiniSu
14个回答

1015

Java有静态的嵌套类,但是听起来你正在寻找一个顶层的静态类。Java没有办法让顶层类成为静态的,但是你可以通过以下方式模拟一个静态类:

  • 声明你的类为final- 防止类被扩展,因为扩展一个静态类没有意义
  • 将构造函数设为private - 防止客户端代码实例化该类,因为实例化一个静态类没有意义
  • 将类的所有成员和函数设置为static - 由于该类不能被实例化,因此无法调用任何实例方法或访问实例字段
  • 请注意,编译器不会阻止您声明一个实例(非静态)成员。只有在尝试调用实例成员时才会出现问题

根据上述建议的简单示例:

public class TestMyStaticClass {
     public static void main(String []args){
        MyStaticClass.setMyStaticMember(5);
        System.out.println("Static value: " + MyStaticClass.getMyStaticMember());
        System.out.println("Value squared: " + MyStaticClass.squareMyStaticMember());
        // MyStaticClass x = new MyStaticClass(); // results in compile time error
     }
}

// A top-level Java class mimicking static class behavior
public final class MyStaticClass {
    private MyStaticClass () { // private constructor
        myStaticMember = 1;
    }
    private static int myStaticMember;
    public static void setMyStaticMember(int val) {
        myStaticMember = val;
    }
    public static int getMyStaticMember() {
        return myStaticMember;
    }
    public static int squareMyStaticMember() {
        return myStaticMember * myStaticMember;
    }
}

静态类有什么用处? 静态类的一个很好的用途是定义一次性、实用和/或库类,其中实例化是没有意义的。一个很好的例子是数学类(Math class),它包含一些数学常量,如π和E,并提供数学计算。在这种情况下需要实例化是不必要而且令人困惑的。请参见Math类和源代码。请注意,它是final的,其所有成员都是static的。如果Java允许顶层类声明为static,那么Math类确实将是静态的。


50
只有静态方法的Foo类与静态类Foo不同。 - craigb
15
如果一个类被声明为final,则它的方法会自动变成(有效地)final。这是因为final类不能被子类化,因此其方法不能被覆盖(即有效地成为final)。详见:http://docs.oracle.com/javase/tutorial/java/IandI/final.html - jwayne
43
这个回答或许涉及到了提问者的意思,但它(目前)没有解释Java静态类,因此根本没有回答问题!对于想要弄清Java中静态类含义的人来说,这非常糟糕。 - Tom
16
@JBoy:Java 中有一种叫做“静态类”的东西,这就是问题所在。但是,这个答案没有任何解释。相反,它解释了如何在 Java 中模拟答案所称的“静态类” - 但这不是 Java 中的“静态类”!(也许这是在其他语言中称为“静态类”的东西,但是来到这里学习 Java 静态类的人会被误导和困惑。) - Tom
8
你应该明确提到,private MyStaticClass () { // private constructor myStaticMember = 1; } 将没有任何效果,因为构造函数不会被调用。但这并不是重点。我仍然非常困惑静态内部类在Java中的实用性以及它们的效用或附加值。 - moldovean
显示剩余11条评论

358

Java有“静态嵌套类”,但它们与C#的静态类完全不同,如果您是从那里来的话。 静态嵌套类只是没有隐式引用外部类实例的类。

静态嵌套类可以具有实例方法和静态方法。

在Java中,不存在顶级静态类。


15
为什么Java的静态嵌套类允许实例方法?这样的类中的实例方法有什么用途? - Geek
20
@Geek:你读了我的答案吗? 仔细阅读第二个句子。为什么你不想能够拥有静态类的实例方法呢? 毕竟,你可以创建它们的实例。 你读过我的答案吗?注意第二句话。为什么你不想拥有静态类的实例方法?毕竟你可以创建它们的实例。 - Jon Skeet
17
@Geek:是的,这是完全允许的。你对静态类是实用程序类的“理解”是不正确的。基本上,这不是Java中静态类的意思。 - Jon Skeet
14
@Geek:是的,正如我在我的答案中所写的那样:“静态嵌套类仅指没有对外部类实例的引用的嵌套类。” - Jon Skeet
6
您的意思是“隐式”吗?鉴于您在声明时没有使用关键字“static”,它们肯定不是“显式”静态的。它们是隐式静态的,因为您无需引用任何其他内容即可构造一个对象。就个人而言,我认为对于嵌套类来说,“静态/非静态”这种术语有点奇怪...我认为更简单的做法是讨论它们的行为。 - Jon Skeet
显示剩余5条评论

187

有一个静态嵌套类,这个嵌套类不需要外部类的实例就可以被实例化。

这样的类[静态嵌套类]只能访问外部类的静态成员[因为它没有对外部类实例的引用...]

代码示例:

public class Test { 
  class A { } 
  static class B { }
  public static void main(String[] args) { 
    /*will fail - compilation error, you need an instance of Test to instantiate A*/
    A a = new A(); 
    /*will compile successfully, not instance of Test is needed to instantiate B */
    B b = new B(); 
  }
}

2
那么我们可以说我们可以使用内部静态类来实例化它们而无需使它们公开吗? - moldovean
@moldovean 我们使用内部静态类来从静态上下文(例如main)实例化它们。我认为这与可见性无关。 - Michael Dorst
3
@moldovean 静态/非静态与可见性是正交的。你可以在静态或非静态情况下拥有任何类型的可见性。关键是,你需要一个封装类的实例来创建内部类吗? - amit

128

Java中确实有静态嵌套类。当您将嵌套类声明为静态时,它会自动成为一个独立的类,可以实例化而无需实例化它所属的外部类。

示例:

public class A
{

 public static class B
 {
 }
}

因为 class B 被声明为静态,所以可以显式地实例化如下:

B b = new B();

请注意,如果未将B类声明为静态使其独立存在,则实例对象调用将如下所示:

A a= new A();
B b = a.new B();

12
请注意,如果您尝试从类“A”本身实例化非静态类,则可以像这样正常实例化它:B b = new B(); - Muhammed Refaat

44

当一个类内的成员被声明为 static 时会发生什么?这意味着可以在不实例化该类的情况下访问该成员。因此,将外部类(顶级类)声明为 static 没有意义,因此是不允许的。

但是可以将内部类设置为静态(因为它是顶级类的成员)。然后,可以在不实例化顶级类的情况下访问该类。考虑以下示例:

public class A {
    public static class B {

    }
}

现在,在另一个类C内部,可以访问类A的实例而无需创建一个实例。

public class C {
    A.B ab = new A.B();
}

static类也可以有非静态成员,只有类本身是静态的。

但是如果从类B中删除static关键字,则不能直接访问它,除非创建A的实例。

public class C {
    A a = new A();
    A.B ab = a. new B();
}

但是我们不能在一个非静态内部类中拥有static成员。


我们能否实例化一个静态类或者说这样做有意义吗? - Supun Wijerathne
7
在Java中,与其他语言不同,static只有一个含义。如果一个类中的某个元素是static,那么这个元素可以在不创建该类实例的情况下访问。这并不涉及到是否创建实例的问题。 - Ramesh-X
抱歉stackoverflow!在这种情况下,我不能不说感谢Ramesh-X!您几乎涵盖了我对静态内部类和内部类的所有疑问。 - moldovean
你不能将内部类设置为静态。这是一个“词语自相矛盾”的情况(contradiction in terms)。嵌套类要么是内部的,要么是静态的。 - user207421

26

Java中的类可以是静态的吗?

答案是可以的,在Java中我们可以有静态类。在Java中,我们有静态实例变量静态方法以及静态块。类也可以在Java中被定义为静态。

在Java中,我们不能将顶级(外部)类设为静态。只有嵌套类可以是静态的。

静态嵌套类与非静态嵌套类

1) 静态嵌套类不需要引用外部类,但是非静态嵌套类或内部类需要对外部类进行引用。

2) 内部类(或非静态嵌套类)可以访问外部类的静态和非静态成员。一个静态类不能访问外部类的非静态成员,它只能访问外部类的静态成员。

请参见:https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html


1
同时,内部的“非静态”类不能声明静态字段或方法。 - Mr.Cat
1
顶层类默认为静态,这就是为什么不能对其使用static关键字的唯一原因。这只是多余的。(不需要类的实例来访问该类,因此它们是静态的)。 - Sebastian

12

鉴于这是谷歌上“静态类java”的最高搜索结果,而最佳答案并不在此,所以我认为我应该添加一些内容。我理解OP的问题指的是C#中的静态类,在Java世界中被称为单例模式。对于那些不知道的人来说,在C#中,“static”关键字可以应用于类声明,这意味着生成的类永远无法实例化。

Josha Bloch的《Effective Java - 第二版》(被广泛认为是最好的Java样式指南之一)中的摘录:

从1.5版本开始,有第三种实现单例模式的方法。只需创建一个元素的枚举类型:

// Enum singleton - the preferred approach
public enum Elvis {
    INSTANCE;
    public void leaveTheBuilding() { ... }
}

这种方法在功能上与公共字段方法等价,只是更加简洁,提供了免费的序列化机制,并提供了一个坚不可摧的保证,即使面对复杂的序列化或反射攻击也不会多次实例化。虽然这种方法尚未被广泛采用,但单元素枚举类型是实现单例的最佳方式。(作者强调)


6
实现单例模式的好方法。不幸的是,这个问题不是关于单例模式的,而是关于静态类。 - David SN
1
Java对“static”关键字有一个相当独特的解释。看起来OP是来自C#,在Java中,“static class”相当于单例模式。我已经更新了我的答案,以明确这个问题的解释。 - Bennet Huber
2
一个 C# 的静态类不是单例模式。单例模式的实例是一个对象,可以实现接口,这意味着它可以参与依赖注入并且可以被模拟。C# 的静态类无法实现接口或以任何方式进行注入,并且更接近于一堆 C 函数,当然也允许扩展方法。 - Novaterata

7

外部类不能是静态的,但嵌套/内部类可以是静态的。这基本上帮助您在不创建外部类实例的情况下使用嵌套/内部类。


1
“静态内部类”这个词本身就是一个矛盾的说法。 - user207421
外部类默认为静态类(不需要实例来创建实例) - Sebastian

6
简单来说,Java只支持内部类声明为静态类,而不支持顶级类。
顶级类:一个Java项目可以在每个Java源文件中包含多个顶级类,其中一个类的名称与文件名相同。在顶级类之前,只允许三个选项或关键字,即public、abstract和final。
内部类:在顶级类内部的类称为内部类,这基本上是嵌套类的概念。内部类可以是静态的。使内部类静态的想法是利用实例化内部类对象而不实例化顶级类对象的优势。这与顶级类内的静态方法和变量的工作方式完全相同。
因此,Java仅支持嵌套类中的静态类。
而Java不支持在顶级类中定义静态类。
我希望这能更简单地解答有关Java中静态类的基本问题。

“静态内部类”这个词本身就是一个矛盾的说法。 - user207421
顶层类默认为静态(无需实例即可访问)。由于它们不能是非静态的(需要它们来创建实例),允许使用关键字“static”将要求将所有顶层类标记为静态。这就是为什么不支持该关键字的原因。但这并不意味着不支持静态属性。 - Sebastian

2

除非是内部类,否则不能在类中使用static关键字。静态内部类是外部类的静态成员的嵌套类。它可以在不实例化外部类的情况下访问,使用其他静态成员。就像静态成员一样,静态嵌套类没有访问外部类的实例变量和方法的权限。

public class Outer {
   static class Nested_Demo {
      public void my_method() {
          System.out.println("This is my nested class");
      }
   }
public static void main(String args[]) {
      Outer.Nested_Demo nested = new Outer.Nested_Demo();
      nested.my_method();
   }
}

1
除非它是一个嵌套类,否则您不能在类中使用 static 关键字。 'Static inner' 是一个自相矛盾的词语 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接