### 3.7 static关键字
---
Java提供了一个称为`static`的关键字,用于修饰类的成员,如成员变量、成员方法和代码块。使用`static`修饰的成员拥有特殊性。
---
#### 3.7.1 静态属性
当属性被`static`关键字修饰时,该属性称为**静态属性**(又称全局属性)。不同于普通属性,静态属性属于类而不是对象,因此可以直接使用类名进行访问:
**访问格式**:
```java
类名.属性名
```
**例子**:
在`Example13.java`中,Student类有三个属性:`name`、`age`和`school`,其中`school`是一个普通属性。即使`stu1`对象的`school`属性值被修改为"B大学",其他对象的`school`属性值并不受影响。
为了使所有对象共享同一个学校名称,且当其中一个对象的学校名称发生改变时,其他所有对象的学校名称都能随之改变,我们可以将`school`属性声明为静态属性。
在`Example14.java`中,`school`属性已经被声明为静态属性。因此,当`stu1`对象的`school`属性值被修改后,所有对象的`school`属性值都被修改。
---
#### 重点结论:
1. 静态属性是类级别的,所有的实例对象共享同一个静态属性。
2. 静态属性可以直接使用类名进行访问,无需实例化对象。
3. 修改某个对象的静态属性值会影响所有其他对象的相应静态属性值。
4. 静态属性在程序启动时创建,程序结束时销毁。
---
#### 使用场景:
当某个属性需要被类的所有对象共享,并且当其中一个对象修改了这个属性的值时,希望其他所有对象的这个属性值都能随之改变时,可以使用静态属性。
---
#### 注意事项:
- 由于静态属性不依赖于任何对象,因此可以在没有创建对象的情况下访问。
- 静态属性在内存中只有一个副本,这可以帮助节省内存。
- 非静态成员不能直接访问静态成员,但静态成员可以访问非静态成员。
---
这一节的内容主要介绍了静态属性的定义、特点和使用方法。在实际编程中,静态属性经常用于存储那些与类的所有对象相关的信息,如公司名称、版本号等。
### 3.7.2 静态方法
**静态属性**
首先需要了解,当一个属性被`static`关键字修饰时,这个属性就成为了静态属性,它属于整个类而不是某个具体的对象实例。这意味着所有的对象实例共享同一个静态属性。这可以通过图3-19的示例来证实,当我们修改了`stu1`对象的`school`属性后,`stu2`和`stu3`的`school`属性也随之发生了变化。这是因为它们都引用了同一块内存空间。
**图3-20的内存分配**
从图中可以看出,当我们修改一个对象的静态属性值时,其他所有对象的这个静态属性值都会被修改,因为它们在内存中的位置是共享的。
**关于static关键字**
- `static`关键字不能修饰局部变量,它只能修饰成员变量。如果尝试修饰局部变量,编译器会报错。
**静态方法**
在日常开发中,有时候我们希望能够在不创建对象的情况下,直接通过类名调用某个方法,此时就需要使用静态方法。要创建一个静态方法,只需要在方法声明前添加`static`关键字。
静态方法可以通过以下两种方式来访问:
1. 类名.方法
2. 实例对象名.方法
**例子:** 文件3-15展示了一个简单的例子,其中`Student`类有一个静态属性`school`和两个静态方法`getSchool()`和`setSchool()`. 在`main`函数中,我们可以看到在不创建任何对象的情况下,通过`Student`类名直接调用`setSchool()`方法来修改静态属性`school`的值。
**注意事项**
静态方法只能访问静态成员。非静态成员需要先创建对象才能访问。这是因为,只有当对象被创建时,非静态成员才会在内存中被分配。而静态方法在被调用时不需要创建任何对象。
**结论**
- 静态属性是类级别的,所有对象实例共享同一个静态属性值。
- 静态方法可以在不创建对象的情况下被调用。
- 在静态方法内,只能直接访问静态成员,非静态成员需要通过对象来访问。
### 3.7.3 静态代码块
**定义**:
静态代码块是使用`static`关键字修饰的代码块。它会在类被加载时执行,由于类只被加载一次,所以静态代码块也只会执行一次。通常情况下,静态代码块用于对类的成员变量进行初始化。
**示例**:
在文件3-16中,我们可以看到一个简单的例子。其中第3~5行是一个构造代码块,第6~8行是一个静态代码块。而第15~17行实例化了三个Student对象。
**执行顺序**:
当运行文件3-16时,我们可以从图3-22的输出结果看到,代码块的执行顺序是:静态代码块 → 构造代码块 → 构造方法。其中,`static`修饰的代码块是优先级最高的,它会随着class文件一同加载。
**特点**:
- 从文件3-16的输出结果中,我们可以明显看到,尽管我们实例化了三个Student对象,但静态代码块中的内容只输出了一次。这正是因为静态代码块只在类第一次被使用时加载,并且只会被加载一次。
### 3.8 本章小结
本章深入讨论了面向对象的基本知识,主要涵盖了以下内容:
1. 面向对象的核心思想。
2. 类与对象的关系,包括:
- 类的定义。
- 对象的创建与使用。
- 对象的引用传递。
- 访问控制。
3. 类的封装原理及其实现。
4. 构造方法的定义与重载。
5. `this`关键字的使用。
6. 代码块与`static`关键字的使用。
通过本章的学习,读者应能够对Java中面向对象的思想有初步的认识,为后续章节的学习打下坚实的基础。理解面向对象的核心思想对实际开发非常关键。
### 3.7 `static`关键字总结
**重点**:
1. **定义与作用**:
- `static`是一个关键字,用于声明静态成员(属性或方法)。
- 静态成员属于类,而不是对象,所以它们可以在没有创建类的对象的情况下被访问。
2. **静态变量**:
- 共享性:所有对象共享同一份静态变量,修改其中一个对象的静态变量,其他对象的静态变量值也会发生变化。
- 生命周期:静态变量随类的加载而加载,存在于全局数据区。
3. **静态方法**:
- 只能访问静态成员,不能访问非静态成员。
- 通过类名或对象来访问。
4. **静态代码块**:
- 在类被加载时执行,且只执行一次。
- 通常用于对静态成员变量进行初始化。
**难点**:
1. **与非静态成员的区别**:
- 静态成员是属于类的,而非静态成员属于对象。
- 静态方法中不能直接访问非静态成员,因为非静态成员需要对象的存在。
2. **生命周期和存储区域**:
- 静态成员的生命周期从类加载到类卸载,而非静态成员随对象的创建而存在,随对象的消失而消失。
- 静态变量存放在全局数据区,非静态变量存放在堆内存。
**易错点**:
1. **误用静态方法**:
- 在静态方法中尝试直接访问非静态成员会导致编译错误。
2. **静态变量误解**:
- 误以为不同对象的静态变量是独立的,实际上所有对象共享同一静态变量。
3. **局部变量使用`static`**:
- `static`关键字不能修饰局部变量,这是一个常见的编码错误。
4. **执行时机误区**:
- 误以为静态代码块每次创建对象时都会执行,实际上静态代码块只在类被加载时执行一次。