静态变量
一、概述
- 静态变量和静态方法能够通过类名来访问,不需要创建一个类的对象来访问该类的静态成员,所以static修饰的成员又称作类变量和类方法。
- 静态变量与成员变量不同,成员变量总是通过对象来访问,因为它们的值在对象之间有所不同。
- 当你的某一个变量会经常被外部代码访问的时候,可以考虑设计为静态的。
二、内存分配及初始化
- 静态变量属于类,不属于任何独立的对象。因为编译器只为整个类创建了一个静态变量的副本,也就是只分配一个内存空间。
- 静态变量在代码运行前就已经存在于内存之中,静态变量存在的意义就是不需要实例化就可以直接用类名调用。
- 成员变量则不同,每创建一个对象,都会分配一次内存空间,不同变量的内存相互独立。
- 类会在首次被“主动使用”时执行初始化,为静态变量赋予正确的初始值。在Java代码中,一个正确的初始值是通过静态变量初始化语句或者静态代码块给出的。而我们这里所说的主动使用包括:
①创建类的实例
②调用类的静态方法
③使用类的非常量静态字段
④调用Java API中的某些反射方法
⑤初始化某个类的子类
⑥含有main()方法的类启动时
PS:初始化一个类包括两个步骤:
1、 如果类存在直接父类的话,且父类还没有被初始化,则先初始化其父类。
2、 如果类存在一个初始化方法,就执行此方法。
代码示例:
public class Demo {
static int i;
int j;
public static void main(String[] args) {
Demo demo1 = new Demo();
demo1.i = 7;
demo1.j = 8;
Demo demo2 = new Demo();
System.out.println("demo1.i=" + demo1.i + ", demo1.j=" + demo1.j);
System.out.println("demo2.i=" + demo2.i + ", demo2.j=" + demo2.j);
}
}
//demo1.i=7, demo1.j=8
//demo2.i=7, demo2.j=0
可以看到demo2.i=7,这是因为demo1.i和demo2.i指的是同一块内存空间。
静态方法
一、概述及注意事项
- static方法是类的方法,不需要创建对象就可以使用。非static方法是对象的方法,只有对象被创建出来以后才可以被使用。
- static方法中不能使用this和super关键字。
- 不能调用非static方法。
- 只能访问所属类的静态变量和静态方法。因为当static方法被调用的时候,这个类的对象可能还没有创建,即使已经被创建了,也无法确认调用那个对象的方法。不能访问非静态方法同理。
二、用途
单例是运用static的一个很好的例子。
public class Singleton {
private static Singleton singleton;
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
private Singleton() {
}
}
一般工具方法都会设计成静态方法。
三、静态代码块、构造代码块
一、概述
- 构造代码块,为所有的构造器做准备工作,构造器调用之前调用。
- 静态代码块,对静态成员做准备工作(比如初始化)。 随着类的加载而加载,无论创建多少个对象,只调用一次。很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
构造代码块:
{
System.out.println("haha");
}
静态代码块就是前面加了static修饰。
二、构造代码块应用
初始化实例变量
如果一个类中存在若干个构造函数,这些构造函数都需要对实例变量进行初始化,如果我们直接在构造函数中实例化,必定会产生很多重复代码,繁琐和可读性差。这里我们可以充分利用构造代码块来实现。这是利用编译器会将构造代码块添加到每个构造函数中的特性。初始化实例环境
一个对象必须在适当的场景下才能存在,如果没有适当的场景,则就需要在创建对象时创建此场景。我们可以利用构造代码块来创建此场景,尤其是该场景的创建过程较为复杂。构造代码会在构造函数之前执行。
三、注意
- 静态代码块可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。
- 构造代码块每次创建新对象时都会执行。有多个时依次执行。
- 执行顺序:静态代码块 > 构造代码块 > 构造函数。
- 构造代码块和静态代码块有自己的作用域,作用域内部的变量不影响作用域外部。
public class Parent {
static {
System.out.println("父类静态代码块");
}
{
System.out.println("父类构造代码块");
}
public Parent(){
System.out.println("父类构造函数");
}
}
class Children extends Parent {
static {
System.out.println("子类静态代码块");
}
{
System.out.println("子类构造代码块");
}
public Children(){
System.out.println("子类构造函数");
}
public static void main(String[] args) {
new Children();
}
}
//结果:
//父类静态代码块
//子类静态代码块
//父类构造代码块
//父类构造函数
//子类构造代码块
//子类构造函数
四、扩展
创建对象的流程
-> 开辟内存
-> 静态变量显式初始化
-> 静态代码块(如果有多个的轻况,按代码的书写顺序执行)
-> 成员变量的显示初始化
-> 代码块
-> 构造函数
四、补充
- static final用来修饰成员变量和成员方法,可简单理解为“全局常量”。对于变量,表示一旦给值就不可修改;对于方法,表示不可覆盖。
- 对象也能调静态变量和静态方法,但不建议这种写法。
- Java中static只能修饰类的成员变量和方法,不能修饰方法内的局部变量。另外不能被继承,因为它仅仅属于某个类,但不是其对象。
写完喽!ㄟ(▔,▔)ㄏㄟ(▔,▔)ㄏㄟ(▔,▔)ㄏ
知识重在总结和梳理,只有不断地去学习并运用,才能化为自己的东西。当你能为别人讲明白的时候,说明自己已经掌握了。
欢迎转载,转载请注明出处!
如果有错误的地方,或者有您的见解,还请不啬赐教!
喜欢的话,麻烦点个赞!
参考://www.greatytc.com/p/3eb769986bd3