Java基础(static关键字)

static是什么

static关键字修饰的代码属于类,属于类的代码是被共享的。

static修饰的变量叫做类变量,是被所有该类产生的对象所共享的。

static修饰的方法属于静态方法,静态方法能够直接被main方法所使用,非静态方法不能直接被main方法所使用。只有静态方法才能调用静态方法(即除了main方法外只有static关键字修饰的方法才能调用static修饰的方法)。

static修饰的代码块 static修饰的代码块在main方法运行之前运行,其目的是优化程序。

public class Person {
    public String name="张三 ";
    public static String adress="中国";
    public static void run(String num){
        System.out.println("跑了"+num+"米");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                "adress='"+adress+'\''+
                '}';
    }
}
public class Test1 {
    public static void main(String[] args) {
        Person p1=new Person();
        Person p2=new Person();
        p1.name="李四";
        p1.adress="北京";
        p1.run("200");

        p2.name="王五";
        p2.adress="上海";
        p1.run("100");


        System.out.println(p1.toString());
        System.out.println(p2.toString());
    }
}

输出结果为:

跑了200米
跑了100米
Person{name='李四'adress='上海'}
Person{name='王五'adress='上海'}

运行过程:

static修饰的address存放方法区的静态变量池当中,当main方法入栈后,创建p1和p2两个对象,此时对象可以对静态常量池中的静态变量进行修改赋值操作,在执行完p2的修改操作后,静态常量池中的address常量变为上海,再执行打印时,会都输出上海(两个对象共用address静态变量)。

设置static关键字的原因

方便java中的类去更方便直接地使用自己的方法和变量。

方法和变量上面没有static关键字

即方法和变量属于非静态,只有在对象中才会被分配内存空间,只有对象才能调用。

方法和变量上有static关键字

即方法和变量属于静态,方法和变量会被存储在方法区的静态常量池中,能够直接被类调用。上一张图中可以看出如果没有static关键字,那么类是不可以调用自己的属性和方法的,只能用对象去调用。

static关键字怎么用

以下是static关键字的用法。

static修饰变量

static修饰的变量被称为类变量,这个变量与普通变量不同,类变量是属于整个类的,此类产生的所有对象都可以调用此变量。可以算得上是“公共资源”。类变量(即static修饰的变量)存储在方法区的静态常量池中,被所有对象由该类产生的对象所共享。
在代码中使用 static 修饰一个变量时,该变量就不再属于某个对象实例,而是属于类本身。

public class Person {
    public String name="张三 ";
    public static String adress="中国";
    public static void run(String num){
        System.out.println("跑了"+num+"米");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                "adress='"+adress+'\''+
                '}';
    }
}
public class Test1 {
    public static void main(String[] args) {
        Person p1=new Person();
        Person p2=new Person();
        p1.name="李四";
        p1.adress="北京";
        p1.run("200");

        p2.name="王五";
        p2.adress="上海";
        p1.run("100");


        System.out.println(p1.toString());
        System.out.println(p2.toString());
    }
}

输出为:

跑了200米
跑了100米
Person{name='李四'adress='上海'}
Person{name='王五'adress='上海'}

分析:

address变量被 static 修饰,存储在方法区的静态常量池中,由该类产生的所有对象实例( p1、p2)共享此静态变量。
p1和p2 是两个实例对象,两个对象的name变量存储在各自的堆内存中,彼此独立。
当我们通过 p1修改 address的值时,类变量address的值就被修改为 "北京"。由于address是类变量,p2再次修改它的值时,所有实例访问到的address都变成了 "上海"。

static修饰方法

static修饰的静态方法无法调用非静态方法

public class A{
    public static String name="admin";
    public static String address="中国";

    public static void H(){
        F();
    }
    public void F(){

    }

static修饰的方法称为静态方法。静态方法与类关联,而不是与某个对象关联。这意味着我们可以在没有创建对象实例的情况下调用静态方法。

静态方法与非静态方法的互相调用
静态方法中无法直接调用非静态方法。因为非静态方法依赖于对象实例,而静态方法不依赖于任何对象实例。

解决无法调用问题

1、将非静态方法转换为静态方法:可以通过将非静态方法添加 static 关键字,使其成为静态方法。
2、通过对象调用非静态方法:在静态方法中创建一个对象实例,然后通过该对象来调用非静态方法。

在非静态方法中可以调用静态方法

在非静态方法中可以调用静态方法的原因:在对象实例创建之前,类已经加载且静态方法已存在。静态方法是类的一部分,并且在类加载时就已经存在,因此在任何时候都可以被调用。

static修饰代码块

static修饰的代码块(即静态代码块)在类被加载时自动执行,通常用于在类加载时执行一些初始化工作。static修饰的代码块在main方法执行之前运行(真正意义上说,是在static代码块所在的类被调用进方法区时进行static代码块的运行),主要用于优化程序或进行一些预处理。

代码一般运行顺序

当程序启动时,首先会寻找含有 main() 函数的类,并启动该程序。
扫描检查该类是否有父类。如果有,则继续扫描父类并加载父类(递归地进行)。
当找到最顶层的父类后,首先加载父类,并执行父类中的 static 代码块。
接着加载子类,并执行子类中的 static 代码块。
最后,进入 main() 方法,程序开始执行。

例子:

public class Test extends Base {
    static {
        System.out.println("test static");
    }
    public Test(){
        System.out.println("test constructor");
    }
}
class Base{
    static {
        System.out.println("base static");
    }
    public Base(){
        System.out.println("base constructor");
    }
    public static void main(String[] args) {
        new Test();
    }
}

输出:

base static
test static
base constructor
test constructor

运行逻辑:

程序执行先去找main()方法启动程序
1、程序执行先去扫描Base类,发现Base类没有父类
2、将Base.class加载进方法区,此时Base类当中的static代码块执行
3、main方法入栈,执行new Test();创建Test类对象
4、扫描Test类,其有父类且父类已经被扫描过
5、将Test.class加载进方法区,此时Base类当中的static代码块执行
6、继续执行new Test();创建Test类对象
7、创建子类对象之前先创建父类对象,所以先执行Base()构造器,再执行Test()构造器

 main方法调用方法

两种方式可以让某个方法在main方法中调用:

将方法设为静态方法

某个方法可以直接被main方法调用,只需在该方法前添加 static 关键字即可(将方法变为类方法,直接调用方法)。

public class ceshidaima1 {
 
    public static void ceshi() {
 
        System.out.println("这是类方法");
 
    }
 
}
 
 
 
public class Test {
 
    public static void main(String[] args) {
 
        ceshidaima1.ceshi(); // 直接调用静态方法
 
    }
 
}

输出:

这是类方法

通过对象调用非静态方法

若方法是非静态的,则需要先创建对象,然后通过对象调用该方法。

public class ceshidaima1 {
 
    public void ceshi() {
 
        System.out.println("这是非静态方法");
 
    }
 
}
 
 
 
public class Test {
 
    public static void main(String[] args) {
 
        ceshidaima1 a = new ceshidaima1();
 
        a.ceshi(); // 通过对象调用非静态方法
 
    }
 
}

输出:

这是非静态方法

具体实例

具体的代码示例,分析 static 关键字的加载顺序和使用。

public class Demo {
 
    public Demo(String aa) {
 
        System.out.println("====" + aa);
 
    }
    static {
 
        System.out.println("11");
 
    }
    public static Demo demo = new Demo("+++");
    static {
 
        System.out.println("22");
 
    }
 
}
class Test {
 
    public static void main(String[] args) {
 
        Demo demo = new Demo("----");
 
    }
 
}

输出:

11
====+++
22
====----

分析:

首先,程序执行main方法,定位到 Test 类。

在执行 main 方法中的语句 Demo demo = new Demo("----"); 时,需要调用 Demo 类的构造器。

由于 Demo 类被引用,JVM 会首先加载 Demo.class 到内存,并初始化其中的静态部分。

static 代码块和静态变量按顺序执行,因此输出顺序如下:

11(第一个静态代码块)

====+++(静态变量 demo 调用了 Demo 的构造函数)

22(第二个静态代码块)

====---(main 方法中 new 了一个 Demo 对象)

至此,此篇文章结束。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值