关于static关键字,我讲两句
1. 什么是 static
先用词典查一下意思:
在 java 语言中,static 是一个关键字,表示“静态的”。它可以用来修饰变量、方法、代码块等。
static 修饰的变量叫静态变量,修饰的方法叫静态方法,修饰的代码块叫静态代码块。
在 java 中凡是被 static 修饰的东西都跟类有关
,跟对象没一毛钱关系,不需要对象的参与。
被 static 修饰的东西可以直接用 类名.
进行访问。
2. 为什么要用 static
先看一个例子:
- 新建诗人类
//诗人类
public class Poet {
// 姓名
private String name;
// 年龄
private int age;
// 朝代
private String dynasty;
public Poet(String name, int age, String dynasty) {
this.name = name;
this.age = age;
this.dynasty = dynasty;
}
@Override
public String toString() {
return "姓名:" + this.name + ", 年龄:" + age + ", 朝代:" + dynasty;
}
}
- 测试
// 静态方法测试
public class StaticTest {
public static void main(String[] args) {
Poet poet1 = new Poet("李白",61,"唐朝");
Poet poet2 = new Poet("杜甫",50,"唐朝");
System.out.println(poet1.toString());
System.out.println(poet2.toString());
}
}
- 运行结果:
结果分析:
上面的例子中我们新建了两个诗人对象:李白和杜甫,他们都是唐朝伟大的诗人。
java 程序运行时, JVM 内存图中是这样展示的:
我们知道李白和杜甫所处的朝代都是唐朝,如果再创建白居易、杜牧、孟浩然等一堆诗人对象,我们是不是还要在堆里面为他们各自开辟个内存,用来存储朝代信息? 这样是不是太浪费内存了?
String dynasty = "唐朝";
所以 static 的出现,可以帮助我们处理数据共享的问题。
3. static 的几种用法
3.1 静态变量
3.1.1 变量分类
在 java 中变量分为局部变量和成员变量。
局部变量在方法体中定义,例如:
public void eat(){
String food = "苹果";
System.out.println(food);
}
成员变量又分为实例变量和静态变量,例如:
//诗人类
public class Poet {
// 实例变量:姓名
private String name;
// 实例变量:年龄
private int age;
// 静态变量:朝代
static String dynasty;
}
3.1.2 静态变量
被 static 修饰的变量叫做静态变量,没有被 static 修饰的变量叫做实例变量。
要想访问实例变量必须先创建对象,然后通过对象.变量名
访问。因为实例变量对每个对象来说都是独一无二的,比如诗人对象的姓名、年龄等。
访问静态变量不需要创建对象,可以通过类名.变量名
访问,例如:
//诗人类
public class Poet {
// 实例变量:姓名
private String name;
// 实例变量:年龄
private int age;
// 静态变量:朝代
static String dynasty = "唐朝";
}
// static测试类
public class StaticTest {
public static void main(String[] args) {
System.out.println(Poet.dynasty);
}
}
运行结果:
我们都知道实例变量存储在堆内存中,通过调用构造方法进行初始化,例如:
而静态变量存储在方法区中,在类加载时初始化。静态变量在 JVM 内存图中是这样的:
所以当一个类中所有对象的某一些属性值一样的时候,我们可以设置成静态变量,从而实现数据共享。
总结:
-
- 静态变量存在于JVM的方法区中
-
- 静态变量可以通过
类名.变量名
访问,和对象无关
- 静态变量可以通过
-
- 当类中对象的一些属性值一样的时候(不会随着对象的改变而改变),我们可以设置成静态的。
3.2 静态代码块
3.2.1 定义静态代码块
语法格式:
类{
// 静态代码块
static{
代码
}
}
例如:
public class StaticTest {
static {
System.out.println("李白和杜甫是我国伟大的诗人,李白比杜甫大11岁");
}
public static void main(String[] args) {
System.out.println("哈哈哈哈");
}
}
运行结果:
静态代码块在类加载时执行,并且只执行一次。也就是说只要类一加载,这玩意就出来了。
所以上面的例子会先打印静态代码块中的数据。
3.2.2 多个静态代码块
一个类中可以编写多个静态代码块,他们按照从上到下的顺序去执行,例如:
public class StaticTest {
static {
System.out.println("床前明月光");
}
static {
System.out.println("疑是地上霜");
}
static {
System.out.println("举头望明月");
}
static {
System.out.println("低头思故乡");
}
public static void main(String[] args) {
System.out.println("李白代表作《静夜思》");
}
}
运行结果:
3.2.3 静态代码块使用场景
因为静态代码块在类加载时执行,并且只执行一次,所以我们可以在初始化一些数据的时候使用静态代码块。例如:
-
- 给对象的属性初始化
-
- jdbc 加载驱动
3.3 静态方法
3.3.1 语法格式
static 修饰的方法叫做静态方法。 语法格式:
修饰符 static 返回值 方法名(){
}
例如:
public class StaticTest {
public static void eat(){
System.out.println("-----");
}
}
3.3.2 使用场景
因为静态方法随着类的加载而加载,跟对象无关,所以我们可以把一些通用的辅助功能定义成静态方法。
例如我们在写工具类的时候就可以使用静态方法:
// 计算工具类
public class ComputeUtil {
public static int add(int a, int b) {
return a + b;
}
public static int sub(int a, int b) {
return a - b;
}
public static void main(String[] args) {
int addResult = ComputeUtil.add(1, 2);
System.out.println("两数相加结果:"+addResult);
int subResult = ComputeUtil.sub(10, 2);
System.out.println("两数相减结果:"+subResult);
}
}
运行结果:
4. 关于 static 的几个小问题
4.1 静态方法中可以使用 this 关键字吗?例如:
//诗人类
public class Poet {
// 实例变量:姓名
private String name;
// 静态变量:朝代
static String dynasty = "唐朝";
static void initName(){
this.name = "李白";
}
}
回答:不可以。静态代码随着类的加载而加载,this 表示当前对象,因为类加载的时候还没创建对象呢,所以不能用。
4.2 静态方法可以使用静态变量吗?例如:
//诗人类
public class Poet {
// 实例变量:姓名
private String name;
// 静态变量:朝代
static String dynasty ;
static void init(){
dynasty = "唐朝";
}
}
回答:可以,因为他俩都是随着类的加载而加载。
4.3 静态方法可以调用非静态方法吗?例如:
public class Poet {
static void init(){
write();
}
void write(){
System.out.println("写首诗");
}
}
回答:不可以。静态方法是属于类的,即静态方法是随着类的加载而加载的,在加载类时,程序就会为静态方法分配内存。非静态方法是属于对象的,对象是在类加载之后创建的,也就是说静态方法先于对象存在,这时候还没有创建对象,所以不能。
4.4 静态方法可以使用非静态变量吗?例如:
//诗人类
public class Poet {
// 姓名
private String name;
static void init(){
name = "李白";
}
}
回答:不可以。因为非静态变量是实例变量,只有创建对象之后才能使用。而静态方法随着类的加载而加载,这时候还没有创建对象,所以不能。
4.5 非静态方法可以使用静态变量吗?例如:
//诗人类
public class Poet {
// 姓名
static String name;
void init(){
name = "李白";
}
}
回答:可以。因为先有静态变量,后有非静态方法。后面出来的肯定可以访问前面出来的。
4.6 非静态方法可以调用静态方法吗?
回答:可以。同上。
总结:static 是属于类级别的,随着类的加载而加载,先于对象相关的东西出现。
转载自:https://juejin.cn/post/7036676587672043528