static关键字详解

static关键字

static 可以修饰变量,方法,代码块和内部类。

1 、static修饰变量

static修饰成员变量时:static修饰成员变量时,那么该成员变量的数据就是一个共享的数据.

静态成员变量的访问方式:
方式一: 使用对象进行访问。
对象.属性名
方式二:可以使用类名进行访问。
类名.属性名

注意:

  1. 非静态成员变量不能类名直接访问,只能使用对象进行访问。

  2. 千万不要为了方便访问成员变量而使用static修饰,一定要是该数据是共享数据 时才使用static修饰。

2、static修饰方法

static方法称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说是没有this和super的。因为他不依赖于任何对象,既然都没有对象,就谈不上this和super了。

并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。

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

举个例子来看:

package com.cc;

public class StaticTest {
    private static String str1 = "moon";
    private String str2 = "cmy";

    public StaticTest() {

    }

    public void print1() {
        System.out.println(str1);
        System.out.println(str2);
        print2();
    }

    public static void print2() {
        System.out.println(str1);
        //System.out.println(str2);//静态方法中不能调用非静态成员变量
        //print1();//静态方法中不能调用非静态方法
    }
}

3、static修饰类

static一般用来修饰成员变量和方法,但是有一种特殊的用法是用static修饰内部类,普通类是不允许用static修饰的,只有内部类可以。

看个例子更清晰:

package com.cc;

public class StaticTest {

    //static关键字修饰内部类
    public static class InnerClass {
        public InnerClass() {
            System.out.println("静态内部类");
        }
        public void InnerMethod() {
            System.out.println("静态内部方法");
        }
    }

    public static void main(String[] args) {
        //直接通过类名StaticTest访问静态内部类InnerClass
        InnerClass inner = new StaticTest.InnerClass();
        inner.InnerMethod();
    }
}


/* 输出结果:
 * 静态内部类
 * 静态内部方法
*/ 

如果没有用static修饰InterClass,则只能new 一个外部类实例。再通过外部实例创建内部类。

4、static修饰代码块

静态代码块在类第一次被加载的时候执行,咱们这里来验证一下类初始化的顺序。

父类构造函数

父类静态代码块

子类构造函数

子类静态代码块
package com.cc;

public class Father {

    static {
        System.out.println("父类静态代码块");
    }

    public Father() {
        System.out.println("父类构造函数");
    }
}
package com.cc;

public class Son extends Father{

    static {
        System.out.println("子类静态代码块");
    }

    public Son() {
        System.out.println("子类构造函数");
    }

    public static void main(String[] args) {
        new Son();
    }
}
//输出结果:
父类静态代码块
子类静态代码块
父类构造函数
子类构造函数   

咱们再通过内存的角度来分析一下static关键字。

这就涉及到了JVM运行时数据区,关于各个区域的介绍,可参考此篇博客

内存分析static

在这里插入图片描述

从上图我们可以发现,静态变量存放在方法区中,并且是被所有线程所共享的。这里要说一下java堆,java堆存放的就是我们创建的一个个实例变量。

堆区:

1、存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)

2、jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身

栈区:

1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中

2、每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。

3、栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。、

方法区:

1、又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。

2、方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

下面通过一个案例说明一下,从内存的角度来看,static关键字为什么会有这样的特性。

package com.cc;

public class Person {

    static String firstName;
    String lastName;

    public void showName() {
        System.out.println(firstName + lastName);
    }
    
    public static void viewName() {
        System.out.println(firstName);
    }

    public static void main(String[] args) {
        Person p1 = new Person();
        Person.firstName = "张";
        p1.lastName = "三";
        p1.showName();

        Person p2 = new Person();
        Person.firstName = "李";
        p2.lastName = "四";
        p2.showName();
    }
}

/*
输出结果:
张三
李四*/

看一下内存图:
在这里插入图片描述
从上面可以看到,我们的方法在调用的时候,是从方法区调用的,但是堆内存不一样,堆内存中的成员变量lastname是随着对象的产生而产生。随着对象的消失而消失。静态变量是所有线程共享的,所以不会消失。这也就能解释上面static关键字的真正原因。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值