关于Java:”静态”关键字在一个类中做什么?

What does the 'static' keyword do in a class?

具体来说,我尝试了以下代码:

1
2
3
4
5
6
7
8
9
10
package hello;

public class Hello {

    Clock clock = new Clock();

    public static void main(String args[]) {
        clock.sayTime();
    }
}

但它给出了错误

Cannot access non-static field in static method main

所以我把EDOCX1的声明改为:

1
static Clock clock = new Clock();

它奏效了。把那个关键字放在声明之前意味着什么?它究竟会做什么和/或限制在什么可以做的对象上?


static成员属于类,而不是特定的实例。

这意味着一个static字段只有一个实例存在[1],即使您创建了一百万个该类的实例或者您没有创建任何实例。它将由所有实例共享。

由于static方法也不属于特定的实例,因此不能引用实例成员。在给出的示例中,main不知道它应该引用的Hello类的哪个实例(因此也不知道它应该引用的Clock类的哪个实例)。static成员只能指static成员。实例成员当然可以访问static成员。

旁注:当然,static成员可以通过对象引用访问实例成员。

例子:

1
2
3
4
5
6
7
8
9
10
11
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]:根据运行时的特性,它可以是每个类加载器或AppDomain或线程一个,但这与点无关。


这意味着hello中只有一个"clock"实例,而不是"hello"类的每个单独实例都有一个实例,或者更多,这意味着"hello"类的所有实例中都将有一个共享的"clock"引用。

因此,如果您要在代码中的任何位置执行"新的你好"操作:A-在第一个场景中(在更改之前,不使用"static"),每次调用"new hello"时,它都会生成一个新的时钟,但是B-在第二个场景中(更改之后,使用"static"),每个"new hello"实例仍将共享并使用最初创建的相同"clock"引用。

除非你需要在主系统之外的某个地方"时钟",否则这也会起作用:

1
2
3
4
5
6
7
8
9
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允许您访问静态成员,就像它们是实例成员一样。

1
2
3
// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);

这使得它看起来好像sleep是一个实例方法,但实际上它是一个静态方法——它总是使当前线程休眠。最好在呼叫代码中说明这一点:

1
2
// Clearer
Thread.sleep(5000);


Java中的EDCOX1×0 }关键字意味着变量或函数在该类的所有实例之间共享,因为它属于类型,而不是实际对象本身。

因此,如果您有一个变量:private static int i = 0;,并且您在一个实例中增加了它(i++),那么这个变化将反映在所有实例中。i现在在所有情况下都是1。

静态方法可以在不实例化对象的情况下使用。


静态成员的基本用法…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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的情况下,如何在所有类成员中共享值的方法。而whit-static则不需要创建类实例。

1
2
Hello hello = new Hello();
hello.staticValue ="abc";

只需按类名调用静态值或方法:

1
Hello.staticValue ="abc";

静态意味着您不必创建类的实例来使用与类关联的方法或变量。在您的示例中,您可以调用:

1
Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class

直接,而不是:

1
2
Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the"h" variable

从静态方法(属于类)内部,您不能访问任何非静态成员,因为它们的值取决于类的实例化。作为实例成员的非静态时钟对象对于Hello类的每个实例都具有不同的值/引用,因此您无法从类的静态部分访问它。


Java中的静态:

静态是非访问修饰符。静态关键字属于类而不是类的实例。可用于将变量或方法附加到类。

静态关键字可用于:

方法

变量

嵌套在另一个类中的类

初始化块

不能用于:

类(不嵌套)

构造函数

界面

方法局部内部类(先差后嵌套类)

内部类方法

实例变量

局部变量

例子:

假设下面的示例有一个名为count的实例变量,该变量在构造函数中递增:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

由于实例变量在创建对象时获取内存,因此每个对象都将拥有实例变量的副本,如果实例变量递增,则不会反映到其他对象。

现在,如果我们将实例变量计数更改为静态的,那么程序将产生不同的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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的变量有时被称为常量。接口的所有字段都被称为常量,因为它们在默认情况下是最终的和静态的。

enter image description here

图片资源:最终静态


到目前为止,这个讨论忽略了类加载器的考虑。严格来说,Java静态字段在给定的类加载器的类的所有实例之间共享。


要添加到现有答案,让我尝试图片:

2%的利率适用于所有储蓄账户。因此它是静态的。

平衡应该是独立的,所以它不是静态的。

enter image description here


可以将字段分配给类或类的实例。默认情况下,字段是实例变量。通过使用static字段成为一个类变量,因此只有一个Clock。如果您在一个地方进行更改,它将随处可见。实例变量相互独立地进行更改。


在Java中,EDCOX1的0个关键字可以简单地被视为指示如下:

"without regard or relationship to any particular instance"

如果您以这种方式考虑static,那么在遇到它的各种上下文中更容易理解它的使用:

  • static字段是属于类而不是任何特定实例的字段。

  • static方法是一种没有this概念的方法;它是在类上定义的,除非传递一个引用,否则它不知道该类的任何特定实例。

  • static成员类是一个嵌套类,对其封闭类的实例没有任何概念或知识(除非传递了对封闭类实例的引用)。


静态使时钟成员成为类成员而不是实例成员。如果没有static关键字,则需要创建hello类的实例(该类有一个时钟成员变量),例如

1
2
Hello hello = new Hello();
hello.clock.sayTime();

关键字static用于表示属于类本身而不是实例的字段或方法。使用代码,如果对象Clock是静态的,那么Hello类的所有实例将共享这个Clock数据成员(字段)。如果将其设置为非静态的,则Hello的每个单独实例都可以有一个唯一的Clock字段。

问题是,您向类Hello添加了一个主方法,以便可以运行代码。这里的问题是,主要方法是静态的,因此,它不能引用非静态字段或其中的方法。您可以通过两种方式解决此问题:

  • 使Hello类的所有字段和方法都是静态的,以便在主方法中引用它们。这确实不是一件好事(或者错误的原因使字段和/或方法成为静态的)。
  • 在主方法内创建一个Hello类的实例,并按照最初的预期方式访问所有的字段和方法。
  • 对于您来说,这意味着对代码进行以下更改:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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();
        }
    }

    静态方法不使用在其中定义的类的任何实例变量。在这一页上可以找到一个很好的差异解释。


    我已经对"helper"类中的静态方法(只有在可能的情况下)产生了兴趣。

    调用类不需要创建助手类的另一个成员(实例)变量。您只需调用helper类的方法。另外,帮助器类也得到了改进,因为您不再需要构造函数,也不需要成员(实例)变量。

    可能还有其他优势。


    理解静态概念

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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 */

        }
    }

    第二课堂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class StaticPractise2 {
        public static void printUddhavsStatic1() {
            System.out.println("Uddhav");
        }

        public void printUddhav() {
            System.out.println("Uddhav");
        }
    }

    还可以考虑没有"this"指针的静态成员。它们在所有实例之间共享。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //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
        }
    }

    main()是一种静态方法,有两个基本限制:

  • 静态方法不能使用非静态数据成员或直接调用非静态方法。
  • this()super()不能在静态上下文中使用。

    1
    2
    3
    4
    5
    6
    class A {  
        int a = 40; //non static
        public static void main(String args[]) {  
            System.out.println(a);  
        }  
    }
  • Output: Compile Time Error


    静态变量只能在静态方法中访问,所以当我们声明静态变量时,getter和setter方法将是静态方法。

    静态方法是我们可以使用类名访问的类级别

    下面是静态变量getter和setter的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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;
        }

    }

    When run some project firstly load static things(variables, methods, blocks..).

    运行此项目时,首先加载主方法。因为它的static method。然后它看起来像对象"a" object,但对象a还没有定义。因为它是非静态的。然后像这个错误一样出现。