[英]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.