Static关键字

static关键字

static能够修饰的结构:

  • 属性
  • 方法
  • 代码块
  • 内部类

static修饰属性:静态变量

静态变量是由类中的对象所共享的。当其中的一个对象修改了静态变量以后,会导致其他对象调用此静态变量的时候,也是修改过了的

静态变量会在类加载过程中的链接阶段进行初始化操作,其中:

  • 准备阶段进行默认零值的初始化

  • 初始化阶段进行静态变量的赋值操作

需要注意的点:

  • 静态变量随着类的加载而加载,可以通过类名.静态变量的方式进行调用
  • 静态变量的加载早于对象的创建,在上面已经提到了
  • 由于类只会加载一次,故静态变量也只会在内存中存在一个副本,JDK8之前存放在方法区中的静态域中,JDK8以后存放在堆的静态域
  • 可以使用this调用静态变量,也可以使用this调用静态方法,只要访问权限够就行!!!

Java中常见的静态变量:

  • System.out
  • Math.PI

场景题:非静态方法能够通过this访问静态变量吗?

package com.feng;

public class Main {
    static int value = 33;
    public static void main(String[] args) {
        new Main().print();
    }

    public void print() {
        int value = 3;
        System.out.println(this.value);
    }
}

输出结果:

33

解析:

  • 这里面主要考察队this和static的理解。this代表什么?this代表当前对象,那么通过new Main()来调用printValue的话,当前对象就是通过new Main()生成的对象。而static变量是被对象所享有的,因此在printValue中的this.value的值毫无疑问是33。在printValue方法内部的value是局部变量,根本不可能与this关联,所以输出结果是33。
  • 在这里永远要记住一点:静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)

static修饰方法:静态方法

static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。

但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。举个简单的例子:

在这里插入图片描述

在上面的代码中,由于print2方法是独立于对象存在的,可以直接用过类名调用。假如说可以在静态方法中访问非静态方法/变量的话,那么如果在main方法中有下面一条语句:

MyObject.print2();

此时对象都没有,str2根本就不存在,所以就会产生矛盾了。同样对于方法也是一样,由于你无法预知在print1方法中是否访问了非静态成员变量,所以也禁止在静态成员方法中访问非静态成员方法。

而对于非静态成员方法,它访问静态成员方法/变量显然是毫无限制的。

因此,如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为static。我们最常见的static方法就是main方法,至于为什么main方法必须是static的,现在就很清楚了。因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问

注意的点:

  • 静态方法不仅可以使用类名.静态方法的方式进行调用,也可以使用创建对象,使用对象.静态方法的方式进行调用
  • 在静态方法中,不能使用this,super关键字
  • 一般我们在一些工具类中,习惯将方法声明为static,例如:Math,Arrays,Collections等等

static修饰代码块:静态代码块

static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。

下面看个例子:

isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好:

因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

package com.feng;

public class Main {
    static int value = 33;
    static {
        System.out.println("我是静态代码块");
        System.out.println(value);
    }
    public static void main(String[] args) {
        new Main().method();
    }

    public void method() {
        System.out.println("成员方法");
    }
}

输出结果:

我是静态代码块
33
成员方法

static内部类

当我们向将一个类隐藏在另一个类的内部,并不需要内部类引用外围对象,对此我们可以将该内部类声明为static

其中:

  • 静态内部类只能访问外部类的静态变量和静态方法,在静态内部类内部可以定义静态变量,方法以及构造函数等等
  • 我们可以采取自己new的方式进行静态内部类的对象的创建,同样可以使用外部类.静态内部类的方式调用静态方法,但是不能调用非静态方法
public class OuterClass {
    private int a = 10;
    private static int b = 20;

    public static class StaticInnerClass {
        private static int b = 30;

        //可以定义构造函数
        public StaticInnerClass() {

        }

        //定义静态方法
        public static void func1() {
            System.out.println("静态内部类的静态方法");
        }

        //定义非静态方法
        public void func2() {
            System.out.println("静态内部类的非静态方法");
        }
    }
}
public static void main(String[] args) {
    //创建静态内部类的第一种方式:自己new
    StaticInnerClass class1 = new StaticInnerClass();
    class1.func2();
    class1.func1();
}
public static void main(String[] args) {
    //采用外部类.内部类
    OuterClass.StaticInnerClass.func1();
    OuterClass.StaticInnerClass.func2();   //编译不通过
}

`

public static void main(String[] args) {
    //采用外部类.内部类
    OuterClass.StaticInnerClass.func1();
    OuterClass.StaticInnerClass.func2();   //编译不通过
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值