[英]What does the 'static' keyword do in a class?
具体来说,我正在尝试以下代码:
package hello;
public class Hello {
Clock clock = new Clock();
public static void main(String args[]) {
clock.sayTime();
}
}
但它给出了错误
无法访问静态方法 main 中的非静态字段
所以我把clock
的声明改成这样:
static Clock clock = new Clock();
它奏效了。 将关键字放在声明之前是什么意思? 就可以对该对象执行的操作而言,它究竟会做什么和/或限制什么?
static
成员属于类而不是特定实例。
这意味着只有一个static
字段的实例存在[1] ,即使您创建了一百万个该类的实例或者您没有创建任何实例。 它将由所有实例共享。
由于static
方法也不属于特定实例,因此它们不能引用实例成员。 在给出的示例中, main
不知道应该引用Hello
类的哪个实例(因此也不知道Clock
类的哪个实例)。 static
成员只能引用static
成员。 实例成员当然可以访问static
成员。
Of course, static
members can access instance members through an object reference .当然, static
成员可以通过对象引用访问实例成员。
例子:
public class Example {
private static boolean staticField;
private boolean instanceField;
public static void main(String[] args) {
// a static method can access static fields
staticField = true;
// a static method can access instance fields through an object reference
Example instance = new Example();
instance.instanceField = true;
}
[1]:根据运行时特性,它可以是每个 ClassLoader 或 AppDomain 或线程一个,但这不是重点。
这意味着 Hello 中只有一个“时钟”实例,而不是每个单独的“Hello”类实例都有一个,或者更多,这意味着在所有实例之间将有一个共同共享的“时钟”引用“你好”类。
因此,如果您要在代码中的任何位置执行“新 Hello”: A- 在第一个场景中(在更改之前,不使用“静态”),每次调用“新 Hello”时都会生成一个新时钟,但是 B- 在第二种情况下(更改后,使用“静态”),每个“新 Hello”实例仍将共享并使用最初创建的相同“时钟”引用。
除非您在 main 之外的某个地方需要“时钟”,否则这也可以:
package hello;
public class Hello
{
public static void main(String args[])
{
Clock clock=new Clock();
clock.sayTime();
}
}
static
关键字意味着某些东西(字段、方法或嵌套类)与类型相关,而不是与该类型的任何特定实例相关。 例如,在没有任何Math
类实例的情况下调用Math.sin(...)
,实际上您无法创建Math
类的实例。
有关更多信息,请参阅Oracle 的 Java 教程的相关部分。
边注
不幸的是,Java允许您像访问实例成员一样访问静态成员,例如
// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);
这使它看起来好像sleep
是一个实例方法,但它实际上是一个静态方法 - 它总是使当前线程休眠。 最好在调用代码中明确这一点:
// Clearer
Thread.sleep(5000);
Java 中的static
关键字意味着变量或函数在该类的所有实例之间共享,因为它属于type ,而不是实际的对象本身。
所以如果你有一个变量: private static int i = 0;
并且您在一个实例中增加它( i++
),更改将反映在所有实例中。 i
现在在所有情况下都是 1。
无需实例化对象即可使用静态方法。
静态成员的基本用法...
public class Hello
{
// value / method
public static String staticValue;
public String nonStaticValue;
}
class A
{
Hello hello = new Hello();
hello.staticValue = "abc";
hello.nonStaticValue = "xyz";
}
class B
{
Hello hello2 = new Hello(); // here staticValue = "abc"
hello2.staticValue; // will have value of "abc"
hello2.nonStaticValue; // will have value of null
}
这就是您可以在所有类成员中共享值的方式,而无需将类实例 Hello 发送到其他类。 而且你不需要创建类实例。
Hello hello = new Hello();
hello.staticValue = "abc";
您可以通过类名调用静态值或方法:
Hello.staticValue = "abc";
静态意味着您不必创建类的实例即可使用与类关联的方法或变量。 在您的示例中,您可以调用:
Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class
直接,而不是:
Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the "h" variable
从静态方法(属于类)内部,您无法访问任何非静态成员,因为它们的值取决于您对类的实例化。 作为实例成员的非静态时钟对象对于 Hello 类的每个实例都有不同的值/引用,因此您无法从类的静态部分访问它。
Java中的静态:
静态是非访问修饰符。 static 关键字属于类而不是类的实例。 可用于将变量或方法附加到类。
静态关键字可用于:
方法
多变的
嵌套在另一个类中的类
初始化块
不能用于:
类(未嵌套)
构造函数
接口
方法局部内部类(差异然后嵌套类)
内部类方法
实例变量
局部变量
例子:
想象一下下面的例子,它有一个名为 count 的实例变量,它在构造函数中递增:
package pkg;
class StaticExample {
int count = 0;// will get memory when instance is created
StaticExample() {
count++;
System.out.println(count);
}
public static void main(String args[]) {
StaticExample c1 = new StaticExample();
StaticExample c2 = new StaticExample();
StaticExample c3 = new StaticExample();
}
}
输出:
1 1 1
由于实例变量在对象创建时就获得了内存,所以每个对象都会有实例变量的副本,如果递增,就不会反映到其他对象。
现在,如果我们将实例变量 count 更改为静态变量,那么程序将产生不同的输出:
package pkg;
class StaticExample {
static int count = 0;// will get memory when instance is created
StaticExample() {
count++;
System.out.println(count);
}
public static void main(String args[]) {
StaticExample c1 = new StaticExample();
StaticExample c2 = new StaticExample();
StaticExample c3 = new StaticExample();
}
}
输出:
1 2 3
在这种情况下,静态变量只会获得一次内存,如果任何对象更改了静态变量的值,它将保留其值。
静态与最终:
声明为final 和 static的全局变量在整个执行过程中保持不变。 因为,静态成员存储在类内存中,并且在整个执行过程中只加载一次。 它们对类的所有对象都是通用的。 如果将静态变量声明为 final,则任何对象都无法更改其值,因为它是 final。 因此,声明为 final 和 static 的变量有时称为常量。 接口的所有字段都称为常量,因为默认情况下它们是最终的和静态的。
图片资源:最终静态
到目前为止,这个讨论忽略了类加载器的考虑。 严格来说,Java 静态字段在给定类加载器的类的所有实例之间共享。
关键字static
用于表示属于类本身而不是实例的字段或方法。 使用您的代码,如果对象Clock
是静态的,则Hello
类的所有实例将共享此Clock
数据成员(字段)。 如果将其设为非静态,则Hello
的每个单独实例都可以有一个唯一的Clock
字段。
您向Hello
类添加了一个main方法,以便您可以运行代码。 问题在于main方法是静态的,因此它不能引用其中的非静态字段或方法。 您可以通过两种方式解决此问题:
Hello
类的所有字段和方法设为静态,以便可以在main方法中引用它们。 这真的不是一件好事(或者使字段和/或方法静态的错误原因)Hello
类的实例,并按照最初的预期方式访问它的所有字段和方法。对您而言,这意味着对您的代码进行以下更改:
package hello;
public class Hello {
private Clock clock = new Clock();
public Clock getClock() {
return clock;
}
public static void main(String args[]) {
Hello hello = new Hello();
hello.getClock().sayTime();
}
}
可以将字段分配给类或类的实例。 默认情况下,字段是实例变量。 通过使用static
字段成为一个类变量,因此只有一个clock
。 如果您在一个地方进行更改,它在任何地方都可见。 实例变量彼此独立地更改。
在 Java 中, static
关键字可以简单地认为表示以下内容:
“不考虑或与任何特定实例有关”
如果您以这种方式考虑static
,则更容易理解它在遇到它的各种上下文中的使用:
static
字段是属于类而不是任何特定实例的字段
static
方法是没有this
概念的方法; 它是在类上定义的,并且不知道该类的任何特定实例,除非将引用传递给它
static
成员类是一个嵌套类,对其封闭类的实例没有任何概念或知识(除非将对封闭类实例的引用传递给它)
我已经对“助手”类中的静态方法(仅在可能的情况下)产生了兴趣。
调用类不需要创建帮助类的另一个成员(实例)变量。 您只需调用助手类的方法。 辅助类也得到了改进,因为您不再需要构造函数,并且不需要成员(实例)变量。
可能还有其他优点。
静态使时钟成员成为类成员而不是实例成员。 如果没有 static 关键字,您将需要创建 Hello 类的实例(它有一个时钟成员变量) - 例如
Hello hello = new Hello();
hello.clock.sayTime();
静态方法不使用定义它们的类的任何实例变量。可以在此页面上找到对差异的很好解释
//Here is an example
public class StaticClass
{
static int version;
public void printVersion() {
System.out.println(version);
}
}
public class MainClass
{
public static void main(String args[]) {
StaticClass staticVar1 = new StaticClass();
staticVar1.version = 10;
staticVar1.printVersion() // Output 10
StaticClass staticVar2 = new StaticClass();
staticVar2.printVersion() // Output 10
staticVar2.version = 20;
staticVar2.printVersion() // Output 20
staticVar1.printVersion() // Output 20
}
}
还可以考虑没有“this”指针的静态成员。 它们在所有实例之间共享。
了解静态概念
public class StaticPractise1 {
public static void main(String[] args) {
StaticPractise2 staticPractise2 = new StaticPractise2();
staticPractise2.printUddhav(); //true
StaticPractise2.printUddhav(); /* false, because printUddhav() is although inside StaticPractise2, but it is where exactly depends on PC program counter on runtime. */
StaticPractise2.printUddhavsStatic1(); //true
staticPractise2.printUddhavsStatic1(); /*false, because, when staticPractise2 is blueprinted, it tracks everything other than static things and it organizes in its own heap. So, class static methods, object can't reference */
}
}
二等舱
public class StaticPractise2 {
public static void printUddhavsStatic1() {
System.out.println("Uddhav");
}
public void printUddhav() {
System.out.println("Uddhav");
}
}
main()
是一个静态方法,它有两个基本限制:
this()
和super()
不能在静态上下文中使用。
class A { int a = 40; //non static public static void main(String args[]) { System.out.println(a); } }
输出:编译时错误
静态变量只能在静态方法中访问,所以当我们声明静态变量时,getter和setter方法将是静态方法
静态方法是我们可以使用类名访问的类级别
以下是静态变量 Getter 和 Setter 的示例:
public class Static
{
private static String owner;
private static int rent;
private String car;
public String getCar() {
return car;
}
public void setCar(String car) {
this.car = car;
}
public static int getRent() {
return rent;
}
public static void setRent(int rent) {
Static.rent = rent;
}
public static String getOwner() {
return owner;
}
public static void setOwner(String owner) {
Static.owner = owner;
}
}
这里提出了一个关于为这个概念选择“静态”这个词的问题。 这是对这个问题的欺骗,但我认为词源没有得到明确解决。 所以...
这是由于关键字重用,从 C 开始。
考虑 C 中的数据声明(在函数体内):
void f() {
int foo = 1;
static int bar = 2;
:
}
变量 foo 在进入函数时在堆栈上创建(并在函数终止时销毁)。 相比之下, bar 总是在那里,所以它在普通英语的意义上是“静态的”——它不会去任何地方。
Java 和类似的语言对数据有相同的概念。 可以为每个类的实例(每个对象)分配数据,也可以为整个类分配一次。 由于 Java 旨在为 C/C++ 程序员提供熟悉的语法,因此“静态”关键字在这里是合适的。
class C {
int foo = 1;
static int bar = 2;
:
}
最后,我们来谈谈方法。
class C {
int foo() { ... }
static int bar() { ... }
:
}
从概念上讲,类 C 的每个实例都有一个 foo() 实例。整个 C 类只有一个 bar() 实例。这与我们讨论的数据情况类似,因此使用 'static ' 又是一个明智的选择,特别是如果您不想在您的语言中添加更多保留关键字。
在运行某些项目时,首先要加载静态内容(变量,方法,块..)。
运行此项目时,首先加载主方法。 因为它是static method
。 然后,它看起来是对象"a" object
。但是对象a尚未定义。 因为它是非静态的。 然后出现此错误。
Java 程序中的成员可以使用其声明/定义之前的关键字“static”声明为静态的。 当一个成员被声明为静态时,它本质上意味着该成员由一个类的所有实例共享,而无需为每个实例制作副本。
因此 static 是 Java 中使用的非类修饰符,可以应用于以下成员:
当一个成员被声明为静态的,那么它就可以在不使用对象的情况下被访问。 这意味着在类被实例化之前,静态成员是活动的并且是可访问的。 与当类的对象超出范围时不再存在的其他非静态类成员不同,静态成员显然仍然是活动的。
Java中的静态变量
声明为静态的类的成员变量称为静态变量。 它也被称为“类变量”。 一旦变量被声明为静态,内存只分配一次,而不是每次实例化类时。 因此,您可以在不引用对象的情况下访问静态变量。
以下 Java 程序描述了静态变量的用法:
class Main
{
// static variables a and b
static int a = 10;
static int b;
static void printStatic()
{
a = a /2;
b = a;
System.out.println("printStatic::Value of a : "+a + " Value of b :
"+b);
}
public static void main(String[] args)
{
printStatic();
b = a*5;
a++;
System.out.println("main::Value of a : "+a + " Value of b : "+b);
}
}
输出::
printStatic::Value of a : Value of b : 5
main::Value of a : 6 Value of b : 25
在上面的程序中,我们有两个静态变量,即 a 和 b。 我们在函数“printStatic”和“main”中修改这些变量。 请注意,即使函数范围结束,这些静态变量的值也会在函数中保留。 输出显示两个函数中的变量值。
静态方法
当 Java 中的方法前面带有关键字“static”时,它就是静态的。
关于静态方法,您需要记住的一些要点包括:
以下程序显示了 Java 中静态方法的实现:
class Main
{
// static method
static void static_method()
{
System.out.println("Static method in Java...called without any
object");
}
public static void main(String[] args)
{
static_method();
}
}
输出:
Static method in Java...called without any object
Java中的静态块
就像您在 Java 中的 C++、C# 等编程语言中具有功能块一样,也有一个称为“静态”块的特殊块,它通常包含与静态数据相关的代码块。
此静态块在创建类的第一个对象时(准确地说是在类加载时)或使用块内的静态成员时执行。
以下程序显示了静态块的用法。
class Main
{
static int sum = 0;
static int val1 = 5;
static int val2;
// static block
static {
sum = val1 + val2;
System.out.println("In static block, val1: " + val1 + " val2: "+
val2 + " sum:" + sum);
val2 = val1 * 3;
sum = val1 + val2;
}
public static void main(String[] args)
{
System.out.println("In main function, val1: " + val1 + " val2: "+ val2 + " sum:" + sum);
}
}
输出:
In static block, val1: 5 val2: 0 sum:5
In main function, val1: val2: 15 sum:20
静态类
在 Java 中,您有静态块、静态方法,甚至是静态变量。 因此很明显,您也可以拥有静态类。 在 Java 中,可以在另一个类中包含一个类,这称为嵌套类。 包含嵌套类的类称为 Outer 类。
在 Java 中,虽然可以将嵌套类声明为静态,但不能将外部类声明为静态。
现在让我们探索 Java 中的静态嵌套类。
静态嵌套类
如前所述,您可以在 Java 中将嵌套类声明为静态。 静态嵌套类在某些方面不同于非静态嵌套类(内部类),如下所示。
与非静态嵌套类不同,嵌套静态类不需要外部类引用。
静态嵌套类只能访问外部类的静态成员,而非静态类可以访问外部类的静态成员和非静态成员。
下面给出了一个静态嵌套类的示例。
class Main{
private static String str = "SoftwareTestingHelp";
//Static nested class
static class NestedClass{
//non-static method
public void display() {
System.out.println("Static string in OuterClass: " + str);
}
}
public static void main(String args[])
{
Main.NestedClassobj = new Main.NestedClass();
obj.display();
}
}
输出
Static string in OuterClass: SoftwareTestingHelp
我认为这就是 static 关键字在 java 中的工作方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.