• Java Static关键字详解


    先思考两个问题:

    1.为什么要使用Static关键字?

    2.加了Static关键字修饰后会有什么不同?  

    Static

    一.为什么要使用Static关键字?

    这里摘录一下《Java编程思想(第四版)》里关于static关键字的一段原话:(P29)通常来说,当创建类时,就是在描述那个类的对象的外观与行为。除非用new创建那个对象,否则,实际上并未获得任何对象。执行new来创建对象的时候,数据存储空间才被分配,其方法才供外界调用。有两种情形用上述方法是无法解决的。一种情形是,只想为某特定域分配单一存储空间,而不去考虑究竟要创建多少个对象,甚至根本不需要创建任何对象。另一种情形是,希望某个方法不与包含他的类的任何对象关联在一起。也就是说,即使没有创建对象,也能够调用方法。简单来说,static的主要目的就是创建独立于具体对象的域变量与方法。

    二.加了Static关键字修饰会有什么不同?

    1.this不能调用被static修饰的属性字段。

       因为被static修饰的会在类加载的时候初始化,被称为类级变量(属于类);而类的实例是在运行的时候初始化,属于对象级变量(属于对象)。

       this是指当前对象的实例,super是指父类对象的实例。this(super)不能调用被static修饰的属性字段的原因:jvm有类加载器,第一次加载时执行static域,jvm会专门划分一个内存区域给static程序块,所以什么时候都可以调用这个被static修饰的属性字段或者方法,属于类。this指针是指向类的对象,在实例化对象时候jvm会在堆区分配给一个具体对象,this指向该对象。所以在静态方法中不能调用非静态属性或者方法,如果在静态方法中使用this关键字,则this无法指向合适的对象。(通俗一点的话:即jvm的类加载机制决定了加载静态会先与非静态,即加载静态的时候非静态属性和方法都不存在)

    2.static修饰属性和方法

    1.static修饰属性时候,即所有该类对象共享一份存储空间。

    public class StaticTest {
        public static int staticA;
        public int A;
        
        public static void main(String[] args){
           StaticTest test;
           StaticTest A1=new StaticTest();
           StaticTest A2=new StaticTest();
           A1.staticA++;
           A2.staticA++;
           A1.A++;
           A2.A++;
           System.out.println("StaticAInfo:"+A1.staticA+" "+A2.staticA);
           System.out.println("AInfo"+A1.A+" "+A2.A);
        }
    }
    
    /** 运行结果
     * StaticAInfo:2 2
     * AInfo1 1
     **/

    即static修饰的不是某个具体对象所有,而是该类所有对象共有的,StaticTest.staticA只有一份存储空间。

    2.static修饰方法时候,类和对象都能调用该方法,没有被static修饰的方法只能被实例化对象调用。

    public class StaticTest {
        public static void staticTest(){
            
        }    
        public void test(){
            
        }
          
        public static void main(String[] args){
           StaticTest.staticTest();
           //StaticTest.test();  该调用是错误的
           StaticTest test=new StaticTest();
           test.staticTest();
           test.test();
        }
    }

    static修饰成员方法最大的作用,就是可以使用"类名.方法名"的方式操作方法,避免了先要new出对象的繁琐和资源消耗,一个static修饰的类中,不能使用非static修饰的成员变量和方法,这很好理解,因为static修饰的方法是属于类的,如果去直接使用对象的成员变量,它会不知所措(不知该使用哪一个对象的属性)。

    static修饰成员方法的时候最大的好处是可以节省new一个对象的开销,即可以直接通过类来调用方法。

    3.static修饰内部类

    一般用的比较少只能用来修饰内部类,一个static修饰的内部类中,不能使用非static修饰的成员变量和方法,这很好理解,因为static修饰的方法是属于类的,如果去直接使用对象的成员变量,它会不知所措(不知该使用哪一个对象的属性)。

    4.静态块

    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初始化
         *///~
    }

    在上面的例子中我们可以发现两个有意思的地方,第一个是当我们没有创建对象,而是通过类去调用类方法时,尽管该方法没有使用到任何的类成员,类成员还是在方法调用之前就初始化了,这说明,当我们第一次去使用一个类时,就会触发该类的成员初始化。第二个是当我们使用了类方法,完成类的成员的初始化后,再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初始化
         *///~
    }

       

     

     

    余虽不敏,然余诚矣。如果有什么不对的地方望不吝赐教,希望通过博客来沉淀自己和分享讨论自己的见解。
  • 相关阅读:
    P1587 [NOI2016]循环之美 杜教筛
    【学习笔记】省选动态规划类型选讲
    【模板】结构体重载高精度
    SP1716 GSS3
    SP1043 GSS1
    P1890 gcd区间 线段树
    【模板】(最小费用)最大流
    【模板】矩阵乘法
    P1073 最优贸易 DFS
    【2019.8.14】2019QB学堂DP图论班第一次考试 Problem C
  • 原文地址:https://www.cnblogs.com/ahangBlogs/p/7719330.html
Copyright © 2020-2023  润新知