Java中static详解

为了让static 关键字的概念更加浅显易懂,我们可以从一个简单的学生信息系统入手。假设我们需要创建一个 Student 类来存储每个学生的姓名、学号等信息,同时还需要记录学校的名字和统计当前有多少学生。这时候,static 就能发挥很好的作用。

静态变量

1. 没有 static 的场景:每个学生都有自己的一份数据

首先,让我们看看没有 static 的时候,所有信息(包括不应该重复存储的)都被每个学生对象独立保存的情况。

代码示例:
class Student {
    // 学生的实例变量,每个学生都有独立的姓名和学号
    String name;
    int id;
    String schoolName = "清华大学";  // 这里是学校的名字(每个对象都保存)

    // 构造函数
    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }

    // 显示学生信息
    public void displayInfo() {
        System.out.println("姓名: " + name + ", 学号: " + id + ", 学校: " + schoolName);
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建两个学生对象
        Student student1 = new Student("小明", 101);
        Student student2 = new Student("小红", 102);
        
        // 显示学生信息
        student1.displayInfo();
        student2.displayInfo();
    }
}
运行结果:
姓名: 小明, 学号: 101, 学校: 清华大学
姓名: 小红, 学号: 102, 学校: 清华大学

问题:
  • 在这个例子中,schoolName(学校名称)是每个学生对象的实例变量,这意味着每个学生对象都存储了同样的学校信息。如果有 1000 个学生,那每个学生都将独立保存相同的“清华大学”字符串。这显然浪费了内存。
  • 解决方法:我们可以使用 static 关键字,让学校名称只保存一份,所有学生对象共享这一数据。

2. 引入 static:共享学校名称和统计学生人数

通过使用 static 关键字,我们可以做到以下几点:

  • 学校名称是所有学生共享的,只存储一份。
  • 学生人数是共享的,每创建一个学生对象,学生数量自动增加。

代码示例:

class Student {
    // 学生的实例变量(每个学生都有自己的姓名和学号)
    String name;
    int id;
    
    // 静态变量(所有学生共享),学校名称和学生总人数
    static String schoolName = "清华大学";
    static int studentCount = 0;

    // 构造函数
    public Student(String name, int id) {
        this.name = name;
        this.id = id;
        studentCount++;  // 每创建一个学生,人数增加
    }

    // 显示学生信息
    public void displayInfo() {
        System.out.println("姓名: " + name + ", 学号: " + id + ", 学校: " + schoolName);
    }

    // 静态方法:显示学生总数
    public static void displayStudentCount() {
        System.out.println("当前学生总数: " + studentCount);
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建两个学生对象
        Student student1 = new Student("小明", 101);
        Student student2 = new Student("小红", 102);
        
        // 显示每个学生的信息
        student1.displayInfo();
        student2.displayInfo();
        
        // 调用静态方法显示总人数
        Student.displayStudentCount(); // 注意,静态方法通过类名调用
    }
}

运行结果:

姓名: 小明, 学号: 101, 学校: 清华大学
姓名: 小红, 学号: 102, 学校: 清华大学
当前学生总数: 2
解释:
  • schoolName 是一个 static 变量,因此它属于类本身,而不是某个具体的学生对象。这意味着无论创建多少个学生对象,schoolName 只会存储一份,所有对象共享这个学校名称。
  • studentCount 是一个 static 变量,用于记录学生的总数。每次创建一个学生对象,studentCount 都会增加。这也是静态变量的一个重要用途:统计类级别的信息
  • displayStudentCount() 是一个 static 方法,表示它与具体的对象无关,可以直接通过类名调用。

3. 为什么需要 static

  • 节省内存: 如果我们不使用 static,每个对象都需要独立存储相同的信息,比如学校的名字。这会浪费大量内存。而使用 static 后,学校名称只存储一份,所有对象共享。

  • 全局统计: 如果你需要在整个程序中维护一些全局的状态,比如学生的总人数,使用 static 变量可以确保所有对象共享这一状态,并且可以在类级别访问它,而无需依赖于具体的某个对象。

  • 无需依赖对象: 静态方法和静态变量与对象无关,因此可以直接通过类名调用,方便那些不依赖实例的操作。


静态方法(static method)

好的!接下来我们详细讲解一下**static 方法**在 Java 中的使用,包括它的特性、应用场景、以及注意事项。

1. 什么是static method?

static 方法是属于类本身的方法,而不是属于某个特定对象的方法。换句话说,static 方法不依赖于对象的状态,因此可以通过类名直接调用,而不需要实例化对象。

特性:

  • static 方法可以直接通过类名调用,而不需要创建类的对象。
  • static 方法只能访问静态变量或调用静态方法,不能访问类的非静态(实例)变量或调用非静态方法,因为它不与特定对象关联。
  • 常用于工具类或不依赖对象状态的功能。

2. 为什么使用 static 方法?

1) 无需创建对象

有些功能不需要对象状态,例如数学计算、全局的逻辑操作等。为了避免每次使用这些功能时都创建对象,我们可以将这些功能设计为 static 方法,这样可以直接通过类名调用,简化代码。

2) 提高性能和效率

static 方法在类加载时就已经绑定到类上,因此调用时不需要通过对象查找,性能上有一定的优势。

3) 不依赖于对象状态

如果方法的行为不依赖于对象的实例变量或实例方法,那么它可以被设计为 static 方法。这样可以让方法更通用,减少对对象的依赖。


3. static 方法的示例

例子1:数学工具类

假设我们需要创建一个数学工具类,提供计算平方和平方根的功能。这些功能并不依赖于对象状态,因此可以将其定义为静态方法。

class MathUtil {
    // 静态方法:计算平方
    public static int square(int number) {
        return number * number;
    }

    // 静态方法:计算平方根
    public static double squareRoot(double number) {
        return Math.sqrt(number);
    }
}

public class Main {
    public static void main(String[] args) {
        // 通过类名直接调用静态方法,无需创建对象
        int result = MathUtil.square(5);
        System.out.println("5的平方是: " + result);

        double sqrtResult = MathUtil.squareRoot(25.0);
        System.out.println("25的平方根是: " + sqrtResult);
    }
}

输出:
5的平方是: 25
25的平方根是: 5.0

解释:
  • MathUtil 类中的 squaresquareRoot 是静态方法,因为它们不依赖于任何对象状态。我们可以直接通过 MathUtil.square(5)MathUtil.squareRoot(25.0) 调用这些方法,而不需要创建 MathUtil 类的对象.

4. static 方法的访问限制

只能访问静态变量和静态方法

由于 static 方法属于类本身,而不是某个具体对象,所以它无法访问对象的实例变量或实例方法。static 方法只能访问类的静态成员(静态变量和静态方法)

示例:
class Student {
    String name; // 实例变量
    static String schoolName = "清华大学"; // 静态变量

    // 静态方法
    public static void printSchoolName() {
        System.out.println("学校名称: " + schoolName); // 可以访问静态变量
        // System.out.println("学生姓名: " + name); // 错误!静态方法不能访问实例变量
    }
}

解释:
  • printSchoolName 是一个静态方法,它只能访问类的静态变量 schoolName
  • 如果尝试在静态方法中访问实例变量 name,会导致编译错误,因为静态方法不依赖于任何具体对象,因此无法访问对象的实例变量。

5. 静态方法的限制

1) 无法访问非静态成员

正如前面提到的,静态方法不能直接访问类的实例变量或调用实例方法,因为静态方法不依赖于具体的对象实例。

2) 不能使用 thissuper 关键字

this 关键字引用的是当前对象,而 super 关键字引用的是父类对象的引用。由于静态方法属于类本身而不是对象,因此在静态方法中不能使用 thissuper

示例:
class Test {
    int x;

    public static void testMethod() {
        // this.x = 5; // 错误!静态方法中不能使用this
    }
}

3) 静态方法不能被重写(overriding)

静态方法属于类,不参与对象的动态绑定(多态性)。如果一个静态方法在子类中定义了相同的方法,实际上这是对父类静态方法的隐藏(hiding),而不是重写。

示例:
class Parent {
    public static void display() {
        System.out.println("Parent类的静态方法");
    }
}

class Child extends Parent {
    public static void display() {
        System.out.println("Child类的静态方法");
    }
}

public class Main {
    public static void main(String[] args) {
        Parent parent = new Parent();
        Parent child = new Child();
        
        parent.display();  // 输出:Parent类的静态方法
        child.display();   // 输出:Parent类的静态方法(静态方法没有多态性)
    }
}

解释:
  • 虽然在子类中定义了与父类相同的静态方法,但静态方法属于类本身,因此并不会像实例方法一样通过对象的多态性调用子类方法。child.display() 实际上调用的是 Parent 类的 display() 方法。
  • 如果方法需要动态绑定,应该使用实例方法而不是静态方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值