为什么Java类不能声明为静态的?

27

我正在尝试找出为什么该类不能被创建为静态的?例如:

public static class Qwert {    
    public static void main(String args[]) {
        int x = 12;
        while (x<12) {
            x--;
        }
        System.out.println(" the X value is : "+ x);
    }
}
6个回答

64
在Java中,static关键字通常用于标记一个方法或字段不是每个类实例都存在一次,而是仅存在一次。由于一个类本身只存在一次,因此所有类在这种方式上都是“静态的”,并且所有对象都是类的实例。 static对于内部类有一个完全不同的含义:通常,内部类实例可以访问其绑定到的外部类实例的成员,但如果内部类是static,它就没有这样的引用,并且可以在没有外部类实例的情况下实例化。也许你在某个地方看到过它,然后试图在顶级类中使用它,在那里它没有意义。
或者你在其他语言中看到了它,比如C#,其语法非常像Java的语法。
(有一次我无法弄清楚为什么一个外部类实例没有被垃圾回收——原来是因为我在别处保留了其内部类实例之一的引用,而该内部类不是static,因此具有对外部类实例的引用。因此,默认情况下,我现在使内部类static。)

3
几乎完全正确。内部类默认情况下不是静态的,也就是说每个具有嵌套类的类实例都会有自己的嵌套类副本。这就是你可以在类中引用“this”的原因,也是为什么不能声明静态方法或字段,因为外部类的每个实例都有自己的副本,这样做没有意义。一个“静态”嵌套类(根据定义是真正的“内部”类)意味着只有一个该类的副本,这更像是普通类。我一直认为这些嵌套类的语义非常复杂。 - Jeff Walker
我还扭曲了关于非静态方法在内存角度上每个实例只存在一次的事实,实际上并不是这样的。我只是想表达一个概念上的观点。 - easeout
@jeff,静态声明的内部类和非静态声明的内部类在从该类实例化对象方面有什么区别?是否存在某种类型,即您只能从静态内部类实例化单个对象,并且可以从非静态内部类实例化多个对象?就是这样吗? - ultrajohn
对于变量而言,它不是一次性的,而是每个类一次。由于一个类可以被不同的类加载器多次加载,因此它的静态成员可以存在多个,尽管在不同的命名空间中。 - Lawrence Dol
如果内部类是静态的,那么它只是在另一个类中声明的类,因此您可以正常实例化它。否则,您必须有一个外部类实例来执行它,因为新实例将使用其成员。完整的语法是“outerClassInstance.new InnerClass(args)”。但是,如果“this”是外部类的实例,则可以只说“new InnerClass(args)”,它将把实例与“this”关联起来。 - easeout
显示剩余3条评论

8
为了防止一个特定的类被实例化,您应该添加一个私有构造函数。这样可以阻止“任何其他”类能够创建类型为 Qwert 的对象。
例如:
    public class Qwert {
    
        
        private Qwert() {}

        public static void main(String args[]){
    
            int x = 12;
            while(x<12){
                x--;
            }
            System.out.println(" the X value is : "+ x);
        }
    }

好的洞察力,这可能是他当时想做的事情。 - easeout
在我将一个类声明为static时,出现了modifier static not allowed here的错误,就像这个例子一样。 - Rafs
嗨@RTD,我已经更新了代码以修复编译器错误源。这基本上是原始问题的复制/粘贴,所以当我在Stackoverflow上输入它时,我没有将其放入编译器中(13年前)。 - edwardsmatt

2
我们应该将成员定义为静态,这些成员应满足以下条件:
1. 应该是类的所有对象共有的。 2. 应该属于类并可通过类名访问。 3. 不需要一个类的对象来访问它们。
现在假设我们将外部类定义为静态,并且允许这样做。这会为开发人员带来任何好处或优势吗?还是会给开发人员和语言创建者带来歧义和复杂性?
让我们检查一下,将外部类定义为静态是否符合我们上述定义的目的。
根据以上三点,我们可以说Java创建者之所以不允许外部类为静态是因为没有必要使它静态化。允许将外部类定义为静态只会增加复杂性、模棱两可和重复性。了解更多信息,请参阅为什么外部Java类不能是静态的

1
为了防止任何类通过继承或使用反射创建Qwert的实例,您可以通过放置一个毒丸来使构造函数失败:
public class Qwert { 

    private Qwert() throws IllegalAccessException {
        throw new IllegalAccessException("Utility class!");
    }

    public static class Yuiop {
        public Yuiop() throws IllegalAccessException {
            // generates a synthetic accessor method to super()
        }
    }

    public static void main(String args[]) {
        new Yuiop();
    }
}

1

当我们为组件使用静态关键字时,该组件变成了类级别的组件,并且其内存由其类占用。


0
在Java中,根据定义,静态应用于类的内部组件。 "X是静态的"在Java中意味着“X与其定义的类相关联,而不是与类的任何实例相关联”。
“静态”一词字面意思是“固定在内存中的一个位置”。类的每个实例共享静态变量或静态成员。因此,“类变量”被用作“静态变量”的同义词。这让您立即看到,您不能将外部类定义为静态。
因此,您的类Qwert不能被创建为静态。除非它被包含为外部类的组件,从而使其成为内部类。

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