一、理解类成员
▲static不要理解为静态的意思,static是类的意思,有static修饰的成员是类成员,没有static修饰的成员是实例变量。
static不能修饰局部变量,局部变量不属于类成员。
static不能修饰外部类,外部类不属于类成员。
类的定义:public(final|abstatct) 类名{...}
类的成员:成员变量、方法、构造器、内部类、初始化块。static修饰类成员,除了构造器以外,其他类成员都可以修饰。
类成员属于整个类,当系统第一次准备使用该类的时候,系统会为该类分配内存空间,类变量开始初始化,知道该类被卸载,该类变量所占的内存被GC回收。不管通过类还是对象来访问类成员,实际上都是通过类来访问类成员,同一类所有实例的类变量共享同一块内存区。(为了理解,类成员最好用类来访问)。
因为类成员属于类,类成员的作用域作用域比实例变量作用域大,完全可能出现类成员已经初始化完成,实例成员还未进行初始化的情况,如果允许类成员来范文实例变量将会引起大量错误。所有static有一条重要的规则:类成员(成员变量、方法、内部类、初始化块(内部枚举枚举))不能访问实例成员(成员变量、方法、构造器、内部类、初始化块(内部枚举枚举))。
从上图可以看出,有20种情况会报错:无法从静态上下文访问非静态 变量
1、从类方法访问实例方法
1 class 面试题1 2 { 3 public void info() 4 { 5 System.out.println("这是实例(非静态)方法"); 6 } 7 public static void main(String[] args) 8 { 9 var p=new 面试题1();//这是实例(非静态)方法 10 p.info(); 11 info();//面试题1.java:11: 错误: 无法从静态上下文中引用非静态 方法 info() 12 } 13 }
2、从类方法访问非静态内部类
1 class 面试题2 2 { 3 class A 4 { 5 public void info() 6 { 7 System.out.println("这是一个非静态的内部类"); 8 } 9 } 10 public static void main(String[] args) 11 { 12 A obj=new A();//面试题2.java:12: 错误: 无法从静态上下文中引用非静态 变量 this 13 } 14 }
3、类成员变量访问实例变量
1 class 面试题3 2 { 3 int a=5; 4 static int b=a;//面试题3.java:4: 错误: 无法从静态上下文中引用非静态 变量 a 5 }
4、静态初始化块访问实例成员
1 class 面试题4 2 { 3 int age; 4 static{ 5 age=18;//面试题4.java:5: 错误: 无法从静态上下文中引用非静态 变量 age 6 } 7 }
5、类初始化块调用内部类
1 class 面试题5 2 { 3 class A 4 { 5 } 6 static{ 7 A obj=new A();//面试题5.java:7: 错误: 无法从静态上下文中引用非静态 变量 this 8 } 9 }
二、单例(Singleton)类
在某些情况下,允许其他类自由创建该类的对象没有任何意义,还可能造成系统性能下降(因为频繁地创建对象,回收对象带来的系统开销问题),例如只能有一个窗口管理器、一个数据库引擎访问点。
设计模式:对于一些经常出现的设计场景,前人总结出的一些成功的设计。
单例模式:在某些场景下,某些类只需创建一个实例。
如何设计单例模式?
一、隐藏构造器避免被创建实例
二、暴露一个static方法用于创建实例
三、保存实例,记录是否已经创建过实例。
1 class Singleton 2 { 3 //使用一个类变量来缓存曾经创建过的实例 4 private static Singleton instance; 5 //对构造器使用private修饰来隐藏构造器 6 private Singleton() 7 {} 8 9 //提供一个静态方法用于创建实例,并且控制只能产生一个实例 10 public static Singleton getInstance() 11 { 12 if(instance==null) 13 { 14 //创建一个Singleton对象 15 instance=new Singleton(); 16 } 17 return instance; 18 } 19 } 20 21 public class SingletonTest 22 { 23 public static void main(String[] args) 24 { 25 //创建Singleton对象不能调用构造器 26 Singleton s1=Singleton.getInstance(); 27 Singleton s2=Singleton.getInstance(); 28 System.out.println(s1.equals(s2)); 29 } 30 } 31 ---------- 运行Java捕获输出窗 ---------- 32 true 33 34 输出完成 (耗时 0 秒) - 正常终止