1. static keyword
It turns out that for member variables in a class, every new object has its own member variable, because these member variables are not static member variables. For static member variables, there is only one copy of this member variable, and this copy is shared by all objects of this class.
1.1. The difference between static member variables and non-static member variables
Take the following example as an example
package cn.galc.test; public class Cat { /** * 静态成员变量 */ private static int sid = 0; private String name; int id; Cat(String name) { this.name = name; id = sid++; } public void info() { System.out.println("My Name is " + name + ",NO." + id); } public static void main(String[] args) { Cat.sid = 100; Cat mimi = new Cat("mimi"); Cat pipi = new Cat("pipi"); mimi.info(); pipi.info(); } }
Understand the execution process of the entire program by drawing a memory analysis diagram
When executing the first sentence of the program: Cat.sid = 100;, the sid here is a static member variable. The static variable is stored in the data area (data seg), so first allocate a small space in the data area. sid, after the first sentence is executed, there is a value in sid, which is 100.
The memory layout diagram at this time is as follows
The next step is to execute the program to:
Cat mimi = new Cat(“mimi”);
Here, the constructor Cat(String name) of the Cat class is called. The constructor method is defined as follows:
Cat (String name){
this.name = name;
id=sid ;
}
When calling, first allocate a small piece of memory mm in the stack memory, which contains the address of the instance object of the Cat class in the heap memory. mm is the reference object of the Cat class object in the heap memory. This constructor declares a formal parameter variable of string type, so "mimi" is passed to the constructor as an actual parameter. Since the string constant is allocated and stored in the data area, there is a small amount of memory in the data area. Used to store the string "mimi". The memory distribution at this time is as shown below:
When the constructor is called, first allocate a small space in the stack memory for the formal parameter name. The name is name. Then the string "mimi" is passed to name as an actual parameter. The string is also a reference. Type, except for the four and eight basic data types, all others are reference types, so it can be considered that a string is also an object. So this is equivalent to passing the reference of the "mimi" object to name, so now name points to "mimi". So the memory layout at this time is as shown below:
Next execute the code in the constructor body:
this.name=name;
This here refers to the current object, which refers to the cat in the heap memory. Here, the value contained in the name in the stack is passed to the name attribute of the cat object in the heap memory, so the value contained in the name can also be found in the string object "mimi" located in the data area. At this time, this name is also a reference object of the string object "mimi". Through its attribute value, the string object "mimi" located in the data area can be found. The memory distribution at this time is as shown below:
Next, execute another line of code in the method body: id=sid;
Here the value of sid is passed to id, so the value of id is 100. After the sid is passed, add 1 yourself, and sid becomes 101. The memory layout at this time is shown in the figure below.
At this point, the constructor method is called, and all the memory space occupied by the local variables allocated to this constructor method will disappear, so the name memory located in the stack space disappears. The reference to the string object "mimi" in the data area in the stack memory also disappears. At this time, only the reference to the string object "mimi" in the heap memory remains. The memory layout at this time is as shown below:
Next execution: Cat pipi = new Cat(“pipi”);
Here is the second call to the constructor method Cat(). The entire calling process is the same as the first time. After the call is completed, the memory layout at this time is as shown below:
最后两句代码是调用info()方法打印出来,打印结果如下:
通过这个程序,看出来了这个静态成员变量sid的作用,它可以计数。每当有一只猫new出来的时候,就给它记一个数。让它自己往上加1。
程序执行完后,内存中的整个布局就如上图所示了。一直持续到main方法调用完成的前一刻。
这里调用构造方法Cat(String name) 创建出两只猫,首先在栈内存里面分配两小块空间mimi和pipi,里面分别装着可以找到这两只猫的地址,mimi和pipi对应着堆内存里面的两只猫的引用。这里的构造方法声明有字符串类型的变量,字符串常量是分配在数据区里面的,所以这里会把传过来的字符串mimi和pipi都存储到数据区里面。所以数据区里面分配有存储字符串mimi和pipi的两小块内存,里面装着字符串“mimi”和“pipi”,字符串也是引用类型,除了那四类8种的基础数据类型之外,其他所有的数据类型都是引用类型。所以可以认为字符串也是一个对象。
这里是new了两只猫出来,这两只猫都有自己的id和name属性,所以这里的id和name都是非静态成员变量,即没有static修饰。所以每new出一只新猫,这只新猫都有属于它自己的id和name,即非静态成员变量id和name是每一个对象都有单独的一份。但对于静态成员变量来说,只有一份,不管new了多少个对象,哪怕不new对象,静态成员变量在数据区也会保留一份。如这里的sid一样,sid存放在数据区,无论new出来了多少只猫在堆内存里面,sid都只有一份,只在数据区保留一份。
静态成员变量是属于整个类的,它不属于专门的某个对象。那么如何访问这个静态成员变量的值呢?首先第一点,任何一个对象都可以访问这个静态的值,访问的时候访问的都是同一块内存。第二点,即便是没有对象也可以访问这个静态的值,通过“类名.静态成员变量名”来访问这个静态的值,所以以后看到某一个类名加上“.”再加上后面有一个东西,那么后面这个东西一定是静态的,如”System.out”,这里就是通过类名(System类)再加上“.”来访问这个out的,所以这个out一定是静态的。
再看下面的这段代码
package cn.galc.test; public class Cat { /** * 这里面的sid不再是静态成员变量了,因为没有static修饰符, * 此时它就是类里面一个普通的非静态成员变量,和id,name一样, * 成为每一个new出来的对象都具有的属性。 */ private int sid = 0; private String name; int id; Cat(String name) { this.name = name; id = sid++; } public void info() { System.out.println("My Name is " + name + ",NO." + id); } public static void main(String[] args) { //Cat.sid = 100;这里不能再使用“类.静态成员变量”的格式来访问sid了,因为sid现在变成了非静态的成员变量了。所以必须要把这句话注释掉,否则无法编译通过。 Cat mimi = new Cat("mimi"); Cat pipi = new Cat("pipi"); mimi.info(); pipi.info(); } }
The only difference between this code and the previous code is that the static modifier of the sid variable is removed. At this time, sid is no longer a static member variable, but a non-static member variable. At this time, each The cat objects produced by new will have their own separate sid attributes. So after this code is executed, the layout in the memory is as shown below:
Since sid has become a non-static member variable, it no longer has the counting function. Like the id and name attributes, sid becomes an attribute that every new object has, so every new cat has a sid attribute added to it. Since the sid can no longer be accessed in the format of "class name. static member object name", the first sentence of the code "Cat.sid =100;" cannot be used in this way, otherwise a compilation error will occur. This sentence must be commented out to compile. success. Since the value of sid cannot be accessed, the value of sid is always the value 0 assigned during initialization. Until the constructor is called and the code id=sid in the method body is executed, sid first assigns its own value of 0 to id, so the value of id is 0, and then sid adds 1 to itself, so sid becomes 1.
So the difference between static variables and non-static variables is that static variables can be used for counting, but non-static variables cannot.
If you understand memory, you understand everything, and you understand various languages. All languages are nothing more than this: the memory allocated for local variables is always on the stack, the memory allocated for new things is always on the heap, and the memory allocated for static things is always in the data area. The rest of the code must be in the code area. All languages are like this.
In a static method, if you want to access a non-static member variable, you cannot access it directly. You must create a new object in the static method to access it. If a static member variable is added, then this member variable is a static member variable and can be accessed directly in the main method.
The main method is a static method. When the main method is to be executed, there is no need to create a new object.
Dynamic methods are called for a certain object, while static methods are not called for a certain object. They can still be used without an object. So you can use the form of "classname.method()" to call static methods. Therefore, it is not possible to access non-static member variables in the main method. It is also impossible to access non-static methods in the main method, because non-static methods can only be called for a certain object. If there is no object, it cannot be found. Now comes the executor of the method.
Member variables are only allocated storage space in the heap memory when an object is created by new. Local variables allocate storage space in stack memory.
Static methods are no longer called on a certain object, so non-static members cannot be accessed.
Non-static members are exclusive to a certain object. If you want to access non-static members, you must create a new object to access them.
Static variables can be accessed through object names or class names. Both access the same memory.
The above is the entire content of this article. There is a lot of information and you need to read it patiently to truly learn the java static keyword.