static关键字解析

0.前言

    static关键字表示静态,常用于修饰属性,方法和代码块。

1.修饰成员变量(类变量)

    static修饰的成员称为类成员或者静态成员,相对于对象的属性和方法来说的。请看下面的例子:(未避免程序太过臃肿,暂时不管访问控制)

tips:  static不能修饰局部变量;类变量是在类加载时被创建开始进行初始化,类加载只进行一次,那么类变量也只被创建一次;不管有没有static修饰的方法(其实就是方法),都不能出现static变量、

public class Person {
    String name;
    int age;
    
    public String toString() {
        return "Name:" + name + ", Age:" + age;
    }
    
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "zhangsan";
        p1.age = 10;
        Person p2 = new Person();
        p2.name = "lisi";
        p2.age = 12;
        System.out.println(p1);
        System.out.println(p2);
    }
    /**Output
     * Name:zhangsan, Age:10
     * Name:lisi, Age:12
     *///~
}

        Person构造出的每一个对象都是独立存在的,保存有自己独立的成员变量,相互不会影响,他们在内存中的示意如下:

 

        从上图中可以看出,p1和p2两个变量引用的对象分别存储在内存中堆区域的不同地址中,所以他们之间相互不会干扰。但其实,在这当中,对象的成员属性都在这了,由每个对象自己保存,那么他们的方法呢?实际上,不论一个类创建了几个对象,他们的方法都是一样的:


        从上面的图中我们可以看到,两个Person对象的方法实际上只是指向了同一个方法定义。这个方法定义是位于内存中的一块不变区域(由jvm划分),我们暂称它为静态存储区。这一块存储区不仅存放了方法的定义,实际上从更大的角度而言,它存放的是各种类的定义,当我们通过new来生成对象时,会根据这里定义的类的定义去创建对象。多个对象仅会对应同一个方法,这里有一个让我们充分信服的理由,那就是不管多少的对象,他们的方法总是相同的,尽管最后的输出会有所不同,但是方法总是会按照我们预想的结果去操作,即不同的对象去调用同一个方法,结果会不尽相同。

public class Person {
    String name;
    static int age;
    
    /* 其余代码不变... */

    /**Output
     * Name:zhangsan, Age:12
     * Name:lisi, Age:12
     *///~
}

        我们发现,结果发生了一点变化,在给p2的age属性赋值时,干扰了p1的age属性,这是为什么呢?我们还是来看他们在内存中的示意:


        我们发现,给age属性加了static关键字之后,Person对象就不再拥有age属性了,age属性会统一交给Person类去管理,即多个Person对象只会对应一个age属性,一个对象如果对age属性做了改变,其他的对象都会受到影响。我们看到此时的age和toString()方法一样,都是交由类去管理。
        虽然我们看到static可以让对象共享属性,但是实际中我们很少这么用,也不推荐这么使用。因为这样会让该属性变得难以控制,因为它在任何地方都有可能被改变。如果我们想共享属性,一般我们会采用其他的办法:

public class Person {
    private static int count = 0;
    int id;
    String name;
    int age;
    
    public Person() {
        id = ++count;
    }
    
    public String toString() {
        return "Id:" + id + ", Name:" + name + ", Age:" + age;
    }
    
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "zhangsan";
        p1.age = 10;
        Person p2 = new Person();
        p2.name = "lisi";
        p2.age = 12;
        System.out.println(p1);
        System.out.println(p2);
    }
    /**Output
     * Id:1, Name:zhangsan, Age:10
     * Id:2, Name:lisi, Age:12
     *///~
}

        上面的代码起到了给Person的对象创建一个唯一id以及记录总数的作用,其中count由static修饰,是Person类的成员属性,每次创建一个Person对象,就会使该属性自加1然后赋给对象的id属性,这样,count属性记录了创建Person对象的总数,由于count使用了private修饰,所以从类外面无法随意改变。


2.修饰方法(静态方法)

可以使用"类名.方法名"的方式操作方法:

注意:static修饰的方法,不能访问本类中非静态(static)成员(包括方法和属性),本类的非静态(static)方法可以访问本类的静态成员,静态方法中不能出现this,super关键字

public class PrintHelper {
    public static void print(Object o){
        System.out.println(o);
    }    
    public static void main(String[] args) {
        PrintHelper.print("Hello world");
    }
}

    一个static修饰的类中,不能使用非static修饰的成员变量和方法,因为static修饰的方法是属于类的,如果去直接使用对象的成员变量,它会不知所措(不知该使用哪一个对象的属性)。


3. 静态块

static修饰的类成员,在程序运行过程中,只需要初始化一次即可,不会进行多次的初始化。

class Book{
    public Book(String msg) {
        System.out.println(msg);
    }
}

public class Person {

    Book book1 = new Book("book1成员变量初始化");
    static Book book2;
    
    static {
        book2 = new Book("static成员book2成员变量初始化");
        book4 = new Book("static成员book4成员变量初始化");
    }
    
    public Person(String msg) {
        System.out.println(msg);
    }
    
    Book book3 = new Book("book3成员变量初始化");
    static Book book4;
    
    public static void funStatic() {
        System.out.println("static修饰的funStatic方法");
    }
    
    public static void main(String[] args) {
        Person.funStatic();
        System.out.println("****************");
        Person p1 = new Person("p1初始化");
    }
    /**Output
     * static成员book2成员变量初始化
     * static成员book4成员变量初始化
     * static修饰的funStatic方法
     * ***************
     * book1成员变量初始化
     * book3成员变量初始化
     * p1初始化
     *///~
}


4.静态导包

    实际上它很简单,而且在调用类方法时会更方便。 

    采用static导入包后,在不与当前类的方法名冲突的情况下,无需使用“类名.方法名”的方法去调用类方法了,直接可以采用"方法名"去调用类方法。

/* PrintHelper.java文件 */
package com.dotgua.study;

public class PrintHelper {

    public static void print(Object o){
        System.out.println(o);
    }
}
/* App.java文件 */

import static com.dotgua.study.PrintHelper.*;

public class App 
{
    public static void main( String[] args )
    {
        print("Hello World!");
    }
    /**Output
     * Hello World!
     *///~
}

   

5.总结

static是java中非常重要的一个关键字,而且它的用法也很丰富,主要有四种用法:
  • 修饰成员变量,将其变为类的成员,从而实现所有对象对于该成员的共享
  • 修饰成员方法,将其变为类方法,可以直接使用“类名.方法名”的方式调用,常用于工具类
  • 静态块用法,将多个类成员放在一起初始化,使得程序更加规整,其中理解对象的初始化过程非常关键
  • 静态导包用法,将类的方法直接导入到当前类中,从而直接使用“方法名”即可调用类方法,更加方便
常见误区:

  • static关键字不会改变类中成员的访问权限?  Java只有private,public、包访问等改变权限。
  • 不能通过this来访问静态成员变量。    this代表当前对象,static变量是所有对象共享的,两者没关系。
  • static不能作用局部变量。语法规定。


修改转载:https://www.cnblogs.com/dotgua/p/6354151.html?utm_source=itdadao&utm_medium=referral


猜你喜欢

转载自blog.csdn.net/jae_wang/article/details/80235025