跳到内容
当前位置:首页>面试真题>【面试真题拆解09】Java的Static关键字到底怎么用?

【面试真题拆解09】Java的Static关键字到底怎么用?

  • 2026-09-14 19:41:06
【面试真题拆解09】Java的Static关键字到底怎么用?

面试官上来就问:

“ 那个Java里面的Static关键字,一般是怎么用?”

一句话:

Static是“类级别的”,不是“实例级别的”。

被Static修饰的东西,属于整个类,所有实例共用一份,不用new对象就能直接用;

而没被Static修饰的东西,属于单个实例,每个实例有自己的一份,必须new对象才能用。

对比项
静态(Static)
实例(非Static)
归属
属于整个类
属于单个实例
内存位置
方法区(JDK8 之后叫元空间)
堆内存
访问方式
类名.(变量/方法),或(实例.变量/方法)(不推荐)
必须通过实例.变量/方法访问
共享性
所有实例共用一份
每个实例有自己的一份
初始化时机
类加载时初始化
创建实例时初始化
访问限制
只能直接访问静态成员
可以访问静态成员和实例成员

1. 静态变量

静态变量就像是整个类共享的“公共储物柜”,所有实例共用这一个柜子,你放进去的东西,别人也能拿到;而实例变量是每个实例自己的“私人储物柜”,互不干扰。

举个例子,用静态变量做全局计数器

/** * 网站访问计数器 */publicclassWebsiteCounter{// 静态变量:所有实例共用,统计总访问次数publicstaticint totalVisitCount = 0;// 实例变量:每个实例自己的,统计单个用户的访问次数publicint userVisitCount = 0;/**     * 访问方法     */publicvoidvisit(){// 修改静态变量:总访问次数+1        totalVisitCount++;// 修改实例变量:单个用户访问次数+1        userVisitCount++;    }publicstaticvoidmain(String[] args){// 用户1访问        WebsiteCounter user1 = new WebsiteCounter();        user1.visit();        user1.visit();        System.out.println("用户1访问次数:" + user1.userVisitCount); // 输出2        System.out.println("总访问次数:" + WebsiteCounter.totalVisitCount); // 输出2// 用户2访问        WebsiteCounter user2 = new WebsiteCounter();        user2.visit();        System.out.println("用户2访问次数:" + user2.userVisitCount); // 输出1        System.out.println("总访问次数:" + WebsiteCounter.totalVisitCount); // 输出3    }}

2. 静态方法

静态方法是属于类的“公共工具”,不用new对象,直接通过【类名.方法名】就能调用,而实例方法是属于单个实例的,必须new对象之后才能调用。

举个例子,用静态方法做工具类

/** * 字符串工具类 */publicclassStringUtils{// 私有构造方法:从根源上禁止外部代码 new StringUtils()// 工具类全是静态方法,完全不需要实例化,这样做能强制大家用[类名.方法名]的正确用法privateStringUtils(){}/**     * 静态方法:判断字符串是否为空     */publicstaticbooleanisEmpty(String str){return str == null || str.trim().isEmpty();    }/**     * 静态方法:字符串反转     */publicstatic String reverse(String str){if (isEmpty(str)) {return str;        }returnnew StringBuilder(str).reverse().toString();    }publicstaticvoidmain(String[] args){// 直接通过类名调用静态方法,不用new对象        System.out.println(StringUtils.isEmpty("")); // 输出true        System.out.println(StringUtils.reverse("hello")); // 输出olleh    }}

3. 静态代码块

静态代码块是类加载的时候执行一次,且只执行一次的代码块,用来初始化静态变量,或者做一些类级别的准备工作(比如加载配置文件、初始化数据库连接池)。

举个例子,用静态代码块初始化静态配置

/** * 配置类 */publicclassConfig{// 静态变量:数据库连接地址publicstatic String dbUrl;publicstatic String dbUsername;publicstatic String dbPassword;// 静态代码块:类加载时执行一次,初始化静态变量static {        System.out.println("静态代码块执行,开始初始化配置...");// 模拟从配置文件读取配置        dbUrl = "jdbc:mysql://localhost:3306/test";        dbUsername = "root";        dbPassword = "123456";    }// 实例代码块:创建实例时执行,每次new都执行    {        System.out.println("实例代码块执行...");    }// 构造方法:创建实例时执行,每次new都执行publicConfig(){        System.out.println("构造方法执行...");    }publicstaticvoidmain(String[] args){// 第一次访问Config类,触发类加载,静态代码块执行        System.out.println("数据库地址:" + Config.dbUrl);        System.out.println("---");// new第一个实例,实例代码块和构造方法执行new Config();        System.out.println("---");// new第二个实例,实例代码块和构造方法执行,但静态代码块不再执行new Config();    }}

小贴士

静态代码块只在类第一次被加载时执行一次,之后不管new多少个实例,都不会再执行。

4. 静态内部类

静态内部类是属于外部类的“独立房间”,不用依赖外部类的实例就能直接创建,而非静态内部类是属于外部类实例的“附属房间”,必须先有外部类实例才能创建。

静态内部类的作用是:

利用 Java 的类加载时机,实现了懒加载(用的时候才创建)+ 线程安全(JVM 保证)+ 不用加锁(性能高)的完美单例。

举个例子,用静态内部类实现线程安全的单例模式

/** * 单例模式:静态内部类实现 */publicclassSingleton{// 私有构造方法:从根源上禁止外部代码直接 new Singleton()privateSingleton(){}// 静态内部类:只有第一次被访问时才会加载(实现懒加载,用的时候才创建实例,不占内存)// 因为是在 Singleton 类内部,所以可以访问上面的 private 构造方法privatestaticclassSingletonHolder{// 静态变量:JVM 类加载过程是天然线程安全的,这里初始化唯一的单例实例(不用加锁,性能高)privatestaticfinal Singleton INSTANCE = new Singleton();    }// 全局唯一的访问点:外部代码只能通过这里获取单例实例publicstatic Singleton getInstance(){return SingletonHolder.INSTANCE;    }publicstaticvoidmain(String[] args){// 获取单例实例        Singleton instance1 = Singleton.getInstance();        Singleton instance2 = Singleton.getInstance();// 两个实例是同一个,完美实现单例        System.out.println(instance1 == instance2); // 输出true    }}

小贴士

  • 静态变量存放在JVM的方法区(元空间),不是堆内存。
  • 静态变量可以通过【类名.变量名】直接访问,也可以通过【实例.变量名】访问(不过,不推荐,因为容易混淆)。
  • 因为所有线程共用同一个静态变量,多线程同时修改会出现并发问题,需要加锁保证线程安全。
  • 因为实例变量和方法依赖具体的实例,静态方法调用时可能还没new对象,所以,静态方法只能直接访问静态变量和静态方法,不能直接访问实例变量和实例方法。
  • this 代表当前实例,静态方法属于类,调用时可能还没创建实例,this 根本不存在,所以,静态方法不能用 this。
  • 静态内部类只能直接访问外部类的静态变量和静态方法,不能直接访问实例变量和实例方法。