【Java 基础】static 关键字的用法

31 篇文章 3 订阅
13 篇文章 3 订阅

一、概述

  • 在《Java 编程思想》有这样一段话:

static 方法就是没有 this 的方法。在 static 方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用 static 方法。这实际上正是 static 方法的主要用途。

一句话描述就是:方便在没有创建对象的情况下来进行调用(方法/变量)。很显然,被 static 关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

  • static 是静态修饰符。什么是静态修饰符?在程序中,任何变量或者代码都是在编译时由系统自动分配内存来存储的。而所谓静态,就是指在编译后系统所分配的内存会一直存在,直到程序退出内存才会释放这个空间。也就是说,只要程序在运行,那么这块内存就会一直存在。这样做有什么意义呢?在 Java 程序里面,所有的东西都是对象,而对象的抽象就是类,对于一个类而言,如果要使用它的成员,那么普通情况下必须先实例化对象后,通过对象的引用才能够访问这些成员,但是用 static 修饰的成员可以通过类名加”.“成员进行直接访问。

  • 被 static 修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,而是被类的所有实例共享。只要这个类被加载,Java 虚拟机就能根据类名在运行时数据区的方法区内找到被 static 修饰的方法。因为, static 对象可以在它的任何对象创建之前访问,无需引用任何对象。

  • static 变量前可以有 private 修饰。表示这个变量可以在类的静态代码块中,或者类的其它静态成员方法中使用,但是不能在其它类中通过类名来直接引用,有访问权限限定。static 是不允许用来修饰局部变量。

  • static 可以用来修饰类的成员方法、类的成员变量,另外可以编写 static 代码块来优化程序性能。

    • 类名.静态方法名(参数列表...)

    • 类名.静态变量名

    • 用 static 修饰的代码块表示静态代码块,当 Java 虚拟机(JVM)加载类时,就会执行该代码块

二、为什么要设计 static ?

  • 类直接调用成员。使用 static 修饰的成员可以通过”类名.成员“的方式直接调用。无需创建对象,进行调用成员方法。

  • 优先加载,兼顾优化性能。使用 static 修饰的变量,在内存中只有一个拷贝,可以节省内存。static 可以用来声明静态代码块,静态代码块只会执行一次。JVM 在加载类时会执行静态代码块,所以静态代码块先于主方法执行。如果类中包含多个静态代码块,会按顺序执行。静态代码块可以优化程序性能。

三、静态变量

static String str = "This is a static variable.";

按照是否静态的对类成员变量进行分类可分两种:一种是被 static 修饰的变量,叫静态变量或类变量。另一种是没有被 static 修饰的变量,叫实例变量。

两者的区别是:

  • 静态变量:对于静态变量在内存中只有一个拷贝(节省内存),JVM 只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便)。
  • 实例变量:每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。

四、静态方法

    public static void printString() {
        System.out.println("This is a static method.");
    }
  • 静态方法可以直接通过“类名.静态方法名(参数列表...)”。静态方法只能访问所属当前类的静态成员变量和静态成员方法。

  • 静态方法中不能用 this 和 super 关键字。静态方法属于类,不属于实例(对象)

  • 静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法写成静态的,一个类内部的方法一般都写成非静态的。

五、静态代码块

  • 用 static 关键字声明的代码块,每个静态代码块只会执行一次。由于 JVM 在加载类时会执行静态代码块,所以静态代码块先于主方法执行。

  • 如果类中包含多个静态代码块,则会按照顺序执行。

  • 静态代码块可以优化程序性能。

1、为什么说静态代码块可以优化程序性能?因为它的特性:只会在类加载的时候执行一次。

public class Person {

    private Date birthDate;

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }

    boolean isBornBetween1946And1964() {
        Date startDate = Date.valueOf("1946");
        Date endDate = Date.valueOf("1964");
        return birthDate.compareTo(startDate) > 0 && birthDate.compareTo(endDate) < 0;
    }

}

Person 是一个非常简单的类,其中 isBornBetween1946And1964() 是用来判断这个人是否是 1946 ~ 1964 年出生的,而每次 isBornBetween1946And1964() 被调用的时候,都会生成 startDate 和 endDate 两个对象,造成了空间浪费,如果改成这样效率是不是会更好。

public class Person {

    private Date birthDate;

    private static Date startDate, endDate;

    static {
        startDate = Date.valueOf("1946");
        endDate = Date.valueOf("1964");
    }

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }

    boolean isBornBetween1946And1964() {
//        Date startDate = Date.valueOf("1946");
//        Date endDate = Date.valueOf("1964");
        return birthDate.compareTo(startDate) > 0 && birthDate.compareTo(endDate) < 0;
    }

}

 所以,很多时候,可以将一些只需要执行一次的初始化操作放在 static 代码块中执行,有利于提高程序的效率。

2、常见面试题

public class Test extends Base{

    static {
        System.out.println("Test static");
    }

    public Test() {
        System.out.println("test 无参构造");
    }

    public static void main(String[] args) {
        new Test();
    }

}

class Base{

    static {
        System.out.println("base static");
    }

    public Base() {
        System.out.println("base 无参构造");
    }

}

输出结果:

base static
Test static
base 无参构造
test 无参构造

进程已结束,退出代码为 0

        看一下这段代码具体的执行过程,在执行开始,先要寻找到 main 方法,因为 main 方法是程序的入口,但是在执行 main 方法之前,必须先加载 Test 类,而在加载 Test 类的时候发现 Test 类继承自 Base 类,因此会转去先加载 Base 类,在加载 Base 类的时候,发现有 static 块,便执行了 static 块。在 Base 类加载完成之后,便继续记载 Test 类,然后发现 Test 类中也有 static 块,便执行 static 块。在加载完所需的类之后,便开始执行 main 方法。在 main 方法中执行 new Test() 的时候会先调用父类的构造器,然后再调用自身的构造器。

六、final static 的作用

private static final String TAG = "TAG";

static final 用来修饰成员变量和成员方法,可简单理解为 Java 中的“全局常量”。  

对于变量,使用 static final 修饰后,表示一旦给值就不可修改,并且通过类名可以访问。

static final为什么要一起用:

final与static final的区别是:final在一个对象类唯一,static final在多个对象中都唯一;

七、static 的注意事项

1、static 关键字会改变类中成员的访问权限吗?

Java 中的 static 关键字不会影响到变量或者方法的作用域。

在 Java 中能够影响到访问权限的只有 private、public、protected(包括访问权限)这几个关键字。看个例子就明白了:

 这说明 static 关键字并不会改变变量和方法的访问权限。

2、能通过 this 访问静态成员变量吗?

        在静态方法里只能直接调用同类中其他的静态成员(包括变量和方法),而不能直接访问同类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。而 this 本身就是引用的对象,当静态方法调用时,this 所引用的对象根本没有产生。

3、static 能作用于局部变量吗?

在 Java 中切记:static 是不允许用来修饰局部变量。不要问为什么,这是 Java 语法的规定。

成员变量的主体是类,类中定义的不是静态变量的都是成员变量。成员变量对类中所有成员可见,对外是否可见要看关键词有没有private,public,protected这些;局部变量的主体是方法,定义在函数中的变量就是局部变量,只在函数内起作用。

八、参考文档

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值