final_static关键字的使用
final、static关键字的使用说明,主要是对使用static修饰的变量和方法的分析。static也可修饰类(内部类),被修饰的类叫静态内部类,这里不做说明。
Author: Msuenb
Date: 2023-02-10
final 关键字
final
的含义是最终的、不可更改的。它可以修饰变量、方法和类,各有其意义。
final 修饰变量
final
修饰某个变量(成员变量或局部变量),表示它的值不能被修改,称为常量。
注意:
- 常量名建议使用大写字母,如:
final double PI = 3.14
- 被
final
修饰的成员变量,没有set
方法,并且必须初始化(显示赋值、构造器中赋值、代码块中赋值),不能使用默认值。
class FinalVar {
final String name = "Tom"; // 显示赋值
final int age;
final double height;
final double weight;
{
age = 18; // 代码块中赋值
}
public FinalVar() {
height = 179.5; // 构造器中赋值
}
public FinalVar(double weight) {
this.weight = weight; // 构造器中赋值
}
public void setName(String name) {
//this.name = name; // 不可修改
}
}
通常成员常量都是用
public static final
修饰
final 修饰方法
final
修饰某个方法,表示这个方法不能被重写。
class Father {
public final void method() {
System.out.println("father");
}
}
class Son extends Father {
public final void method() { // final 方法不可重写
System.out.println("son");
}
}
final 修饰符类
final
修饰某个类,表示这个类不能被继承。
final class Father2 { }
class Son2 extends Father2 {} // Father2 不能被继承
static 关键字
在类中声明的示例变量,其值是每个对象独立的。有时需要与当前对象无关的成员变量、成员方法,此时就可以将这些成员声明为静态的(static
)。
静态变量
被static
关键字修饰的成员变量就是静态变量,也叫类变量。
【修饰符】 class 类{
【其他修饰符】 static 数据类型 静态变量名;
}
静态变量的特点:
- 静态变量的默认值规则和实例变量一样。父类的静态变量也可以被子类继承。
- 静态变量的值存储在方法区,为所有对象共享。
- 静态变量在本类任意位置都可以使用。权限修饰符允许的话,可以通过
类名.静态变量名
或对象名.静态变量名
(不推荐) 调用。 - 静态变量的
get/set
方法也是静态的。
静态变量使用演示:
public class StaticVarTest {
public static void main(String[] args) {
StaticVar staticVar = new StaticVar(); // 对象1
StaticVar staticVar2 = new StaticVar(); // 对象2
System.out.println(StaticVar.name); // null 可以通过 类名.静态变量 访问
System.out.println(staticVar.name); // null 通过 对象名.静态变量 访问 不推荐
System.out.println(staticVar2.name);// null
StaticVar.name = "Tom"; // 修改 name 的值
System.out.println(StaticVar.name); // Tom
System.out.println(staticVar.name); // Tom
System.out.println(staticVar2.name); // Tom 多个对象共享
StaticVar.setAge(18); // 只能通过 set/get 方法访问 age
System.out.println(StaticVar.getAge()); // 18
}
}
class StaticVar {
public static String name; // 可以通过 类名.静态变量 访问
private static int age; // 只能通过提供的get/set访问
public static String getName() {
return name;
}
public static void setName(String name) {
StaticVar.name = name;
}
public static int getAge() {
return age;
}
public static void setAge(int age) {
StaticVar.age = age;
}
}
静态变量内存分析:
public class Main {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
System.out.println(s1.job); // 学生
System.out.println(s2.job); // 学生
s1.job = "student"; // s1 和 s2 共享 job
System.out.println(s1.job); // student
System.out.println(s2.job); // student
}
}
class Student {
String name;
int age;
static String job = "学生";
}
静态变量、实例变量和局部变量:
- 静态变量:存储在方法区,有默认值,所有对象共享,生命周期和类相同,还可以有权限修饰符、final等其他修饰符
- 实例变量:存储在堆中,有默认值,每一个对象独立,生命周期每一个对象也独立,还可以有权限修饰符、final等其他修饰符
- 局部变量:存储在栈中,没有默认值,每一次方法调用都是独立的,有作用域,只能有final修饰,没有其他修饰符
静态方法
被static
关键字修饰的成员方法就是静态方法。当方法没有访问到任何非静态成员时可以用static
修饰。
【修饰符】 class 类{
【其他修饰符】 static 返回值类型 方法名(形参列表){
方法体
}
}
静态方法的特点:
- 静态方法在本类的任意方法、代码块、构造器中都可以直接被调用。
- 权限修饰符允许的话,可以通过
类名.静态方法名
或对象名.静态方法名
(不推荐) 调用。 - 静态方法可以被子类继承,但不能被子类重写。
- 静态方法的调用都只看编译时类型。
- 静态方法只能访问静态成员 ,不能访问非静态成员。
静态方法使用演示:
public class StaticMethodTest {
public static void main(String[] args) {
Son son = new Son();
Son.fun();
// son.fun(); // 不推荐
son.fun2();
}
}
class Father {
public static String a = "父类的静态变量";
public static void method() {
System.out.println("父类的静态方法");
}
}
class Son extends Father {
public String b = "子类的非静态变量";
{
fun1(); // 代码块中调用静态方法
System.out.println("代码块中调用静态方法");
}
public Son() {
fun1(); // 构造器中调用静态方法
System.out.println("构造器中调用静态方法");
}
//@Override //尝试重写静态方法,加上@Override编译报错,去掉Override不报错,但是也不是重写
//public static void method(){
// System.out.println("Son.fun");
//}
public static void fun() {
System.out.println("子类的静态方法");
// System.out.println(s); // 静态方法中不能访问非静态变量
// fun2(); // 静态方法中不能调用非静态方法
System.out.println(a); // 继承父类的静态变量
method(); // 继承父类的静态方法
}
public static void fun1() { }
public void fun2() {
System.out.println("子类的非静态方法");
fun1(); // 非静态方法可以访问静态成员
System.out.println("非静态方法可以访问静态成员");
}
}
静态导入
如果大量使用另一个类的静态成员,可以使用静态导入,简化代码。(了解)
import static 包.类名.静态成员名;
import static 包.类名.*;
演示:
import static java.lang.Math.*;
public class StaticImportTest {
public static void main(String[] args) {
//使用Math类的静态成员
System.out.println(Math.PI);
System.out.println(Math.sqrt(9));
System.out.println(Math.random());
}
}
静态和非静态的区别
-
本类中的访问限制区别
静态的类变量和静态的方法可以在本类任意位置直接访问。
非静态的实例变量和非静态的方法只能在本类的非静态的方法、构造器等非静态成员中直接访问。
- 静态直接访问静态,可以
- 非静态直接访问非静态,可以
- 非静态直接访问静态,可以
- 静态直接访问非静态,不可以
-
在其他类的访问方式区别
静态的类变量和静态的方法可以通过
类名.
的方式直接访问;也可以通过对象.
(不推荐)的方式访问。非静态的实例变量和非静态的方法只能通过
对象.
方式访问。