Java-静态static

234 阅读4分钟

Static

在类中声明的实例变量,其值是每一个对象独立的。但是有些成员变量的值不需要或不能每一个对象单独存储一份,即有些成员变量和当前类的对象无关。

在类中声明的实例方法,在类的外面必须要先创建对象,才能调用。但是有些方法的调用和当前类的对象无关,那么创建对象就有点麻烦了。

此时,就需要将和当前类的对象无关的成员变量、成员方法声明为静态的(static)。

成员变量分为两种:

  1. 静态变量(有static)
  2. 实例变量(没有static)

1、语法格式

有static修饰的成员变量就是静态变量。

【修饰符】 class 类{
	【其他修饰符】 static 数据类型  静态变量名;
}

2、静态变量的特点

  • 静态变量的默认值规则和实例变量一样。
  • 静态变量值是所有对象共享。
  • 静态变量的值存储在方法区。
  • 静态变量在本类中,可以在任意方法、代码块、构造器中直接使用。原则:对象可以使用类的信息,类不能反过来使用对象的信息。
  • 如果权限修饰符允许,在其他类中可以通过“类名.静态变量”直接访问,也可以通过“对象.静态变量”的方式访问(但是更推荐使用类名.静态变量的方式)。
  • 静态变量的get/set方法也静态的,当局部变量与静态变量重名时,使用“类名.静态变量”进行区分。


案例:编写一个员工类型,希望有一个变量可以统计员工对象的数量(即创建了多少个员工对象)。员工里面有属性:员工编号、员工姓名,希望员工编号是从1开始自增。第一个员工就是1,第二个员工就是2...。

>遇到的问题:之前的非静态的成员变量是每一个对象“独立”的,无法实现“共享”。
>
>解决方案:静态。成员变量用static修饰。

```Java
public class Employee {
    static int total;//默认值还是0
    private int id;
    private String name;
    private int score;

    {
        //非静态代码块,两个构造器共同代码的提取,
        //为什么要抽取?因为有两个构造方法,
        //不抽取的话,分别用不同的构造方法构造对象,数据不会被共享
        total++;
        this.id = total;
    }

    public Employee(String name) {
        this.name = name;
    }

    public Employee(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public static int getTotal() {
        return total;
    }

    public static void setTotal(int total) {
        Employee.total = total;
    }


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + ''' +
                ",total = " + total +
                '}' ;
    }
}
public class TestStatic {
    public static void main(String[] args) {
        System.out.println("一开始,员工对象的数量有:" +  Employee.getTotal());//0
        Employee e1 = new Employee("张三");
        System.out.println(e1);
        Employee e2 = new Employee("李四");
        System.out.println(e2);
        Employee e3 = new Employee("王五", 89);
        System.out.println(e3);
        System.out.println("创建完3个员工对象后,员工对象的数量:" + Employee.getTotal());//推荐 输出3

        //通过对象,访问静态方法
        System.out.println("通过e1对象调用静态方法,获取员工的数量:" + e1.getTotal());//不推荐

        //下面两个使用,需要total不是private的,即权限修饰符允许
        System.out.println("获取total,不通过方法:" + Employee.total);//推荐
        System.out.println("获取total,不通过方法:" + e1.total);//不推荐
    }
}

image.png

2、静态方法的特点

【修饰符】 class 类{
	【其他修饰符】 static 返回值类型 方法名(形参列表){
        方法体
    }
}
  1. 静态方法在本类中,任意的方法、代码块、构造器都可以使用,没有限制。
  2. 静态方法在类的外面,只要权限修饰符允许,可以通过:“对象.静态方法” 或 “类名.静态方法”,推荐使用 "类名.静态方法"
  3. 在静态方法中千万不要直接使用本类的 非静态属性、非静态方法、this、super。
  4. 静态方法不允许被子类重写,但是可以被子类继承。
  5. 静态方法不是“虚”方法。既然不是虚方法,就没有多态现象(只看变量的编译时类型)。
public class Father {
    public static void method(){
        System.out.println("Father.method");
    }

    public static void fun(){
        System.out.println("Father.fun");
    }
}
public class Son extends Father{
//    @Override //尝试重写静态方法,加上@Override编译报错,去掉Override不报错,但是也不是重写
    public static void fun(){
        System.out.println("Son.fun");
    }
}
public class TestStaticMethod {
    public static void main(String[] args) {
        Father.method();
        Son.method();//继承静态方法

        Father f = new Son();
        f.method();//执行Father类中的method
    }
}

3、静态代码块

在代码块前面加static,就是静态代码块

【修饰符】 class 类{
	static{
        静态代码块
    }
}

静态代码块的特点

  • 每一个类的静态代码块只会执行一次。非静态代码块在实例初始化时执行,每次new对象都会执行。
  • 静态代码块的执行优先于非静态代码块和构造器。