什么'静态'关键字做一个类?

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

package hello;


public class Hello {


Clock clock = new Clock();


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

但是它给出了错误

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

因此,我将clock的声明改为:

static Clock clock = new Clock();

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

837212 次浏览

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

[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,该字段成为一个类变量,因此有且只有一个clock。如果你在一个地方做了改动,它就会随处可见。实例变量的改变是彼此独立的。

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

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

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

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

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

static关键字意味着某些东西(字段、方法或嵌套类)与类型相关,而不是该类型的任何特定实例。例如,调用Math.sin(...)时没有任何Math类的实例,实际上你不能创建了一个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中添加了一个主要方法,这样你就可以运行代码了。这样做的问题是主要方法是静态的,因此它不能引用其中的非静态字段或方法。你可以用两种方法来解决这个问题:

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

  1. 静态方法不能使用非静态数据成员,也不能直接调用非静态方法。
  2. this()super()不能在静态上下文中使用。

    class A {
    int a = 40; //non static
    public static void main(String args[]) {
    System.out.println(a);
    }
    }
    

Output: Compile Time Error

只能在静态方法中访问静态变量,因此当我们声明静态变量时,那些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,就更容易理解它在各种上下文中的用法:

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

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

  • static成员类是一个嵌套类,没有任何关于其外围类实例的概念或知识(除非将对外围类实例的引用传递给它)

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

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

余额应该是个人,所以它是静态的。

enter image description here

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

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

现在如果我们将实例变量计数更改为静态计数 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:

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

enter image description here

图片来源:最后一个静态

理解静态概念

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

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


这是由于关键字重用,从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”时,该方法就是静态的。

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

    静态方法相对于其他非静态方法属于类 使用类的实例调用的方法
  • 要调用静态方法,不需要类对象。
  • 类的静态数据成员可以被静态对象访问 方法。static方法甚至可以改变static的值 李数据成员。< / > 静态方法不能引用' this '或' super '成员。 即使静态方法试图引用它们,它也将是一个编译器 李错误。< / > 和静态数据一样,静态方法也可以调用其他静态数据 方法。静态方法不能引用非静态数据成员或 变量,也不能调用非静态方法

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