一、static简介
- 在Java中内存分为栈内存和堆内存,其中栈内存用来存放一些基本类型的变量、数组和对象的引用,堆内存主要存放一些对象。在JVM(虚拟机)加载一个类的时候,若该类中存在static修饰的成员变量、成员方法,则会为这些成员方法在固定的位置开辟一个固定大小的内存区域(即类被加载时,JVM可以根据类名在运行时数据区的方法区内找到它们)。
二、static如何使用
- static可以修饰成员变量、成员方法、代码块、类。当修饰对象为成员变量或者成员方法的时候可以通过类名调用。
1、static变量
- 当变量被static所修饰时,称该变量为静态变量,反之为实例变量。
区别如下:
- 静态变量在类加载时被完全初始化,它在内存中是唯一的,JVM仅为它分配一次内存。实例变量随着实例的创建而产生,与该实例同生共死。
采用静态变量的目的如下:
- 作为共享变量
- 减少对象创建的次数
- 保留唯一的副本
2、static方法
- 静态方法不依赖于任何对象访问,不存在super或this的调用。静态方法中访问非静态变量或方法,需要创建访问的对象。
- 静态成员变量的初始化顺序按照定义的顺序进行。
3、static代码块
- 静态代码块的使用可以优化程序的性能,static块可以置于类中的任何位置,同样类中可以存在多个static代码块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只执行一次。
父类
public class staticBase {
static {
System.out.println("staticBase---父类中的静态代码块加载。。。");
}
public staticBase() {
System.out.println("staticBase---父类中的构造函数加载。。。");
}
}
子类
public class staticTest extends staticBase{
public String test = "成员变量";
static {
System.out.println("staticTest---本类中的静态代码块加载。。。");
staticTest statictest = new staticTest();
System.out.println(statictest.test);
}
public staticTest() {
System.out.println("staticTest---本类中的构造方法加载。。。");
}
public static void main(String[] args) {
new staticTest();
}
}
运行结果如下:
staticBase---父类中的静态代码块加载。。。
staticTest---本类中的静态代码块加载。。。
staticBase---父类中的构造函数加载。。。
staticTest---本类中的构造方法加载。。。
成员变量
staticBase---父类中的构造函数加载。。。
staticTest---本类中的构造方法加载。。。
解析:
- 在子类staticTest不生成实例的情况下(子类本身无构造方法重写和静态代码块),运行时只会执行父类的静态代码块。
- 在子类staticTest生成实例的情况下,父类的构造方法被调用且静态代码块也被执行。
- 运行结果的解析:子类和父类的构造方法均被重写,在staticTest生成实例的时候分别调用了父类staticBase和自身的构造方法。在static块中调用非静态的成员变量,需要生成对象的实例才能完成调用。在生成子类对象staticTest的实例的过程中,分别调用了父类对象和自身的构造方法。当类被加载的时候,静态代码块只执行一次,所以第二次生成对象的实例的时候,运行结果没有出现父类和子类静态代码块的打印信息。
- 执行顺序:父类静态代码块 ->子类静态代码块 ->父类构造方法 ->子类构造方法 ->子类静态代码块中访问非静态成员变量,通过生成子类实例访问。->生成子类实例的过程中分别调用了父类和子类的构造方法。
静态内部类
-
静态内部类可以声明:静态变量、静态常量、普通变量、普通常量。
-
静态内部类不能直接访问外部类中的非静态变量或常量,需要生成外部类的实例对象,才能调用。
-
静态内部类可以直接调用外部类的构造方法、静态方法
外部类调用静态内部类的两种情况
情况一
public class Outter { private static final String static_final_outter = "外部类-静态-常量"; private static String static_outter = "外部类-静态-变量"; private final String final_outter = "外部类-常量"; private String com_outter = "外部类-变量"; // 外部类无参构造 public Outter(String show) { System.out.println("外部类-构造方法"+show); } // 外部类普通方法 public void outterComMethod() { System.out.println("外部类-普通方法"); } // 外部类静态方法 public static void outterStaticMethod(String show) { System.out.println("外部类-静态方法"+show); } // 静态内部类 public static class Inner{ static final String static_final_inner = "内部类-静态-常量"; static String static_inner = "内部类-静态-变量"; private final String final_inner = "内部类-常量"; private String com_inner = "内部类-变量"; // 内部类无参构造 public Inner() { System.out.println("内部类-无参构造"); } // 内部类普通方法 public void inenerComMethod() { System.out.println("内部类-普通方法"); } // 内部类静态方法 public static void inenerStaticMethod(String show) { System.out.println("内部类-静态方法"+show); } // 内部类访问外部类 public void getOutter() { System.out.println(static_final_outter+"-被内部类Inner调用"); System.out.println(static_outter+"-被内部类Inner调用"); new Outter("-被内部类Inner调用"); outterStaticMethod("-被内部类Inner调用"); // new Outter("").outterComMethod(); // 如下不能直接调用,可生成外部类的实例对象调用 // System.out.println(new Outter("").final_outter+"-被内部类Inner调用"); // System.out.println(new Outter("").com_outter+"-被内部类Inner调用"); } } public static void main(String[] args) { // 本类外部类调用内部类 new Inner().getOutter(); //在外部类中调用内部类的构造方法 new Inner(); //外部类调用内部类的静态常量、静态变量、静态方法 System.out.println(Inner.static_final_inner+"-被外部类Outter调用"); System.out.println(Inner.static_inner+"-被外部类Outter调用"); Inner.inenerStaticMethod("-被外部类Outter调用"); new Inner().inenerComMethod(); } }
运行结果如下
内部类-无参构造 外部类-静态-常量-被内部类Inner调用 外部类-静态-变量-被内部类Inner调用 外部类-构造方法-被内部类Inner调用 外部类-静态方法-被内部类Inner调用 内部类-无参构造 内部类-静态-常量-被外部类Outter调用 内部类-静态-变量-被外部类Outter调用 内部类-静态方法-被外部类Outter调用 内部类-无参构造 内部类-普通方法
情况二
import info.StaticFather;
public class Base {
public static void main(String[] args) {
// 外部类调用静态内部类
Outter.Inner oi = new Outter.Inner();
oi.getOutter();
//在外部类中调用内部类的构造方法
new Outter.Inner();
//外部类调用内部类的静态常量、静态变量、静态方法
System.out.println(Outter.Inner.static_final_inner+"-被外部类Outter调用");
System.out.println(Outter.Inner.static_inner+"-被外部类Outter调用");
Outter.Inner.inenerStaticMethod("-被外部类Outter调用");
oi.inenerComMethod();
}
}
运行结果如下
内部类-无参构造
外部类-静态-常量-被内部类Inner调用
外部类-静态-变量-被内部类Inner调用
外部类-构造方法-被内部类Inner调用
外部类-静态方法-被内部类Inner调用
内部类-无参构造
内部类-静态-常量-被外部类Outter调用
内部类-静态-变量-被外部类Outter调用
内部类-静态方法-被外部类Outter调用
内部类-普通方法