static关键字

一、在理解static关键字之前,首先理顺java中类的加载时机,在类初始化的时候加载类,类的初始化有以下4中常用场景来触发:
(1)用new关键字来创建该类的对象时
(2)读取该类的一个静态变量时(被final修饰的静态常量除外-编译期把结果放在常量池)
(3)设置该类的一个静态变量时(被final修饰的静态常量除外-编译期把结果放在常量池)
(4)调用该类的一个静态方法时
目前存疑点:调用该类的静态方法时,该类先初始化,但是只初始化了该类的静态变量,成员变量没有初始化。用new来创建对象时,先初始化静态变量,后初始化成员变量。
解惑:非静态资源,只有在类被创建的时候被初始化,该类对象创建一次,非静态资源初始化一次;静态资源在类初始化时只执行一次。测试代码:

public class Test {
	Book book1 = new Book("book1成员变量初始化");
	static Book book2;
	static Book book3;
	static {
		book2 = new Book("book2静态变量初始化");
		book3 = new Book("book3静态变量初始化");
	}
	Book book4 = new Book("book4成员变量初始化");
	public static void plrint() {
		System.out.println("调用plrint静态方法");
	}
	public static void main(String[] args) {
        Test.plrint();
        System.out.println("**********");
        Test a = new Test();
	}
}
class Book {
	public Book(String msg) {
		System.out.println(msg);
	}
}
/**
* 运行结果
* book3静态变量初始化
* 调用plrint静态方法
* **********
* book1成员变量初始化
* book4成员变量初始化
**/

类的初始化顺序:父类的静态资源>子类的静态资源>父类的属性值/父类普通代码块>父类的构造器>子类的属性值/子类普通代码块>子类构造器
通过上面的疑惑和解惑,理解java编程思想中关于static的一句话:static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。
用类.方法来使用类中方法,比用new创建该类对象可以减少内存的消耗。

二、static的四种用法
1.用来修饰变量
用static修饰类的属性、变量;则该属性被该类的所有对象所共享,这样不常用,因为该属性值会随着多个对象的创建产生混乱。一般搭配final关键字使用,将一个对象修饰为常量,在类的编译期时放在常量池中,常量不可改变。
2.static代码块
在程序运行的过程中,被static修饰的代码块只会被执行一次,用来加载一些静态资源,如图片等
3.静态导包
不常用;举个例子

import static com.cn.hkx.TestUtil.*;

public class Test {
    public static void main(String[] args) {
        getMsg("静态导包测试");
    }
}

package com.cn.hkx.TestUtil

public class TestUtil {
    public static void getMsg(String msg) {
        System.out.println(msg);
    }
}

使用了static关键字,而且在引入类的最后还加上了“.*”,它的作用就是将TestUtil类中的所有类方法直接导入。不同于非static导入,采用static导入包后,在不与当前类的方法名冲突的情况下,无需使用“类名.方法名”的方法去调用类方法了,直接可以采用"方法名"去调用类方法,就好像是该类自己的方法一样使用即可。
4.静态方法
常用;用static修饰的方法,在其他类中可以直接通过类名.方法名的方式来调用,常在工具类中使用static修饰常用工具方法。 静态方法中不能调用非静态变量和非静态方法,但是非静态方法中能调用静态变量和静态方法。 static的一个重要用途就是单例设计模式:

class signTest {
    private static signTest sign = null;
    private signTest(){}
    public static signTest getSignTest() {
        if (signTest == null) {
            signTest = new SignTest();
        }
    }
}

单利模式的特点是该类只能有一个实例,为了实现这一功能,必须隐藏类的构造函数,即把构造函数声明为private,并提供一个创建对象的方法,由于构造对象被声明为private,外界无法直接创建这个类型的对象,只能通过该类提供的方法来获取类的对象。

三、实例构造器是不是静态方法
大佬的文章,膜拜一下https://rednaxelafx.iteye.com/blog/652719
挑点我能看懂的:在Java中,“static”可以有多个意思,对方法而言,至少包括下面两点:
1、Java语言中的“static”关键字用于修饰方法时,表示“静态方法”,与“实例方法”相对。
2、在讨论方法的具体调用目标时,一个方法调用到底能否在运行前就确定一个固定的目标,是则可以进行“静态绑定”(static binding),否则需要做“运行时绑定”(runtime binding)。这与“static”关键字不是一回事。

在调用实例方法时总是把“this”作为第一个参数传入被调用方法。一个方法无论是类方法还是实例方法,其方法描述符都是一样的。“this”作为调用实例方法的一个隐式参数,不会反映在方法描述符中。

Java语言中非虚方法可以通过“静态绑定”(static binding)或者叫“早绑定”(early binding)来选择实际的调用目标——因为无法覆写,无法产生多态的效果,于是可能的调用目标总是固定的一个。虚方法则一般需要等到运行时根据“接收者”的具体类型来选择到底要调用哪个版本的方法,这个过程称为“运行时绑定”(runtime binding)或者叫“迟绑定”(late-binding)。

Java虚拟机规范第二版中定义了四种不同的字节码指令来处理Java程序中不同种类的方法的调用。包括,
· invokestatic - 用于调用类(静态)方法
· invokespecial - 用于调用实例方法,特化于super方法调用、private方法调用与构造器调用
· invokevirtual - 用于调用一般实例方法(包括声明为final但不为private的实例方法)
· invokeinterface - 用于调用接口方法
其中,invokestatic与invokespecial调用的目标必然是可以静态绑定的,因为它们都无法参与子类型多态;invokevirtual与invokeinterface的则一般需要做运行时绑定,JVM实现可以有选择的根据final或实际运行时类层次或类型反馈等信息试图进行静态绑定。

那么Java中的实例构造器是不是“静态方法”呢?从Java语言规范中给出的“静态方法”的定义来看,答案是“否”——首先从Java语言规范对“方法”的定义来说,构造器根本不是“方法”;其次,实例构造器有一个隐式参数,“this”,在实例构造器中可以访问“this”,可以通过“this”访问到正在初始化的对象实例的所有实例成员。
实例构造器无法被隐藏或覆写,不参与多态,因而可以做静态绑定。从这个意义上可以认为实例构造器是“静态”的,但这种用法与Java语言定义的“静态方法”是两码事。

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