• static关键字


    static关键字的四种用法

    1、修饰成员变量

      我们通常将static修饰的成员变量称为类变量或者静态变量,这是相对于对象的属性来说的。请看下面的例子:

     1 public class Person {
     2     String name;
     3     int age;
     4     
     5     public String toString() {
     6         return "Name:" + name + ", Age:" + age;
     7     }
     8     
     9     public static void main(String[] args) {
    10         Person p1 = new Person();
    11         p1.name = "zhangsan";
    12         p1.age = 10;
    13         Person p2 = new Person();
    14         p2.name = "lisi";
    15         p2.age = 12;
    16         System.out.println(p1);
    17         System.out.println(p2);
    18     }
    19     /**Output
    20      * Name:zhangsan, Age:10
    21      * Name:lisi, Age:12
    22      *///~
    23 }
    View Code

       Person类构造出的每个对象都是独立存在的,如p1和p2都有自己的成员变量,互不影响,它们在内存的示意图如下图1.1:

    图1.1

      p1和p2两个引用变量指向的对象分别存储在堆区域的不同地址中,所以它们互不影响。对象的成员变量都在这了,由每个对象自己保存,但是对象的方法却不在堆区域中。其实,无论创建多少对象,它们都共用同一个方法,如下图1.2所示:

    图1.2

      从图1.2中可以看到,两个对象指向同一个方法定义,且该方法定义在一块不变的区域(有JVM划分),暂时称为静态存储区。这块区域不仅存放了方法的定义,各种类的定义也存放在该区域,当用new创建对象时,会根据该区域定义的类去创建对象。

      那么,用static关键字修饰成员变量,让它们变成类所属,会变成不同的样子,请看下面的例子:

    public class Person {
        String name;
        static int age;
        
        /* 其余代码不变... */
    
        /**Output
         * Name:zhangsan, Age:12
         * Name:lisi, Age:12
         *///~
    }
    View Code

    图1.3

      我们可以看到,static修饰的age变量同方法一样由类统一管理,都存放的静态存储区,该变量让对象共享,但实际中很少这么用。

    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
         *///~
    }
    View Code

      上面的例子可以用count记录一共创建了多少个对象,且count是由private修饰的,在类外边无法随意改变。

     2、static关键字修饰成员方法

      存储上没有多大变化,因为方法本来就是在存放在类的定义中。可以直接使用“类名.方法名”方式调用方法,避免先要new出对象的繁琐和资源消耗。

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

      上面的例子可以看出,print()方法相当于一个全局函数,只要导入该类的包,就可以使用“类名.方法名”方式调用它。但是在一个static修饰的方法中,不能使用非静态的方法和成员变量,因为static修饰的方法是属于类的,它不能直接访问对象的成员变量,它不知道使用哪个对象的属性。

    3、静态块

      在说明static的第三种用法时,先介绍一下对象的初始化过程。以下面的代码为例:

    package com.dotgua.study;
    
    class Book{
        public Book(String msg) {
            System.out.println(msg);
        }
    }
    
    public class Person {
    
        Book book1 = new Book("book1成员变量初始化");
        static Book book2 = new Book("static成员book2成员变量初始化");
        
        public Person(String msg) {
            System.out.println(msg);
        }
        
        Book book3 = new Book("book3成员变量初始化");
        static Book book4 = new Book("static成员book4成员变量初始化");
        
        public static void main(String[] args) {
            Person p1 = new Person("p1初始化");
        }
        /**Output
         * static成员book2成员变量初始化
         * static成员book4成员变量初始化
         * book1成员变量初始化
         * book3成员变量初始化
         * p1初始化
         *///~
    }
    View Code

      上面的例子可以看出,new对象时,会先初始化static修饰成员变量book2和book4,接着再初始化普通的成员变量book1和book2,最后调用方法的构造器完成初始化。并且如果有多个static修饰的成员变量时,会按定义的先后顺序进行初始化。

      实际上,static修饰的成员变量变量可以被更早的初始化,以下面的代码为例:

    class Book{
        public Book(String msg) {
            System.out.println(msg);
        }
    }
    
    public class Person {
    
        Book book1 = new Book("book1成员变量初始化");
        static Book book2 = new Book("static成员book2成员变量初始化");
        
        public Person(String msg) {
            System.out.println(msg);
        }
        
        Book book3 = new Book("book3成员变量初始化");
        static Book book4 = new Book("static成员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初始化
         *///~
    }
    View Code

      上面的例子可以看出,未new对象,只是调用static修饰的成员方法,并且方法中未使用任何成员变量,仍会触发static修饰的成员变量初始化,普通的成员变量不会初始化。还可以看到,紧接着new对象的时候,static修饰的成员方法不会再次被初始化,只需要初始化一次。

      接着看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初始化
         *///~
    }
    View Code

      当我们初始static修饰的成员变量时,可以将它们统一放在一个以static开始,花括弧裹起来的块状语句中。

    4、静态导包

      相比上边三种用法,这种用法很少见,以下面的代码为例:

    /* PrintHelper.java文件 */
    package com.dotgua.study;
    
    public class PrintHelper {
    
        public static void print(Object o){
            System.out.println(o);
        }
    }
    View Code
    /* App.java文件 */
    
    import static com.dotgua.study.PrintHelper.*;
    
    public class App 
    {
        public static void main( String[] args )
        {
            print("Hello World!");
        }
        /**Output
         * Hello World!
         *///~
    }
    View Code

      上面代码来自两个Java文件,PrintHelper类包含一个static修饰的静态方法。在App.java中,导入PrintHelper类使用了static关键字,并且在引入类的最后加了“.*”。这样,再不与当前类的方法名冲突的情况下,就可以直接采用“方法名”的方式调用方法,就像该类在使用自己的方法一样。

    总结

      1.用来修饰成员变量,将成员变量由类来统一管理,所有实现该类的对象共享该成员变量;

      2.修饰成员方法,可以使用“类名.方法名”调用方法,常用于工具类;

      3.静态块用法,将多个static修饰的成员变量放在一起初始化,使程序更加规整,理解对象的初始化过程非常关键;

      4.静态导包法,将类的方法直接导入到当前类中,用“方法名”直接调用类方法,更加方便。 

    5、修饰内部类

      内部类可以当普通类 来使用,实例化static内部类的时候不需要依赖外部类。

      

  • 相关阅读:
    View Controller 生命周期的各个方法的用法
    IOS开发之Post 方式获取服务器数据
    委托代理
    Function
    SKPhysicsContactDelegate协议
    UITouch附加
    Remove Duplicates from Sorted Array II
    4Sum
    [Text Justification
    Count and Say
  • 原文地址:https://www.cnblogs.com/lmmblogs/p/8583039.html
Copyright © 2020-2023  润新知