目录
学习笔记
单例与多例
单例设计模式与多例设计模式主要是一种控制实例化对象产生个数的设计操作。
单例设计
如果现在有一个程序类该程序类的定义如下:
class Singleton{
public void print(){
System.out.println("测试") ;
}
}
public class JavaDemo{
public static void main(String[] args){
Singleton instanceA = new Singleton() ;
Singleton instanceB = new Singleton() ;
Singleton instanceC = new Singleton() ;
Singleton instanceD = new Singleton() ;
instanceA.print() ;
instanceB.print() ;
instanceC.print() ;
instanceD.print() ;
}
}
但是由于某些要求,现在要求Singleton这个类只允许提供有一个实例化对象。那么此时应该控制构造方法。因为新的实例化对象产生一定调用构造方法,如果构造方法“没有了”,那么就无法产生实例化对象。
范例:构造方法私有化
class Singleton{
private Singleton(){} ; // 构造方法私有化
public void print(){
System.out.println("测试") ;
}
}
public class JavaDemo{
public static void main(String[] args){
Singleton instance = null ; // 声明对像
instance = new Singleton() ; // 对象实例化 JavaDemo.java:11: 错误: Singleton() 在 Singleton 中是 private 访问控制
}
}
但是要求是:必须产生一个实例化对象,现在必须产生一个是实例化对象交给客户端去调用。那么这个时候的分析如下:
1、private访问权限的主要特点在于:不能在类外部访问,但是可以在类的内部访问构造。
class Singleton{
private Singleton instance = new Singleton() ;
private Singleton(){} ; // 构造方法私有化
public void print(){
System.out.println("测试") ;
}
}
public class JavaDemo{
public static void main(String[] args){
Singleton instance = null ; // 声明对像
instance = new Singleton() ; // 对象实例化
}
}
2、 此时Singleton类内部的instance属于一个普通属性,而普通属性是在有实例化对象产生之后才会被调用的,那么这个时候外部无法产生实例化对象,所以这个属性就不能访问到了,那么就必须考虑没有实例化对象的时候访问此属性,那么只有static属性可以做到。
class Singleton{
static Singleton instance = new Singleton() ;
private Singleton(){} ; // 构造方法私有化
public void print(){
System.out.println("测试") ;
}
}
public class JavaDemo{
public static void main(String[] args){
Singleton instance = null ; // 声明对像
instance = Singleton.instance ; // 对象实例化
instance.print() ;
}
}
3、类中的属性应该封装后使用,所以理论上此时的instance需要被封装起来,那么就需要通过一个static方法获得。
class Singleton{
private static Singleton instance = new Singleton() ;
private Singleton(){} ; // 构造方法私有化
public static Singleton getInstance(){
return instance ; // 不能加this
}
public void print(){
System.out.println("测试") ;
}
}
public class JavaDemo{
public static void main(String[] args){
Singleton instance = null ; // 声明对像
instance = Singleton.getInstance() ;
instance.print() ;
}
}
4、整个代码强调的时只有一个实例化对象,这个时候虽然提供有static的实例化对象,但是这个对象依然可以重新实例化,所以需要保证此时singleton类内部的instance无法再次实例化,那么应该使用final定义。
class Singleton{
private static final Singleton INSTANCE = new Singleton() ;
private Singleton(){} ; // 构造方法私有化
public static Singleton getInstance(){
return INSTANCE ; // 不能加this
}
public void print(){
System.out.println("测试") ;
}
}
public class JavaDemo{
public static void main(String[] args){
Singleton instance = null ; // 声明对像
instance = Singleton.getInstance() ;
instance.print() ;
}
}
在很多情况下有些类的是不需要重复产生对象的,如果:如果一个程序启动,那么现在肯定有一个类负责保存一些有一些程序加载的数据信息。
对于单例设计模式也分为两种:懒汉式、饿汉式。在之前所定义的属于饿汉式。在系统加载类的时候就提供Singleton类的实例化对象,而还有一种懒汉式是第一次使用的时候进行实例化对象处理。
范例:将单例修改为懒汉式
class Singleton{
private static Singleton instance ;
private Singleton(){} ; // 构造方法私有化
public static Singleton getInstance(){
if (instance == null){ // 第一次使用
instance = new Singleton() ; //实例化
}
return instance ; // 不能加this
}
public void print(){
System.out.println("测试") ;
}
}
public class JavaDemo{
public static void main(String[] args){
Singleton instance = null ; // 声明对像
instance = Singleton.getInstance() ;
instance.print() ;
}
}
面试题:请编写一个Singleton程序,并说明组要特点?
-
代码如上,可以把懒汉式(后面还要考虑线程的同步问题)和饿汉式都写上。
-
特点:构造方法私有化,类内部提供static方法获取实例化对象,不挂外部如何操作永远都只有一个是实例化对象提供。
多例设计
与单例设计对应的还有多例设计,单例是指只保留一个实例化对象,多例则是保留多个实例化对象。例如:如果要定义一个描述性别的类,那么该对象只能产生来两个:男、女。或者描述颜色基色的类:红、绿、蓝。这种情况下,使用多例设计。
class Color{ // 定义描述颜色的类
private static final Color RED = new Color("红色") ;
private static final Color GREEN = new Color("绿色") ;
private static final Color BLUE = new Color("蓝色") ;
private String title ;
private Color(String title){ // 构造方法私有化
this.title = title ;
}
public static Color getInstance(String color){
switch(color){
case "红色": {
return RED ;
}
case "绿色": {
return GREEN ;
}
case "蓝色":{
return BLUE ;
}
default: return null ;
}
}
public String toString(){
return this.title ;
}
}
public class JavaDemo{
public static void main(String[] args){
Color instance = null ;
Color red = instance.getInstance("红色") ;
System.out.println(red.toString()) ;
Color green = instance.getInstance("绿色") ;
System.out.println(green) ; // 自动调用toString
Color blue = Color.getInstance("蓝色") ;
System.out.println(blue) ;
}
}
多例设计与单例设计的本质是相同的,一定都会在内部提供static方法以返回实例化对象。构造方法私有化,不仅仅是private,只要不是public都是私有化。
枚举
很多的编程语言都会提供枚举的概念,但是Java到JDK1.5之后才提出了枚举的概念。在实际的开发之中,用于定义有限个数对象的一种结构(多例设计),枚举属于多例设计,但其结构比多例设计简单。
枚举的基本定义
从JDK1.5之后提供有enum的关键字,利用此关键字可以实现枚举的定义。
范例:定义一个枚举
enum Color{ // 定义枚举类
RED, GREEN, BLUE ; // 实例化对象
}
public class JavaDemo{
public static void main(String[] args){
Color c = Color.RED ; // 实例化对象
System.out.println(c) ;
}
}
这个代码实现多例设计中的问题。还可以使用中文
enum Color{ // 定义枚举类
红色, 绿色, 蓝色 ; // 实例化对象
}
public class JavaDemo{
public static void main(String[] args){
Color c = Color.红色 ; // 实例化对象
System.out.println(c) ;
}
}
如果此时采用多例模式来设计,会多出很多代码,这样对于开发的复杂度是比较高的,因为里面毕竟涉及到构造方法的私有化和静态方法。多例设计与枚举设计虽然可以实现相同的功能,但是使用枚举可以在程序编译的时候判断所使用的实例化对象是否存在。
在进行枚举处理的时候,可以使用values()方法获取所有的枚举对象进行输出。
范例:获取所有枚举对象
enum Color{ // 定义枚举类
红色, 绿色, 蓝色 ; // 实例化对象
}
public class JavaDemo{
public static void main(String[] args){
for(Color c : Color.values()){
System.out.println(c) ;
}
}
}
在多例中如何获取所有对象方式,使用对象数组。
从JDK1.5追加了枚举结构之后,就可以使用switch之中的枚举像进行判断。
范例:观察枚举与switch处理
enum Color{ // 定义枚举类
RED, GREEN, BLUE ; // 实例化对象
}
public class JavaDemo{
public static void main(String[] args){
Color c = Color.RED ;
switch (c){
case RED :{
System.out.println("红色") ;
break ;
}
case GREEN:{
System.out.println("绿色") ;
break ;
}
case BLUE:{
System.out.println("蓝色") ;
break ;
}
}
}
}
多例上是无法实现与switch的直接连接的,多例要想实现它需要编写大量的if 判断。
Enum类
严格意义上讲枚举不属于一种新的结构,它的本质相当于一个类,但是这个类默认会继承Enum类。
观察Enum类的定义:
public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable
现在定义的枚举类型就是Enum中使用的E类型。下面观察Enum中定义的方法。
方法名称 | 类型 | 描述 |
| 构造 | 传入名字和序号 |
| 普通 | 获得对象的名字 |
| 普通 | 获得对象的序号 |
范例:观察Enum类的存在
enum Color{ // 定义枚举类
RED, GREEN, BLUE ; // 实例化对象
}
public class JavaDemo{
public static void main(String[] args){
for(Color c : Color.values()){
System.out.println(c.name()) ;
System.out.println(c.ordinal()) ;
}
}
}
在枚举之中,每一个序号的对象都是根据枚举对象的定义顺序来决定的。
面试题:请解释Enum与enum的区别?
-
enum:是从JDK1.5过后提供的关键字,用于定义枚举类的结构;
-
Enum:是一个抽象类,所有使用所有使用enum定义的类就直接默认继承Enum类。
定义枚举结构
枚举本身就属于多例的设计模式,那么既然是多例的设计模式,那么在一个类之中可以定义的结构是非常多的,例如:构造方法、普通方法、属性等。那么这些内容在枚举中依然可以直接定义,但是需要注意的是:枚举类中的构造方法必须私有化(public无法使用)。
范例:在枚举中定义其它结构
enum Color{
RED("红色"), GREEN("绿色"), BLUE("蓝色") ; // 枚举对象必须放在首行
private String title ; // 定义属性
private Color(String title){
this.title = title ;
}
public String toString(){
return this.title ;
}
}
public class JavaDemo{
public static void main(String[] args){
for(Color c : Color.values()){
System.out.println(c.ordinal() + "-" + c.name() + "-" + c) ;
}
}
}
本程序在简化程度上远远高于多设计模式。除了这种基本的结构之外,在枚举类中也可以实现接口的继承。
范例:让枚举实现接口
interface IMessage{
public abstract String getMessage() ;
}
enum Color implements IMessage{
RED("红色"), GREEN("绿色"), BLUE("蓝色") ; // 枚举对象必须放在首行
private String title ; // 定义属性
private Color(String title){
this.title = title ;
}
public String toString(){
return this.title ;
}
public String getMessage(){
return this.title ;
}
}
public class JavaDemo{
public static void main(String[] args){
IMessage msg = Color.RED ;
System.out.println(msg.getMessage()) ;
}
}
在枚举里面最有意思的是可以直接定义抽象方法,并且要求每一个枚举对象都要独立覆写此抽象方法。
范例:观察过枚举中定义抽象方法
enum Color{
RED("红色"){
public String getMessage(){
return this.toString() ;
}
}, GREEN("绿色"){
public String getMessage(){
return this.toString() ;
}
}, BLUE("蓝色"){
public String getMessage(){
return this.toString() ;
}
} ; // 枚举对象必须放在首行
private String title ; // 定义属性
private Color(String title){
this.title = title ;
}
public String toString(){
return this.title ;
}
public abstract String getMessage() ;
}
public class JavaDemo{
public static void main(String[] args){
System.out.println(Color.RED.getMessage()) ;
}
}
枚举的定义是非常灵活的,但是在实际应用之中,枚举更多情况下,建议使用它的正确用法,就是定义实例对象即可。
枚举应用案例
编写一个程序,观察过枚举的应用,例如:现在定义一个Person类,里面有性别,性别不希望用户随意输入,所以使用枚举最合适。
范例:使用枚举
enum Sex{
MALE("男"), FEMALE("女") ;
private String title ;
private Sex(String title){
this.title = title ;
}
public String toString(){
return this.title ;
}
}
class Person{
private String name ;
private int age ;
private Sex sex;
public Person(String name, int age, Sex sex){
this.name = name ;
this.age = age ;
this.sex = sex ;
}
public String toString(){
return "姓名:" + this.name +
"、年龄:" + this.age +
"、性别:" + this.sex ;
}
}
public class JavaDemo{
public static void main(String[] args){
Person per = new Person("张三", 18, Sex.MALE) ;
System.out.println(per) ;
}
}
这个程序不使用枚举也可以实现,追加几个判断即可,所以对于枚举,愿意用就用。