static关键字与单例模式
可以修饰属性变量,方法和代码段
-
static修饰的属性称为静态属性或类属性, 在类加载时就在方法区为属性开辟存储空间,无论创建多少个对象,静态属性在内存中只有一份。
可以使用 类名.静态属性 的方式引用
-
static修饰的方法称为静态方法或类方法,在类加载时就在方法区中开辟存储空间,存储方法中信息,在调用静态方法时,不会默认传递this参数。static修饰的属性和方法会在类加载的时候在内存中开辟空间
可以使用 类名.方法() 的方式引用
-
static修饰的代码段称为静态代码段,在类加载时就自动执行,且仅执行一次。
一般初始化操作可以写在静态代码段中。
1.1 对象属性与静态属性
class A{
int i ;
static int j ;
}
class Test{
main(){
A a= new A();
a.i = 10 ;
A.j = 20 ;
a.j = 20 ;
}
}
-
对象属性:只有创建对象,才能引用。
-
静态属性:可以通过类名直接引用。不需要创建对象。 通过对象也可以引用。
类加载时开辟存储空间, 只有一份, 可以数据共享。
1.2 对象方法与静态方法
特点1
无论是静态方法还是对象方法,都是在类加载的时候,就在方法区中分配了存储空间
无论创建多少个对象,方法在内存中只存储一次。
特点2
在使用上, 对象方法的使用,必须先创建对象,才能调用。
而静态方法,可以通过类名直接调用
特点3
尽然对象方法在内存中只有1份,怎么做到不同对象调用,可以访问不同对象的属性呢?
-
当通过对象调用对象方法时,会默认传递一个参数,这个实参就是当前对象的地址。这个形参就是this
-
当通过类调用类方法时,就不会传递对象地址(此时没有对象),静态方法也没有this这个默认参数
简单来说,对象方法和静态方法的区别就在于是否需要引用对象自己的属性变量。
扩展1
静态方法中,不能使用this关键字。(压根就没有)
静态方法中只能直接使用静态成员(属性和方法),不能直接使用非静态成员。
在对象方法中,可以使用对象成员,也可以使用静态成员。
扩展2
对象方法中会有一个默认的参数叫this,存储的是调用当前方法的那个对象的地址
所以可以通过this,访问指定对象的属性。
默认情况下,访问对象的属性和其他方法时,jvm会自动的根据this的地址访问,而不需要编码时必须使用this关键字
class A{
int i ;
public void t1(){
i = 20 ; //等价于 this.i = 20 ;
}
}
什么情况下必须写this呢?
-
局部变量与属性变量同名时,默认引用的是局部变量
-
调用重载的构造方法的时候
扩展3
方法到底是如何起作用的,以及有与属性同名的变量和没有同名变量的引用过程
1.3 对象代码段和静态代码段
什么是代码段?
-
就是个{} 里面包含一堆代码
-
代码段可以写在方法中 , 也可以写在方法外
-
代码段可以方法中和方法外独立存在,也可以配合着 分支结构和循环结构存在
class A{
{
.....
}
public void t1(){
{
.....
}
}
public void t2(){
if(){
System.out.println()
System.out.println()
System.out.println()
System.out.println()
}
while(){}
}
}
方法外的代码段
-
写在方法外,但要写在类里。
-
可以是普通的代码段,也可以是增加了static关键字修饰的代码段
-
前者就称为对象代码段(普通代码段), 后者称为静态代码段
-
对象代码段,在创建对象时,自动执行,每个对象的创建仅执行一次。
如果创建多个对象,这个代码段就会被执行多次。
-
静态代码段,在类加载时,自动执行,且仅执行一次
-
class A{ { ... } static{ ... } }
扩展
java类在编译时,会自动的提供两种初始化方法
-
<init> 对象的初始化方法 。 其内容来自于构造方法和对象代码段, 如果有构造方法重载的,就会有多个对象初始化方法
-
<clinit>类的初始化方法。没有专门的对应的方法,方法的内容就是静态代码段的内容。
2 单例模式
单例模式是一种设计模式
什么是设计模式?
-
是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结
设计模式主要分为3大类
-
创建型 : 如何创建对象 , 例如单例模式,如何只创建一个对象。
-
结构型 : 设计不同的执行结构,适合不同的执行场景。 暂不解释。
-
行为型 : 与具体的行为操作有关,例如策略模式,如何根据不同的策略完成功能。
单例模式特点
-
确保在jvm内存中,或在程序执行的过程中,某一个类只会产生一个对象。
-
重点在于是否能想明白 为什么只需要对象创建一次,而不在于如何实现对象只创建一次。
单例模式的实现
-
需要构造方法私有化。 不再使用public修饰构造方法,改用private修饰构造方法
private修饰的方法或者属性只有类自己可以使用。外部类不能使用。
-
定义一个属性,来存储类自身创建的对象
类自身只创建一次
-
提供一个方法,外部使用者可以通过调用这个方法,获得刚刚存入属性中的那个对象
class D{
private D(){}
static D d = new D();
public static D getD(){
return d ;
}
//-----------------------
//属性
-
-
由于外部类调用这个方法的时候,还没拥有D对象, 所以只能通过类调用这个方法。
所以这个方法应该是static方法
-
static方法中不能直接使用非静态的属性,
所以d属性应该也是静态的
-
注意:
单例模式的设计与类对象应该具备哪些属性和方法无关。
扩展:懒汉式和饿汉式
-
饿汉式的单例模式:在类加载时就完成对象的创建,并将其存入属性变量
特点:空间换时间
class D{
private D(){}
static D d = new D();
public static D getD(){
return d ;
}
}
懒汉式的单例模式:在类加载时先不创建对象, 第一次请求对象时再创建对象
特点:时间换空间
class D{
private D(){}
static D d ;
public static D getD(){
if(d == null){
//还没有创建呢
d = new D();
}
return d ;
}
}
```