'static'关键字在一个类中做什么?

Cli*_*ote 432 java oop static language-features restriction

具体来说,我正在尝试这段代码:

package hello;

public class Hello {

    Clock clock = new Clock();

    public static void main(String args[]) {
        clock.sayTime();
    }
}
Run Code Online (Sandbox Code Playgroud)

但它给出了错误

无法访问静态方法main中的非静态字段

所以我把声明改为clock:

static Clock clock = new Clock();
Run Code Online (Sandbox Code Playgroud)

它奏效了.在声明之前放置该关键字是什么意思?对于该对象可以做什么,它究竟会做什么和/或限制什么?

Meh*_*ari 616

static 成员属于类而不是特定实例.

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

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

附注:当然,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;
    }
Run Code Online (Sandbox Code Playgroud)

[1]:根据运行时特性,它可以是每个ClassLoader或AppDomain或线程一个,但这不是重点.

  • 在.NET中,您还可以使用[ThreadStatic]属性修改此行为 - 这使得特定线程的静态本地化. (5认同)
  • 我知道这是老帖子,但对于像我这样的初学者来说这可能会有所帮助.http://stackoverflow.com/questions/7026507/why-are-static-variables-considered-evil (3认同)

Pau*_*lin 130

这意味着Hello中只有一个"clock"实例,而不是"Hello"类的每个单独实例中的一个实例,或者更多 - 这意味着在所有实例中都会有一个共同的"时钟"引用. "Hello"课程.

所以,如果你要在你的代码中的任何地方做一个"新的Hello":A-在第一个场景中(在更改之前,不使用"static"),每次调用"new Hello"时它会生成一个新的时钟,但是在第二个场景中B-(在更改之后,使用"静态"),每个"新的Hello"实例仍将共享并使用首先创建的初始和相同的"时钟"引用.

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

package hello;
public class Hello
{
    public static void main(String args[])
    {
      Clock clock=new Clock();
      clock.sayTime();    
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在第二个例子中,时钟静态,它只会创建一次.在我的例子中,时钟在主要内部,然后是,它会在每次调用main时创建它.但通常main只在程序启动时调用一次,当它退出时,一切都是免费的. (2认同)

Jon*_*eet 96

static关键字是指某物(字段,方法或嵌套类)是相关于类型,而不是任何特定的实例的类型.因此,例如,一个调用Math.sin(...)没有Math该类的任何实例,实际上您无法创建Math该类的实例.

有关更多信息,请参阅Oracle Java教程相关部分.


边注

遗憾的是, Java 允许您像访问实例成员一样访问静态成员,例如

// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);
Run Code Online (Sandbox Code Playgroud)

这使它看起来好像sleep是一个实例方法,但它实际上是一个静态方法 - 它总是使当前线程休眠.最好在调用代码中明确这一点:

// Clearer
Thread.sleep(5000);
Run Code Online (Sandbox Code Playgroud)


geo*_*wa4 41

staticJava中的关键字表示变量或函数在该类的所有实例之间共享,因为它属于类型,而不是实际的对象本身.

因此,如果您有一个变量:private static int i = 0;i++在一个实例中递增it(),则更改将反映在所有实例中.i在所有情况下现在都是1.

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

  • "在所有实例之间共享"给出了错误的印象,IMO - 它表明你*需要有一个对象的实例. (3认同)

Vas*_*hev 24

静态成员的基本用法......

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
}
Run Code Online (Sandbox Code Playgroud)

这就是如何在不向其他类发送类实例Hello的情况下在所有类成员中共享值.而whit static则不需要创建类实例.

Hello hello = new Hello();
hello.staticValue = "abc";
Run Code Online (Sandbox Code Playgroud)

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

Hello.staticValue = "abc";
Run Code Online (Sandbox Code Playgroud)


Eli*_*lie 21

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

Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class
Run Code Online (Sandbox Code Playgroud)

直接,而不是:

Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the "h" variable
Run Code Online (Sandbox Code Playgroud)

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


Vir*_*ual 20

Java中的静态:

Static是非访问修饰符.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();

    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

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();

    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

1 2 3

在这种情况下,静态变量只会获取一次内存,如果任何对象更改了静态变量的值,它将保留其值.

静态与最终:

声明为final和static的全局变量在整个执行过程中保持不变.因为,静态成员存储在类内存中,并且在整个执行过程中只加载一次.它们对于该类的所有对象都是通用的.如果将静态变量声明为final,则任何对象都不能更改它们的最终值.因此,声明为final和static的变量有时称为常量.接口的所有字段都称为常量,因为默认情况下它们是final和static.

在此输入图像描述

图片资源:最终静态


Jul*_*ang 13

到目前为止,此讨论忽略了类加载器的注意事项.严格地说,Java静态字段在给定类加载器的类的所有实例之间共享.

  • 这一切都是正确的,但它没有回答这个问题.它本应作为评论发布. (2认同)

And*_*ejs 13

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

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

平衡应该是个体的,因此它不是静态的.

在此输入图像描述


sbl*_*ndy 7

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


hfo*_*nez 6

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

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

  1. 使类的所有字段和方法都是Hello静态的,以便可以在main方法中引用它们.这真的不是一件好事(或者是使字段和/或方法静态的错误原因)
  2. Hello在main方法中创建一个类的实例,并按照它们最初的方式访问它的所有字段和方法.

对您而言,这意味着对您的代码进行以下更改:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)


sco*_*ttb 6

在Java中,static关键字可以简单地视为表示以下内容:

"不考虑或与任何特定实例的关系"

如果您static以这种方式思考,就会更容易理解它在遇到它的各种上下文中的用法:

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

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

  • static构件类是没有其外围类的一个实例的概念任何或知识嵌套类(除非到一个封闭类实例的引用传递给它)


Ste*_*yle 5

Static使clock成员成为类成员而不是实例成员.如果没有static关键字,则需要创建Hello类的实例(具有时钟成员变量) - 例如

Hello hello = new Hello();
hello.clock.sayTime();
Run Code Online (Sandbox Code Playgroud)


Mar*_*ski 5

静态方法不使用它们所定义的类的任何实例变量.可以在此页面上找到对差异的非常好的解释


小智 5

我已经开始喜欢"帮助"类中的静态方法(如果可能的话).

调用类不需要创建辅助类的另一个成员(实例)变量.您只需调用辅助类的方法即可.辅助类也得到了改进,因为您不再需要构造函数,并且您不需要成员(实例)变量.

可能还有其他优点.


小智 5

//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
    }
}
Run Code Online (Sandbox Code Playgroud)