Java中的static关键字

目录

 

static关键字作用

1.static修饰成员变量

成员变量和静态变量的区别?

2.static修饰方法

3.static修饰代码块(静态代码块)

4.加载顺序

5.静态什么时候用?


static关键字作用

被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

static可以用来修饰类的成员方法、类的成员变量,另外也可以编写static代码块来优化程序性能

static关键字: 用于修饰成员( 成员变量和成员函数) 。
被修饰后的成员具备以下特点:
1、 随着类的加载而加载。
2、 优先于对象存在。
3、 被所有对象所共享。
4、 可以直接被类名调用

1.static修饰成员变量

static变量也称为静态变量,静态变量和非静态变量的区别:

  • 静态变量被所有对象共享,在内存中只有一个副本,在类初次加载的时候才会初始化

  • 非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响

当程序中使用了static关键字进行定义之后,那么此属性将不会保存在堆内存里面,会保存在一个全部数据区的内存空间之中.
静态成员属性对象也可以进行修改,修改后所有的对象的属性都发生变化
:
01. class Person{
02. //成员变量, 实例变量
03. String name;
04. //静态变量, 类变量
05. //所有对象共享的属性用static修饰
06. static String country = "CN";
07. public void show(){
08. System.out.println(country + ":" + name);
09. //等效语句: System.out.println(Person.country + ":" + this.name);
10. }
11. }
12.
13. class StaticDemo{
14. public static void main(String[] args){
15. Person p = new Person();
16. System.out.println(p.country);
17. //可以用类名直接调用
18. System.out.println(Person.country);
19. }
20. }

成员变量和静态变量的区别?

1.两个变量的生命周期不同
成员变量随着对象的创建而存在, 随着对象被回收而释放。
静态变量随着类的加载而存在, 随着类的消失而消失。
2.调用方式不同
成员变量只能被对象调用。
静态变量可以被对象调用, 还可以被类名调用。
3.别名不同
成员变量也称为实例变量。
静态变量也称为类变量。
4.数据存储位置不同
成员变量存储在堆内存的对象中, 所以也叫对象的特有数据。
静态变量数据存储在方法区( 共享数据区) 的静态区, 所以也叫对象的共享数据。

2.static修饰方法

 //    所有的static方法不允许调用非static定义的属性或方法。
//    所有的非static方法允许访问static属性或方法
//
//    因为所有的static方法可以在没有实例化对象的时候访问,而所有的非static方法在有实例化对象产生之后才可以操作。
//    一个对象如果对静态属性做了改变,其他的对象都会受到影响。
    //static修饰成员方法最大的作用,就是可以使用"类名.方法名"的方式操作方法,避免了先要new出对象的繁琐和资源消耗
    public static void setCountry(String c) {
        //this.country = country;这样调用报错,因为country是静态属性,this代表对象,此时可能还没有this
//        country = country;      //这样使用同名的参数与类属性不好
        country = c;
        //getInfo();//报Non-static method 'getInfo()' cannot be referenced from a static context
    }

1.静态方法只能访问静态成员, 如果访问非静态成员, 就会报错

2.静态方法中不可以写this, super关键字。

原因: 静态方法存在的时候, 对象还不存在

3.static修饰代码块(静态代码块)

随着类的加载而执行, 而且只执行一次。
作用: 用于给类进行初始化。提升程序性能

很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行

静态初始化块可以置于类中的任何地方,类中可以有多个静态初始化块。
在类初次被加载时,会按照静态初始化块的顺序来执行每个块,并且只会执行一次。

4.加载顺序

public class Test extends Base{

    static{
        System.out.println("test static");
    }

    public Test(){
        System.out.println("test constructor");
    }

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

class Base{

    static{
        System.out.println("base static");
    }

    public Base(){
        System.out.println("base constructor");
    }
}
base static
test static
base constructor
test constructor

分析下这段代码的执行过程:

    找到main方法入口,main方法是程序入口,但在执行main方法之前,要先加载Test类

    加载Test类的时候,发现Test类继承Base类,于是先去加载Base类

    加载Base类的时候,发现Base类有static块,而是先执行static块,输出base static结果

    Base类加载完成后,再去加载Test类,发现Test类也有static块,而是执行Test类中的static块,输出test static结果

    Base类和Test类加载完成后,然后执行main方法中的new Test(),调用子类构造器之前会先调用父类构造器

    调用父类构造器,输出base constructor结果

    然后再调用子类构造器,输出test constructor结果
 

public class Test {
    Person person = new Person("Test");
    static{
        System.out.println("test static");
    }

    public Test() {
        System.out.println("test constructor");
    }

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

class Person{
    static{
        System.out.println("person static");
    }
    public Person(String str) {
        System.out.println("person "+str);
    }
}


class MyClass extends Test {
    Person person = new Person("MyClass");
    static{
        System.out.println("myclass static");
    }

    public MyClass() {
        System.out.println("myclass constructor");
    }
}
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor

为什么输出结果是这样的?我们来分析下这段代码的执行过程:

  •     找到main方法入口,main方法是程序入口,但在执行main方法之前,要先加载Test类
  •     加载Test类的时候,发现Test类有static块,而是先执行static块,输出test static结果
  •     然后执行new MyClass(),执行此代码之前,先加载MyClass类,发现MyClass类继承Test类,而是要先加载Test类,Test类之前已加载
  •     加载MyClass类,发现MyClass类有static块,而是先执行static块,输出myclass static结果
  •     然后调用MyClass类的构造器生成对象,在生成对象前,需要先初始化父类Test的成员变量,而是执行Person person = new Person("Test")代码,发现Person类没有加载
  •     加载Person类,发现Person类有static块,而是先执行static块,输出person static结果
  •     接着执行Person构造器,输出person Test结果
  •     然后调用父类Test构造器,输出test constructor结果,这样就完成了父类Test的初始化了
  •     再初始化MyClass类成员变量,执行Person构造器,输出person MyClass结果
  •     最后调用MyClass类构造器,输出myclass constructor结果,这样就完成了MyClass类的初始化了
     

总结:一个类的加载顺序:静态代码块--初始化成员变量--执行构造函数

5.静态什么时候用?


1.静态变量
当分析对象中所具备的成员变量的值都是相同时, 这时这个成员就可以被静态修饰。
只要数据在对象中都是不同的, 就是对象的特有数据, 必须存储在对象中, 是非静态的。
如果是相同的数据, 对象不需要做修改, 只需要使用即可, 不需要存储在对象中, 定义成静态的。
2.静态函数
函数是否用静态修饰, 就参考一点, 就是该函数功能是否需要访问到对象中的特有数据。
简单点说, 从源代码看, 该功能是否需要访问非静态的成员变量, 如果需要, 该功能就是非静态的。
如果不需要, 就可以将该功能定义成静态的。 当然, 也可以定义成非静态, 但是非静态需要被对象调用。
如果没有访问特有数据的方法, 该对象的创建是没有意义。
示例
 

你可能感兴趣的:(java基础)