我对 static 关键字一无所知

static 关键字相信大家在初学编程语言的时候都会遇到,但是你真的了解它吗?

先给大家一个例子,请你观察他的运行结果

public class Test {
	//静态代码块
	static {
		System.out.print("we ");
	}
	//构造代码块
	{
		System.out.print("are ");
	}
	//构造方法
	public Test() {
		System.out.print("family");
	}
	//入口函数
	public static void main(String[] args) {
		new Test();
	}
}

相信大家看完自己都能够得到答案。没错,答案就是“we are family”。那么为什么是这个答案呢?

要想知道这个就得首先知道三个概念:构造方法构造代码块静态代码块

构造方法 就是用于初始化一个类中的成员变量的方法,在使用 new 关键字创造类的同时就会自定的调用构造方法。

构造代码块 提到构造,那么他就是在构造这个类的时候被调用的,而且只会被调用一次,他是在构造方法之前执行的。

静态代码块 静态代码快和构造代码块就少了一个 static 关键字,但是他们两个是完全不同的概念,静态代码块是类被加载的时候就会执行,上面的构造方法和构造代码块都是在创建对象的时候才会被执行,并且静态代码块优先于各种代码块以及构造函数。

所以上面程序的执行顺序就是:静态代码块 →构造代码块→构造方法

下面来深究一下 static 关键字

在《Java编程思想》P86页有这样一段话:“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”

 从上面这段话我们可以提炼出来他的主要功能:不创建任何对象,通过类本身就可以调用

这就是 static 的强大之处

1. 静态变量

static 变量又称静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

static成员变量的初始化顺序按照定义的顺序进行初始化。

2. 静态代码块

静态代码块指的就是在加载这个类的同时并执行的方法,并且只执行一次,通常用作优化。static 可以用在类中的任何地方。如果一个类中有多个静态代码块,他会按照static块的顺序来执行每个static块,并且只会执行一次。

3. 静态方法

静态方法指的是在一个成员方法的前面加上 static 关键字,那么它就变成了静态方法。静态方法不依托于类对象,也就是不需要创建类对象就可以调用它。类中可以有多个静态方法。

4. 常见误区

1)在C/C++中 static 是可以作用域局部变量的,但是在Java中切记:static 是不允许用来修饰局部变量。这是 Java 的规定。

2)在C/C++中 static 关键字会提升变量或者的作用域,但是在 Java 中的 static 关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有 private、public、protected(包括包访问权限)这几个关键字。

3)Java 中的静态方法是可以被 this 关键字调用的,但是不推荐使用,一般 this 关键字指的就是对象本身,而 static 方法属于那个类生成的对象,所以可以被调用,但是又因为 static 本身的特殊性,所以还是推荐大家使用 类名.静态方法 的方式去调用

5. 面试经典题型

1)下面这段代码的输出结果是什么?

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");
    }
}

先来分析一下:首先最早应该执行的是 主函数 main 方法,发现需要创建了 Test 对象,那么就要去加载 Test 这个类里面的内容,发现他有继承的关系,那么应该先加载他的父类 Base ,在加载 Base 的时候,发现有静态代码块,所以就会先执行它的静态代码块,执行完毕以后,接着加载 Base 类,加载完毕以后返回 Test 类中,发现有它也静态代码块,执行代码块,加载 Test 类,全部加载完毕以后进入主函数 main 中的第一行,创建一个 Test 对象,由于 Test 继承了 Base 类,那么他就需要先执行 Base 的构造方法,然后在执行 Test  的构造方法,执行完毕后 main 函数中的函数被调用完了就结束了。

所以答案是:

base static
test static
base constructor
test constructor

2. 这段代码的输出结果是什么?

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");
    }
}

执行流程:首先定位到 main 方法,需要加载 MyClass 这个类, 但是 MyClass 这个类继承了 Test 类,所以最早应该加载的是 Test 类,所以最早执行的是 Test 类中的静态构造方法,然后返回 MyClass 类,执行 MyClass 中的静态构造方法,执行完毕后初步加载完成,然后执行 new MyClass 创建对象,需要初始化父类成员变量,所以就会先执行父类中的 new Person("Test"),执行这个之前需要加载 Person 类,所以先执行了 Person 类中的静态代码块,然后执行 Person 的构造方法,执行完成后返回 Test,执行 Test 的构造方法,都执行完毕后再返回 MyClass 类,初始化子类成员变量,需要 new Person("MyClass"),由于之前 Person 类中的静态代码块已经被执行过了,所以不需要在执行直接执行 Person 的构造方法,然后再执行子类的构造方法,执行完毕后 main 函数中的函数被调用完了就结束了。

所以答案是:

test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor

3. 这段代码的输出结果是什么?

public class Test {
     
    static{
        System.out.println("test static 1");
    }
    public static void main(String[] args) {
         
    }
     
    static{
        System.out.println("test static 2");
    }
}

答案很显然是:

test static 1
test static 2

因为虽然主函数里面没有任何语句,但是还是会输出静态代码块中的内容。

参考资料:

https://www.cnblogs.com/dolphin0520/p/3799052.html

https://www.cnblogs.com/ysocean/p/8194428.html

发布了39 篇原创文章 · 获赞 20 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/cong____cong/article/details/95045724