Day35--static关键字详解

Day35--static关键字详解

本次要掌握的是:

1.静态变量、非静态变量 调用变量的方法

2.静态方法、非静态方法 调用方法的方法

3.静态代码块和匿名代码块、构造器执行的先后顺序

示例:

​ 在demo07中,打开Student类

​ 建立main方法,创建age类变量和score实例变量;创建Student的实例s1,用对象调用变量age、score;用类调用变量age、score

package com.liu.oop.demo07;

//static
public class Student {
    private static int age;     //静态的变量------类变量
    private double score;       //非静态的变量----实例变量

    public static void main(String[] args) {
    
        Student s1 = new Student();
        
        System.out.println(s1.age);     //通过对象调用变量
        System.out.println(Student.age);//通过类调用变量

        System.out.println(s1.score);
        System.out.println(Student.score);//报错
    }
}

调用变量的两种方式:

1.只能通过实例对象调用变量------------------------------------实例变量

2.既能通过类,又能通过实例对象调用变量-----------------类变量

上面的代码,为什么对变量age,通过对象调用和通过类调用都可以,而对变量score,不能通过类调用?

详细解释;

一、关于静态变量
在 Java 中,静态变量(用static关键字修饰)的,既可以通过类名Student来访问它(如Student.age),也可以通过创建的对象来访问(如s1.age,这里s1Student类的一个实例对象)

二、关于非静态变量(实例变量)

非静态变量(没有用static关键字修饰的变量)必须通过创建对象来访问。

再比如:创建了非静态方法run和静态方法go,如何在下面的代码main方法中调用他们?

package com.liu.oop.demo07;

//static
public class Student {
    private static int age;     //静态的变量
    private double score;       //非静态的变量

    public void run(){}
    public static void go(){}

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

实际方法:

package com.liu.oop.demo07;

//static
public class Student {
    private static int age;     //静态的变量
    private double score;       //非静态的变量

    public void run(){}         //静态方法
    public static void go(){}   //非静态方法
    
    public static void main(String[] args) {
        //调用 go方法
        student.go();
        Student.go();
        go();

        //调用run方法
        student.run();
        new Student().run();
    }
}

以下是对 new Student().run();这种调用 run 方法的方式的详细介绍:

在 Java 中,要调用一个非静态方法(像示例代码中的 run 方法),通常需要先创建类的实例(对象),然后通过该实例来调用方法。

Student student = new Student(); // 创建Student类的一个实例
student.run(); // 通过创建好的实例调用run方法

new Student().run(); 这种写法将对象的创建(实例化)和对非静态方法 run 的调用合并在了一起。它首先使用 new Student() 创建了 Student 类的一个新对象,然后紧接着通过这个刚创建好的对象调用了 run 方法。不过,需要注意的是,如果在后续代码中还可能会多次使用到同一个 Student 对象,那么更推荐使用常规的先创建对象并保存引用,然后再通过引用多次调用对象方法的方式,这样代码的可读性和可维护性会更好。

与此同时,我们发现了一个有趣的事情:

非静态方法可以调用静态方法,但是静态方法不能调用非静态方法

 public void run(){
        go();//可以
    }
    
 public static void go(){
        run();//报错
    }

在类里面,有代码块

package com.liu.oop.demo07;

public class Person {


    {
        //代码块(匿名代码块)

    }


   static {
        //静态代码块

    }



}

我们可以借此了解代码块的相关信息

​ 清空Person的内容,然后创建匿名代码块,里面输出System.out.println("匿名代码块");

​ 创建静态代码块,System.out.println("静态代码块");

​ 创建无参构造器,输出 System.out.println("构造方法");

​ 然后创建main方法,创建Person的实例对象

猜一猜,下面的代码输出结果是什么?

package com.liu.oop.demo07;

public class Person {


    {
        System.out.println("匿名代码块");
        //代码块(匿名代码块)

    }


   static {
       System.out.println("静态代码块");
        //静态代码块

    }

    public Person() {
        System.out.println("构造方法");
    }

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

上面的代码加载过程:

  1. Java 程序启动并执行包含 main 方法的类(在这里是 Person 类)时,Java 虚拟机(JVM)开始进行类加载过程。静态代码块是在类加载阶段初始化类时执行的。这是因为静态代码块通常用于初始化静态变量的默认值等。
  2. 在类加载完成后,当执行 new Person(); 来创建一个 Person 类的对象时,首先会执行实例初始化块(匿名代码块)。
  3. 完成匿名代码块的执行后,接着会执行构造器(public Person()),完成对象的创建和初始化过程。

代码输出结果是:

静态代码块
匿名代码块
构造方法

代码第一次执行,按照先后顺序来看,

首先执行的是:静态代码块

然后执行的是:匿名代码块

最后执行的是:构造器

也就是说,在创建对象的时候,先执行静态代码块,再执行匿名代码块,最后执行构造器

那么,再执行一次,结果会有变化吗?

package com.liu.oop.demo07;

public class Person {

    //2
    {
        System.out.println("匿名代码块");
        //代码块(匿名代码块)

    }

    //1
   static {
       System.out.println("静态代码块");
        //静态代码块

    }

    //3
    public Person() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Person person1 = new Person();
        System.out.println("=========================================");
        Person person2 = new Person();
    }
}

输出结果:

静态代码块
匿名代码块
构造方法
=========================================
匿名代码块
构造方法

可见,静态代码块只执行一次

再一个例子:

想生成随机数,我们可以这样:

package com.liu.oop.demo07;

public class Test {
    public static void main(String[] args) {
        System.out.println(Math.random());
    }
}

但是,能不能直接System.out.println(random()); 不用Math?

可以!!!

导入

package com.liu.oop.demo07;

//静态导入包
import static java.lang.Math.random;

public class Test {
    public static void main(String[] args) {
        System.out.println(random());
    }
}

拓展:

如果类是被final修饰的,他没有子类

假如Person是被final修饰的,想让Test作它的子类,不行

package com.liu.oop.demo07;

public final class Person 
public class Test extends Person{  //报错

错误示例:

package com.liu.oop.demo07;//在demo07中,打开Student类
//
//​			建立main方法,创建age类变量和score实例变量;创建Student的实例s1,用对象调用变量age、score;用类调用变量age、score

public class Student {
    public static int age;
    public int score;

    public static void main(String[] args) {
        Student s1 = new Student();
        s1.age();       //报错
        s1.score();     //报错
        Student.age();  //报错
        Student.score();//报错
    }

}

上面的代码为什么报错?

以下是这段代码报错的原因分析:

1. 变量调用方式错误

在Java中,对于实例变量(非静态变量,像代码中的score),需要通过实例对象来访问,其访问语法是实例对象.实例变量名。而对于静态变量(像代码中的age),既可以通过类名直接访问(类名.静态变量名),也可以通过实例对象来访问(实例对象.静态变量名,不过这种方式不推荐,容易造成混淆)。

在代码的main方法里:

  • s1.age(); 这一行报错,是因为age虽然是静态变量,但这样的调用方式像是在调用一个方法,而它实际只是一个变量,正确的访问方式如果通过实例对象来访问应该是 s1.age(直接获取它的值或者对其进行赋值等操作,例如 s1.age = 10;),或者通过类名访问即 Student.age
  • s1.score(); 报错是因为同样把变量当成方法在调用了,对于实例变量score,正确的访问应该是类似 s1.score = 80; 或者获取它的值如 System.out.println(s1.score); 等这样的操作,而不是加括号像调用方法一样去使用它。
  • Student.score(); 也报错,原因和前面把变量当成方法调用类似,静态方式访问实例变量本身就是错误的,实例变量必须通过实例对象来访问,不能通过类名去访问它,因为它是和具体的对象实例相关联的,不像静态变量属于类这个层面,和具体某个对象实例无关。

2. 修改后的正确代码示例

以下是修正后的代码示例,展示了正确的变量访问方式:

package com.liu.oop.demo07;

public class Student {
    public static int age;
    public int score;

    public static void main(String[] args) {
        Student s1 = new Student();
        // 通过实例对象s1访问实例变量score,进行赋值操作
        s1.score = 90;
        // 通过实例对象s1访问静态变量age,进行赋值操作
        s1.age = 20;
        // 通过类名访问静态变量age,输出其值
        System.out.println(Student.age);
        // 通过实例对象s1访问实例变量score,输出其值
        System.out.println(s1.score);
    }
}

总之,代码报错主要是混淆了变量和方法的使用语法,以及没有正确遵循Java中静态变量和实例变量不同的访问规则所导致的。

posted @ 2024-11-21 16:07  1hahahahahahahaha  阅读(19)  评论(0)    收藏  举报