什么是“静态”?
我开始用Java编程。
public static void main(String[]args)
一本书说我应该在这种情况下使用静态,但没有明确说明为什么我应该或它意味着什么。
你能澄清一下吗?
static
的概念与某些东西是某个类还是某个对象(实例)的一部分有关。
在声明为static
的main
方法的情况下,它表示main
方法是一个类方法 – 一个方法,它是类的一部分,而不是对象的一部分。 这意味着另一个类可以通过引用ClassName.method
来调用另一个类的类方法。 例如,调用MyClass
的run方法将通过以下方式完成:
MyClass.main(new String[]{"parameter1", "parameter2"});
另一方面,没有static
修饰符的方法或字段意味着它是对象的一部分(或者也称为“实例”)而不是类的一部分。 它由方法或字段所属的特定对象的名称引用,而不是类名:
MyClass c1 = new MyClass(); c1.getInfo() // "getInfo" is an instance method of the object "c1"
由于每个实例可能具有不同的值,因此不同对象中具有相同名称的方法或字段的值不一定必须相同:
MyClass c1 = getAnotherInstance(); MyClass c2 = getAnotherInstance(); c1.value // The field "value" for "c1" contains 10. c2.value // The field "value" for "c2" contains 12. // Because "c1" and "c2" are different instances, and // "value" is an instance field, they can contain different // values.
结合实例和类变量的两个概念。 假设我们声明一个包含实例和类变量和方法的新类:
class AnotherClass { private int instanceVariable; private static int classVariable = 42; public int getInstanceVariable() { return instanceVariable; } public static int getClassVariable() { return classVariable; } public AnotherClass(int i) { instanceVariable = i; } }
上面的类有一个实例变量instanceVariable
,以及一个用static
修饰符声明的类变量classVariable
。 同样,有一个实例和类方法来检索值。
实例的构造函数将值作为参数分配给实例变量。 类变量初始化为42
并且永远不会更改。
让我们实际使用上面的类,看看会发生什么:
AnotherClass ac1 = new AnotherClass(10); ac1.getInstanceVariable(); // Returns "10" AnotherClass.getClassVariable(); // Returns "42"
请注意调用类和实例方法的不同方法。 它们通过名称AnotherClass
引用类的AnotherClass
,或名称为ac1
的实例。 让我们进一步看看方法的行为差异:
AnotherClass ac1 = new AnotherClass(10); AnotherClass ac2 = new AnotherClass(20); ac1.getInstanceVariable(); // Returns "10" AnotherClass.getClassVariable(); // Returns "42" ac2.getInstanceVariable(); // Returns "20" AnotherClass.getClassVariable(); // Returns "42"
可以看出,实例变量是由对象(或“实例”)保持的实例变量,因此对于该特定实例是唯一的,在该示例中该实例是由ac1
和ac2
引用的对象。
另一方面,类变量仅对整个类是唯一的。 为了更好地AnotherClass
这一点,让我们为AnotherClass
添加一个新方法:
public int getClassVariableFromInstance() { return classVariable; }
然后,运行以下命令:
AnotherClass ac1 = new AnotherClass(10); AnotherClass ac2 = new AnotherClass(20); ac1.getInstanceVariable(); // Returns "10" ac1.getClassVariableFromInstance(); // Returns "42" ac2.getInstanceVariable(); // Returns "20" ac2.getClassVariableFromInstance(); // Returns "42"
尽管getClassVariableFromInstance
是一个实例方法,通过引用实例ac1
和ac2
可以看出,它们都返回相同的值42
。 这是因为在两个实例方法中,它们都引用类方法classVariable
,它对类是唯一的,而不是对实例的引用 – 对于类AnotherClass
只有一个classVariable
的AnotherClass
。
我希望有些内容可以澄清static
修饰符的用途。
Sun 的Java教程有一个名为Understanding Instance and Class Members的部分 ,它也涉及两种类型的变量和方法。
请在维基百科上看到一个很好的描述
例如,请注意在Math类中,您可以说出类似的内容
Math.Abs(x);
不必说
Math m = new Math();
这些是静态方法,因为您不需要实例。 实例方法是那些要求您拥有类实例的方法。
Employee e = new Employee(); e.Terminate();
静态方法是适用于整个类的方法,而不是任何特定成员。 .goExtinct()将是一个整体鸭子种群的方法,而不是任何特定的鸭子。 main是public和static,因为它必须始终可用,并且它不是任何特定类的一部分。
通常,您必须拥有一个对象,即类的实例,以便在其上调用方法,至少有两个原因:
- 它取决于哪个类实现被调用方法的对象。 例如,如果您有子类的实例,则将调用子类中的方法,即使调用该方法的代码相同也是如此。
- 对象通常具有内部状态(字段),方法可以参考。 如果没有对象实例,这不起作用。
您可以通过调用类的构造函数来创建对象实例:
MyObject a = new MyObject();
静态方法是未附加到对象实例的方法。 可以通过命名类来调用它们。 由于他们这样做
- 无法动态调度到子类(这就是为什么当你尝试在对象实例上调用它时会收到警告 ,这只是令人困惑的语法)
- 它们不能引用实例状态 (非静态字段和其他非静态方法)。
许多人认为静态方法是一种糟糕的设计模式,并建议不要使用它们( public static void main
除外)查找单例实例模式以获取替代方案。
在这种特殊情况下,main方法必须是静态的,因为JVM将开始加载类和创建对象的方式。 当您启动Java程序时,JVM将查找传递给它的类的定义并加载它。 所以java MyClass将导致加载MyClass类的定义。
根据定义,Java程序将在作为最初加载的类传递给JVM的类的main()方法中开始执行。 此时,没有创建MyClass类型的实例(对象),因此main方法必须是静态的,以允许开始执行程序。
如果要查看在执行Java程序期间正在加载哪些类,可以使用-verbose:class命令行选项。
在任何面向对象的编程语言(如Java或C ++)中,您创建的类在最基本的级别上类似于建筑物的BluePrints。 您可以查看蓝图并确定各种组件的连接方式,但实际上并不能存在。 类和对象也是一样的。 类是蓝图,您创建一个名为Object的类的实例。 对于相同的蓝图,您可以拥有多个建筑物,对于一个类别,您可以拥有多个对象。 Object是类的实例。 可以在Object或类的实例上调用类中的每个方法,而对于调用静态方法,您实际上不需要实例,可以直接调用ClassName.method()而无需实际创建类的实例。
有时你会想要定义一个独立于该类的任何对象使用的类成员。 通常,只能与类的对象一起访问类成员。 但是,可以创建一个可以单独使用的成员,而无需引用特定实例。 要创建此类成员,请在其声明前面加上关键字static。 当成员声明为static时,可以在创建其类的任何对象之前访问它,而不引用任何对象。 您可以将方法和变量声明为静态。 静态成员最常见的例子是main()。 main()声明为static,因为必须在任何对象存在之前调用它。 两种类型的静态成员是静态字段和静态方法:
Static field:
使用static关键字声明的字段,如下所示:
private static int ballCount:
static关键字的位置可以与可见性关键字(私有和公共,以及受保护)的位置互换。 因此,以下声明也适用:
static private int ballCount;
作为惯例,大多数程序员倾向于将可见性关键字放在首位。
静态字段的值在类的所有实例中都是相同的。 换句话说,如果类具有名为CompanyName的静态字段,则从该类创建的所有对象将具有相同的CompanyName值。
首次加载类时,将创建并初始化静态字段。 当引用类的静态成员或创建类的实例时(以先到者为准),就会发生这种情况。
Static method:
使用static关键字声明的方法。 与静态字段一样,静态方法与类本身相关联,而不是与从类创建的任何特定对象相关联。 因此,在使用类定义的静态方法之前,不必从类创建对象。
最着名的静态方法是main,由Java运行时调用以启动应用程序。 main方法必须是静态的,这意味着默认情况下应用程序在静态上下文中运行。
使用静态方法的基本规则之一是您无法从静态方法访问非静态方法或字段,因为静态方法没有用于引用实例方法或字段的类的实例。