**09 单例设计模式、final关键字、抽象类、模板设计模式、接口 **
单例设计模式 (静态方法和属性的经典使用)
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。//比如某个核心类,很耗费资源,但只需要一个实例
单例模式有两种方式:饿汉式、懒汉式
单例模式——饿汉式实现
(1)构造器私有化 -> 防止直接new
(2)类的内部创建对象
(3)向外暴露一个静态的公共方法 getIstance
Class GirlFriend
{
privite String name;
private static GirlFriend gf = new GirlFriend("小红红");
private GirlFriend(String name)
{
this.name = name;
}
public static GirlFriend getInstance()
{
return gf;
}
}
//通过方法获取对象
GirlFriend instance = GirlFriend.getInstance();
饿汉式可能造成创建了对象,但是没有使用
单例模式——懒汉式实现
Class GirlFriend
{
privite String name;
private static GirlFriend gf;
private GirlFriend(String name)
{
this.name = name;
}
public static GirlFriend getInstance()
{
if(gf == null) //如果没有创建cat对象
{
gf = new GirlFriend("小红红");
}
return gf;
}
}
- 二者最主要的区别在于创建对象的时机不同:饿汉式在类加载时就创建了对象实例,而懒汉式是在使用是才创建。
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
- 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
- java.lang.Runtime就是经典的单例模式。
final关键字
final 可以修饰类、属性、方法和局部变量。在某些情况下,可能有以下需求,就会使用到final:
1)当不希望类被继承时,可能用final修饰。
2)当不希望父类的某个方法被子类覆盖/重写时,可以用final修饰。
3)当不希望类的某个属性的值被修改,可以用final修饰。
4)当不希望某个局部变量被修改,可以使用final修饰。
使用细节
- final修饰的属性又叫常量,一般用 XX_XX_XX 来命名
- final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以再如下位置之一:
定义时;
构造器中;(当final修饰的属性同时也是static时,不能再构造器中赋值)
在代码块中; - 包装类,Sring都是final类,不能被继承
- final 和 static 搭配使用,效率更高
// situation 1
class BBB
{
public static int num = 1000;
static
{
System.out.println("BBB 静态代码块被执行");
}
}
// situation 2
class BBB
{
public final static int num = 1000;
static
{
System.out.println("BBB 静态代码块被执行");
}
}
执行
System.out.println(BBB.num)
// situation1: BBB 静态代码块被执行,1000
// situation2:1000
// final 和 static 搭配使用,效率更高,不会导致类加载,底层编译器做了优化
抽象类
当父类的某些方法,需要声明,但又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类。
使用细节
- 一旦类里包含了抽象方法,这个类必须声明为抽象类;
- 抽象类里则可以不包含抽象方法;
- 抽象类本质还是类,可以拥有任意成员,比如,非抽象方法、构造器、静态属性等等;
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。
- 抽象方法不能使用private、final 和 static 来修饰,因为这些关键字都是和重写相违背的。
abstract class Animal // 抽象类
{
String name;
int age;
abstract public void cry(); //抽象方法,没有方法体
}
模板设计模式(抽象类最佳实践)
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
1)当功能内部一部分实现是确定的,一部分实现是不确定的。这是可以把不确定的部分暴露出去,让子类去实现。
2)编写一个父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其他子类实现,就是一种模板模式。
接口
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来。
语法:
interface 接口名
{
// 属性
// 抽象方法
}
class 类名 implements 接口
{
自己属性;
自己方法;
必须实现的接口的抽象方法
}
说明:
1)在jdk7以前,接口里的所有方法都没有方法体,即都是抽象方法。
2)jdk8后接口可以有静态方法、默认方法,也就是说接口中可以有方法的具体实现。
3)接口不能被实例化。
4)接口中所有的方法是public方法,接口中抽象方法可以不用 abstract 修饰。
5)一个普通类实现接口,就必须将该接口的所有方法都实现。
6)抽象类实现接口,可以不用实现接口的方法。
7)一个类可以实现多个接口。
8)接口中的属性,只能是final的,而且是 public static final 修饰符。
9)接口中属性的访问形式:接口名.属性名
10)接口不能继承其它的类,但是可以继承多个别的接口。(extends)
11)接口的修饰符,只能是 public 和 默认。
interface A
{
int a = 23;
}
class B implements A
{
}
main中:
B b = new B(); // OK
System.out.println(b.a); //23
System.out.println(A.a); //23
System.out.println(B.a); //23
接口 vs 继承类
- 当子类继承了父类,就自动拥有父类的功能。
- 如果子类需要扩展功能,可以通过实现接口的方式扩展。
- 可以理解为,实现接口,是对Java单继承机制的一种补充。
继承的价值主要在于:解决代码的复用性和可维护性。“is - a”
接口的价值主要在于:设计好各种规范(方法)。让其它类去实现这些方法。即更加的灵活。“like - a”
接口在一定长度上实现代码解耦 [即:接口规范性 + 动态绑定机制]
接口多态特性
1)多态参数。当参数类型为接口类时,实参可以为实现该接口的任意类。(接口类型的变量可以指向实现了该接口的类的对象实例)
2)多态数组。
3) 多态传递现象。