static静态标签

static静态变量

我们都知道在测试文件中都需要有:

1
public static void main(String[] args)

这段文字,而文字中public void main这几个我都已经数值,但是这个static是什么意思呢?今天我们来一起探讨一下这个词语。

属性静态调用

当我们遇到不同的成员需要有相同的属性的时候,为了方便同时输入和调用属性,我们引入了static(静态)修饰符:

user:

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
28
29
30
31
32
33
package com.bayeeaa.demo1.d9_static;

public class user {
private String name;
private int number;
public static String tea; //static修饰tea这个变量

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getNumber() {
return number;
}

public void setNumber(int number) {
this.number = number;
}

public user(String name, int number) {
this.name = name;
this.number = number;
}

public void say() {
System.out.println("hi");
}
}

test:

1
2
3
4
5
6
7
8
9
10
11
package com.bayeeaa.demo1.d9_static;

public class test {
public static void main(String[] args) {
user u1 = new user("bb",123);
user u2 = new user("ye",11);
user.tea = "black tea"; //直接对类进行调取
System.out.println(u2.tea); //black tea
System.out.println(u1.tea); //black tea
}
}

我们可以看到当我们给tea用static修饰了之后,在test文件中我们就可以直接用类来进行赋值而不需要用成员来赋值,并且赋值后每个成员所访问的值都是一样的。被static所修饰的成员变量叫做静态变量,它有这三个特点:

  • 被该类所有对象共享
  • 不属于对象,属于类
  • 随着类的加载而加载,优先于对象的存在

当然被static修饰的成员方法,叫做静态方法,它有这些特点:

  • 多用在测试类和工具类中
  • Javabean类中很少会用到

这里我们就可以讨论到工具类的创建。

工具类创建

创建一个工具类,首先我们要将其私有化,这样外部就不会创建这个类的对象了(因为我们这个要让这个类作为工具,那我们就要写死在这里了,不能再让别人有所操作,不然工具变化会带来不便):

1
2
3
public class ArrUtil {
private arrUtil(){}
}

我们写一个工具类的例子:

ArrUtil:

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
package com.bayeeaa.demo1.d9_static;

import java.util.ArrayList; //集合list

public class ArrUtil {
private ArrUtil(){}; //工具类私有化

//设置为静态方便调用
public static int get_sum(int[] arr){ //计算数组所有数据和
int sum=0;
for (int i = 0; i < arr.length; i++) {
sum = sum + arr[i];
}
return sum;
}

public static int get_num_sum(ArrayList<user> list){ //计算集合中所有对象的num属性和
int sum = 0;
for (int i = 0; i < list.size(); i++) {
sum = sum + list.get(i).getNumber();
}
return sum;
}
}

test:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.bayeeaa.demo1.d9_static;

import java.util.ArrayList;

public class test {
public static void main(String[] args) {

int[] a = {1,2,3,4,5,6};
System.out.println(ArrUtil.get_sum(a)); //输出数组的数字和

ArrayList<user> list = new ArrayList<>(); //这是个集合
user u1 = new user("ye",1);
user u2 = new user("yee",2);
user u3 = new user("yeee",12);

list.add(u1); //对象压入集合
list.add(u2);
list.add(u3);

System.out.println(ArrUtil.get_num_sum(list)); //输出集合中num的和

}
}

可以看到可以直接通过 类名.方法名() 来调用工具。

this关键字

其实,static有这几个注意事项:

  • 静态方法中,只能访问静态
  • 非静态方法可以访问所有
  • 静态方法中没有this关键字

而这几个关键都和this关键字有关。以下我来举一些例子。

test:

1
2
3
4
5
6
7
8
9
10
11
package com.bayeeaa.demo1.d9_static;

import java.util.ArrayList;

public class test {
public static void main(String[] args) {
methods_class pj = new methods_class();
pj.repeat();

}
}

methods_class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.bayeeaa.demo1.d9_static;

public class methods_class {

String s;

public void repeat(methods_class this){
System.out.println(this); //输出com.bayeeaa.demo1.d9_static.methods_class@b4c966a
}

public static void again(){
System.out.println(this); //飘红,静态方法中没有this
}
}

我在methods_class文件中输出了两个方法,一个是非静态方法,一个是静态方法,当我们分别用test文件来打印的时候会发现第一个repeat方法打印出了对象的地址,而第二个again方法会报错。

Build Output

在我们平时使用非静态方法应该是不会在非静态方法中手动调入methods_class this这个值的,但是我们却可以直接用方法调用,这是因为在非静态方法中是默认包括this的,而this的赋值又由jvm调取。所以说在非静态方法中如果我们要调用参数,比如num,实际上应该是这样的:

1
2
3
public void repeat(methods_class this){
System.out.println(this.s);
}

但是通过上图的报错我们可以看到静态方法中是没有this的。因此在其中要是强行引入this会导致报错。

有了这样的解释就可以理解上面的三个结论了。

内存解释

在作内存解释之前我们要知道:

栈内存(Stack Memory)
  1. 结构和管理方式
    • 栈内存按照先进后出的原则进行管理(LIFO,即 Last In, First Out)。
    • 内存分配和回收由系统自动管理。每当一个函数被调用时,系统会在栈上为其分配内存,函数返回时,这部分内存会被自动释放。
  2. 用途
    • 用于存储局部变量、函数调用参数和返回地址等。
    • 栈内存的管理非常高效,因为内存分配和释放的操作非常简单,只需调整栈顶指针即可。
  3. 特点
    • 内存分配速度快。
    • 栈内存的大小通常较小,固定大小,超过限制会导致栈溢出(stack overflow)。
    • 数据的生命周期由函数调用的生命周期决定,一旦函数返回,栈内存中的数据就会失效。

堆内存(Heap Memory)

  1. 结构和管理方式
    • 堆内存没有固定的管理顺序,分配和释放内存是由程序员或垃圾回收机制管理的。
    • 内存的分配和释放可以发生在程序的任何地方,不像栈内存那样有固定的顺序。
  2. 用途
    • 用于动态分配内存,比如创建对象、数组等,需要程序员显式地请求内存空间。
    • 适用于需要在多个函数调用间共享数据的情况。
  3. 特点
    • 内存分配和释放相对较慢,因为涉及到更复杂的管理机制。
    • 堆内存的大小通常较大,由操作系统和系统配置决定。
    • 需要程序员显式管理内存,未正确释放的内存会导致内存泄漏(memory leak),一些语言如 Java 和 Python 使用垃圾回收机制来自动处理这一问题。

总结

  • 栈内存适用于存储生命周期短、大小固定的数据,管理简单且高效。
  • 堆内存适用于存储生命周期长或大小不确定的数据,管理复杂但灵活。

我们可以简单的将内存划为三个区域:

内存解释

字节文件加载:引入main文件,加载里面的方法、类文件中的属性、静态属性等等。

然后开始创建对象,在堆内存中开辟一块地,并返回其地址给对象pj。

然后pj就可以根据地址去寻找所要找的元素。

main的解释

现在我们再来看下我们每次的入口文件:

1
public static void main(String[] args)
  • public: 被JVM调用,访问权限足够大
  • static:被JVM调用,不用创建对象,直接类名访问。因为main方法是静态的,所以测试类中其他方法也需要是静态的。(这里注意下,不是静态的叫实例变量,非static方法需要new一个实例出来才能使用,这里意思是main默认只能调用静态方法,实例要new)
  • void:被JVM调用,不需要给JVM返回值
  • main:一个通用的名称,虽然不是关键字,但是被JVM识别
  • String[] args:以前用于接收键盘录入数据的,现在没有,被保留是为了上下版本兼容

static静态标签
https://bayeeaa.github.io/2024/08/14/static静态标签/
Author
Ye
Posted on
August 14, 2024
Licensed under