Java static关键字怎么用?一文搞懂静态变量和方法

 更新时间:2026年08月12日 10:59:56   作者:努力学习的孩子呀  
还在为Java中的static、final和抽象类感到困惑吗?这篇文章将带你彻底搞懂静态修饰符的共享特性、final的不可变性以及抽象类的模板模式,让你掌握这些核心概念,轻松应对开发中的常见场景

1 static修饰符

1.1 static简介

1.1.1 概述

static是Java静态修饰符,用于修饰类成员(变量/方法),核心特征:

1. 属于类(类成员),非单个对象;

2. 被所有对象共享,一处修改全局生效;

3. 类加载时初始化,无需创建对象即可访问。

  • 属于类本身,而非类的单个对象,因此也称为“类成员”
  • 被该类的所有对象共享,一处修改会影响所有对象的访问结果
  • 加载时机早于对象,类加载时静态成员就已初始化,无需创建对象即可访问

典型场景:描述类对象公共属性,如所有中国人的国籍,定义为静态变量供共享。

1.1.2 案例实现

定义中国人类(Chinese),国籍(country)为静态变量,姓名等为普通变量,演示共享特性:

/**  
* @ClassName: Chinese  
* @Description: 中国人类,演示静态变量共享特性
*/
public class Chinese {
    // 静态共享变量
    public static String country = "中国";
    // 对象独有变量
    private String name;
    private int age;
    private String work;

    // 构造器
    public Chinese() {}
    public Chinese(String name, int age, String work) {
        this.name = name;
        this.age = age;
        this.work = work;
    }

    // getter/setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getWork() { return work; }
    public void setWork(String work) { this.work = work; }
}

测试类(StaticDemo)验证共享性:

/**  
* @ClassName: StaticDemo  
* @Description: 静态变量共享性测试
*/
public class StaticDemo {
    public static void main(String[] args) {
        Chinese c1 = new Chinese("王宝强", 34, "演员");
        System.out.println(c1.getAge() + "岁的" + c1.getName() + "是" + c1.country + "人");
        Chinese c2 = new Chinese("周星驰", 48, "演员/导演/制片");
        System.out.println(c2.getAge() + "岁的" + c2.getName() + "是" + c2.country + "人");
        
        // 修改静态变量
        c1.country = "中华人民共和国";
        System.out.println("===============================");
        System.out.println(c1.getAge() + "岁的" + c1.getName() + "是" + c1.country + "人");
        System.out.println(c2.getAge() + "岁的" + c2.getName() + "是" + c2.country + "人");
    }
}

运行结果:修改一个对象访问的静态变量后,所有对象访问结果均改变,验证共享性。

1.2 静态的使用方式及加载原理

1.2.1 访问方式规范

静态成员推荐类名直接访问(对象访问会警告),因静态成员属于类,与对象无关。

访问类型

语法格式

推荐度

静态变量

类名.静态变量名

强烈推荐

静态变量

对象名.静态变量名

不推荐(警告)

静态方法

类名.静态方法名(参数)

强烈推荐

静态方法

对象名.静态方法名(参数)

不推荐(警告)

1.2.2 静态方法的访问限制

静态方法加载早于对象,不能直接访问非静态成员(依赖对象);非静态方法可直接访问静态成员。

/**  
* @ClassName: StaticDemo2  
* @Description: 静态方法访问限制测试
*/
public class StaticDemo2 {
    private String name = "张三"; // 非静态变量
    
    // 非静态方法
    public void normalMethod() {
        System.out.println("非静态方法");
        staticMethod(); // 可访问静态方法
    }
    
    // 静态方法
    public static void staticMethod() {
        System.out.println("静态方法");
        // 错误:静态方法不能访问非静态成员
        // System.out.println(name);
        // normalMethod();
    }
    
    public static void main(String[] args) {
        StaticDemo2.staticMethod(); // 类名直接调用
    }
}

2.final关键字

2.1 概述

final意为“最终的”,修饰类、方法、变量,核心作用是限制修改,保障代码安全。继承场景中可防止父类核心逻辑被篡改。

常见应用:定义常量(如PI)、限制核心类继承(如String)、限制核心方法重写。

2.2 具体使用方式

2.2.1 修饰类:不可被继承

final修饰的类不可继承(“类绝育”),如String、Math等核心类,确保功能不被篡改。

// final修饰类不可继承
final class Fu {
    public void show() { System.out.println("父类方法"); }
}

// 错误:无法继承final类
// class Zi extends Fu {}

2.2.2 修饰方法:不可被重写

final修饰的方法不可重写,但可继承调用,适用于父类固定逻辑的核心方法。

class Fu2 {
    // final方法不可重写
    final public void show1() { System.out.println("父类不可重写方法"); }
    // 普通方法可重写
    public void show2() { System.out.println("父类可重写方法"); }
}

class Zi2 extends Fu2 {
    // 错误:无法重写final方法
    // @Override
    // public void show1() {}
    
    // 正确重写普通方法
    @Override
    public void show2() { System.out.println("子类重写方法"); }
}

2.2.3 修饰变量:不可重复赋值

final修饰的变量仅能赋值一次,按类型分局部变量和成员变量,赋值方式不同。

1. 修饰局部变量

基本类型final局部变量值不可改;引用类型地址不可改,但对象属性可修改。

public class FinalDemo1 {
    public static void main(String[] args) {
        // 基本类型局部变量
        final int a = 10;
        // 错误:不可重复赋值
        // a = 20;
        
        // 引用类型局部变量
        final Chinese c = new Chinese("李四", 25, "教师");
        // 错误:地址不可改
        // c = new Chinese("王五", 30, "医生");
        // 正确:属性可改
        c.setName("李四更新");
        System.out.println(c.getName());
    }
}

注意:循环中final局部变量每次循环是新变量,可正常赋值:

for (int i = 0; i < 3; i++) {
    final int b = i; // 每次循环都是新的b,合法
    System.out.println(b); // 输出:0、1、2
}

2. 修饰成员变量

final成员变量需显式赋值(JVM默认值无效),仅一次赋值机会,两种方式:显式初始化(定义时赋值)、构造器初始化(所有构造器均需赋值)。

  • 显式初始化:定义时直接赋值

  • 构造器初始化:所有构造器中均赋值

public class Student {
    final int num1 = 1001; // 显式初始化
    final int num2; // 构造器初始化
    
    public Student() { num2 = 2001; }
    public Student(int num2) { this.num2 = num2; }
    
    // 错误:普通方法不能赋值final成员变量
    // public void setNum2(int num2) { this.num2 = num2; }
}

命名规范:final静态常量全大写,多单词下划线分隔,如public static final int MAX_AGE = 120;

3 抽象类与抽象方法

3.1 抽象类与抽象方法的引入

部分类仅描述共性,无需创建对象(如“员工”),具体功能由子类实现。不同子类对同一方法实现不同,需抽象类和抽象方法解决。

为解决这种场景,Java引入抽象类和抽象方法:

  • 抽象方法:仅签名无方法体,abstract修饰

  • 抽象类:含抽象方法的类,abstract修饰,不能创建对象

3.2 定义格式

类型

定义格式

说明

抽象类

abstract class 类名 { ... }

abstract在class前

抽象方法

修饰符 abstract 返回值类型 方法名(参数列表);

无方法体,分号结束

3.3 案例实现

以“员工-服务员”为例,抽象员工类定义抽象工作方法,服务员类实现该方法:

/**  
* @ClassName: Employee  
* @Description: 抽象员工类
*/
public abstract class Employee {
    public abstract void work(); // 抽象工作方法
}

/**  
* @ClassName: Waiter  
* @Description: 服务员类(实现抽象方法)
*/
public class Waiter extends Employee {
    @Override
    public void work() {
        System.out.println("服务员:引导就座,记录订单,上菜");
    }
}

/**  
* @ClassName: AbstractDemo  
* @Description: 抽象类测试
*/
public class AbstractDemo {
    public static void main(String[] args) {
        // 错误:抽象类不能创建对象
        // Employee e = new Employee();
        Waiter waiter = new Waiter();
        waiter.work();
    }
}

3.4 抽象类的构造方法

抽象类不能创建对象,但有构造方法,供子类调用以初始化父类成员变量,子类对象可使用这些变量。

/**  
* @ClassName: Employee  
* @Description: 带构造器的抽象员工类
*/
public abstract class Employee {
    private String name;
    private String id;
    
    public Employee(String name, String id) {
        this.name = name;
        this.id = id;
    }
    
    public abstract void work();
    
    // getter
    public String getName() { return name; }
    public String getId() { return id; }
}

/**  
* @ClassName: Manager  
* @Description: 经理类(继承抽象类)
*/
public class Manager extends Employee {
    public Manager(String name, String id) {
        super(name, id); // 调用父类构造器
    }
    
    @Override
    public void work() {
        System.out.println(getName() + "(工号:" + getId() + "):管理员工,制定计划");
    }
}

// 测试类
public class AbstractDemo2 {
    public static void main(String[] args) {
        Manager manager = new Manager("张三", "M001");
        manager.work();
    }
}

3.5 抽象类的核心特点与注意事项

3.5.1 核心特点

  • 抽象类和方法需abstract修饰,抽象方法必在抽象类中
  • 抽象类不能直接创建对象,需通过非抽象子类
  • 子类需重写所有抽象方法,否则子类也为抽象类
  • 抽象类体现模板思想,封装共性,抽象方法定规范

3.5.2 常见误区解析

  • 误区1:抽象类仅含抽象方法? 纠正:可含普通方法、变量、构造器,纯普通方法抽象类用于限制创建对象。
  • 误区2:子类需重写所有方法? 纠正:仅重写抽象方法,普通方法可继承。
  • 误区3:抽象方法有方法体? 纠正:无方法体,有则非抽象方法。

3.6 模板模式(抽象类的典型应用)

模板模式:抽象父类定义固定流程(普通方法),不确定步骤为抽象方法由子类实现,保证流程一致、细节灵活。

案例:新司机和老司机开车的流程一致(开门→点火→驾驶→刹车→熄火),但驾驶姿势不同,用模板模式实现:

/**  
* @ClassName: Driver  
* @Description: 司机抽象类(模板类)
*/
public abstract class Driver {
    // 模板方法:固定流程
    public final void drive() {
        System.out.println("1. 开门上车");
        System.out.println("2. 点火启动");
        drivePosture(); // 抽象步骤
        System.out.println("4. 刹车停车");
        System.out.println("5. 熄火下车");
    }
    
    // 抽象方法:驾驶姿势(子类实现)
    public abstract void drivePosture();
}

// 新司机类
public class NewDriver extends Driver {
    @Override
    public void drivePosture() {
        System.out.println("3. 新司机:双手握方向盘,目视前方");
    }
}

// 老司机类
public class OldDriver extends Driver {
    @Override
    public void drivePosture() {
        System.out.println("3. 老司机:右手握盘,左手搭扶手");
    }
}

// 测试类
public class TemplateDemo {
    public static void main(String[] args) {
        new NewDriver().drive();
        System.out.println("====================");
        new OldDriver().drive();
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Springboot使用kafka的两种方式

    Springboot使用kafka的两种方式

    在公司用kafka比较多,今天整理下Springboot使用kafka的两种方式,Kafka作为一个消息发布订阅系统,就包括消息生成者和消息消费者,文中通过代码示例介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2023-11-11
  • SpringBoot优雅接收前端请求参数的详细过程

    SpringBoot优雅接收前端请求参数的详细过程

    这篇文章主要介绍了SpringBoot如何优雅接收前端请求参数,我们可以通过@RequestParm注解去绑定请求中的参数,将(查询参数或者form表单数据)绑定到controller的方法参数中,本文结合示例代码给大家讲解的非常详细,需要的朋友可以参考下
    2023-06-06
  • 详解Java8 CompletableFuture的并行处理用法

    详解Java8 CompletableFuture的并行处理用法

    Java8中有一个工具非常有用,那就是CompletableFuture,本章主要讲解CompletableFuture的并行处理用法,感兴趣的小伙伴可以了解一下
    2022-04-04
  • SpringBoot配置与使用maven的方法

    SpringBoot配置与使用maven的方法

    本文介绍了如何在IntelliJ IDEA中创建和配置Maven项目,包括创建过程、目录结构、pom.xml文件的用途、依赖管理、生命周期、配置选项以及如何下载依赖和配置本地仓库,感兴趣的朋友跟随小编一起看看吧
    2026-01-01
  • Java中可变长度参数代码详解

    Java中可变长度参数代码详解

    这篇文章主要介绍了Java中可变长度参数代码详解,涉及了实参个数可变的定义方法,数组包裹实参等几个问题,具有一定参考价值,需要的朋友可以了解下。
    2017-12-12
  • Java中重载与重写的对比与区别

    Java中重载与重写的对比与区别

    这篇文章主要介绍了Java中重载与重写的对比与区别的相关资料,需要的朋友可以参考下
    2017-03-03
  • springboot使用RedisRepository操作数据的实现

    springboot使用RedisRepository操作数据的实现

    本文主要介绍了springboot使用RedisRepository操作数据的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Spring框架+jdbcTemplate实现增删改查功能

    Spring框架+jdbcTemplate实现增删改查功能

    这篇文章主要介绍了Spring框架+jdbcTemplate实现增删改查功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Java中的Object类详细介绍

    Java中的Object类详细介绍

    这篇文章主要介绍了Java中的Object类详细介绍,本文讲解了Object类的作用、Object类的主要方法、Object类中不能被重写的方法、Object类的equals方法重写实例等内容,需要的朋友可以参考下
    2015-06-06
  • Springboot实现连接多个ElasticSearch数据库的过程

    Springboot实现连接多个ElasticSearch数据库的过程

    这篇文章介绍了如何在Springboot项目中实现与多个Elasticsearch数据库的高效交互,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2026-03-03

最新评论