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

package hello;

public class Hello {

    Clock clock = new Clock();

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

但是它给出了错误

不能访问静态方法主中的非静态字段

所以我把时钟的声明改为这样:

static Clock clock = new Clock();

这招奏效了。将该关键字放在声明之前意味着什么?它究竟会做什么和/或限制可以对该对象做什么?


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

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

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

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

例子:

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.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

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


这意味着在Hello中只有一个“clock”实例,而不是每个“Hello”类的单独实例都有一个,或者更多——因此,这意味着在“Hello”类的所有实例之间将有一个通用的共享“clock”引用。

因此,如果你在代码的任何地方做一个“new Hello”: A-在第一种情况下(在更改之前,不使用“static”),它会在每次调用“new Hello”时创建一个新的时钟,但是 B-在第二种情况下(在更改之后,使用“static”),每个“new Hello”实例仍然会共享和使用最初创建的初始和相同的“clock”引用。

除非你需要在main之外的某个地方使用“clock”,否则这样也可以:

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

Static使时钟成员成为类成员而不是实例成员。如果没有static关键字,你需要创建一个Hello类的实例(它有一个时钟成员变量)。

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

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


字段可以分配给类或类的实例。默认情况下,字段是实例变量。通过使用static,字段变成了类变量,因此有且只有一个时钟。如果你在一个地方做了改动,它就会随处可见。实例变量的改变是彼此独立的。


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


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


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

如果你有一个变量private static int i = 0;如果您在一个实例中增加它(i++),则更改将反映在所有实例中。I在所有情况下都是1。

静态方法可以不实例化对象而使用。


static关键字意味着某些东西(字段、方法或嵌套类)与类型相关,而不是与类型的任何特定实例相关。例如,在没有Math类实例的情况下调用Math.sin(…),实际上您无法创建Math类的实例。

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


旁注

不幸的是,Java允许你像访问实例成员一样访问静态成员。

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

这使它看起来好像sleep是一个实例方法,但实际上它是一个静态方法——它总是使当前线程休眠。更好的做法是在调用代码中清楚地说明这一点:

// Clearer
Thread.sleep(5000);

我喜欢在“助手”类中使用静态方法(如果可能的话)。

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

或许还有其他优势。


静态成员的基本用法…

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";

关键字static用于表示一个字段或方法属于类本身,而不属于任何特定的实例。使用您的代码,如果对象Clock是静态的,那么Hello类的所有实例将共同共享这个Clock数据成员(字段)。如果使它是非静态的,那么Hello的每个实例都将有一个唯一的Clock。

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

将Hello类的所有字段和方法设置为静态的,以便在主方法中引用它们。这不是一件好事(或者是将字段和/或方法设置为静态的错误原因) 在主方法中创建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();
    }
}

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

静态方法不能使用非静态数据成员,也不能直接调用非静态方法。 This()和super()不能在静态上下文中使用。 A类{ Int a = 40;/ /非静态 public static void main(String args[]) { System.out.println(一个); } }

输出:编译时错误


只能在静态方法中访问静态变量,因此当我们声明静态变量时,那些getter和setter方法将是静态方法

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

下面是静态变量Getters和Setters的例子:

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;
    }

}

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

“不考虑或与任何特定情况有关”

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

静态字段是属于类而不是任何特定实例的字段 静态方法是一种没有这种概念的方法;它在类上定义,并且不知道该类的任何特定实例,除非将引用传递给它 静态成员类是一个嵌套类,没有任何关于其外围类实例的概念或知识(除非将对外围类实例的引用传递给它)


为了补充现有的答案,让我试着用一张图片:

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

平衡应该是个体的,所以它不是静态的。


Java中的静态:

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

    }
}

输出:

1 1 1

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

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

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:

The global variable which is declared as final and static remains unchanged for the whole execution. Because, Static members are stored in the class memory and they are loaded only once in the whole execution. They are common to all objects of the class. If you declare static variables as final, any of the objects can’t change their value as it is final. Therefore, variables declared as final and static are sometimes referred to as Constants. All fields of interfaces are referred as constants, because they are final and static by default.

图片来源:最终静态


理解静态概念

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");
    }
}

//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
    }
}

这里有一个问题是关于这个概念中“静态”一词的选择。这个问题已经解决了,但我认为词源问题还没有明确解决。所以…


这是由于关键字重用,从C开始。

考虑C语言中的数据声明(在函数体中):

    void f() {
        int foo = 1;
        static int bar = 2;
         :
    }

变量foo在输入函数时在堆栈上创建(并在函数终止时销毁)。相比之下,bar总是在那里,所以在普通英语中它是“静态的”——它不会去任何地方。

Java和类似的语言对数据有相同的概念。数据可以为类的每个实例(每个对象)分配,也可以为整个类分配一次。因为Java的目标是为C/ c++程序员提供熟悉的语法,所以这里使用“static”关键字是合适的。

    class C {
        int foo = 1;
        static int bar = 2;
         :
    }

最后,我们来谈谈方法。

    class C {
        int foo() { ... }
        static int bar() { ... }
         :
    }

从概念上讲,类c的每个实例都有一个foo()实例,整个类c只有一个bar()实例。这与我们讨论的数据的情况类似,因此使用'static'也是一个明智的选择,特别是如果你不想在你的语言中添加更多保留的关键字。


Java程序中的成员可以在其声明/定义之前使用关键字“static”声明为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”时,该方法就是静态的。

关于静态方法,你需要记住的要点包括:

A static method belongs to the class as against other non-static methods that are invoked using the instance of a class. To invoke a static method, you don’t need a class object. The static data members of the class are accessible to the static method. The static method can even change the values of the static data member. A static method cannot have a reference to ‘this’ or ‘super’ members. Even if a static method tries to refer them, it will be a compiler error. Just like static data, the static method can also call other static methods. A static method cannot refer to non-static data members or variables and cannot call non-static methods too.

下面的程序显示了静态方法在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中的静态块

就像在c++、c#等编程语言中有函数块一样,在Java中也有一个特殊的块,称为“静态”块,通常包括与静态数据相关的代码块。

这个静态块在创建类的第一个对象时(准确地说是在类加载时)或在块内的静态成员被使用时执行。

下面的程序展示了静态块的用法。

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中,可以将一个类放在另一个类中,这被称为嵌套类。包含嵌套类的类称为外层类。

在Java中,虽然可以将嵌套类声明为Static,但不能将外部类声明为Static。

现在让我们研究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

我认为这就是静态关键字在java中的工作方式。