java-单列模式-final-枚举
内存存储区域
引用变量和普通变量
引用变量放在栈中,基本数据类型的内容是在堆内存中。
对象
放在堆内存中,其引用变量放在栈中,指向堆内存存放对象的地址。
静态变量
放在静态区中,静态变量在程序的执行始中中分配一次,但可改变值,常可作计数器用。
单例模式
什么是单例模式
单例模式指的是在应用整个生命周期内只能存在一个实例。单例模式是一种被广泛使用的设计模式。他有很多好处,能够避免实例对象的重复创建,减少创建实例的系统开销,节省内存。
单例模式和静态类的区别
首先理解一下什么是静态类,静态类就是一个类里面都是静态方法和静态field,构造器被private修饰,因此不能被实例化。Math类就是一个静态类。
Math类:
public static final double PI = 3.14159265358979323846;
知道了什么是静态类后,来说一下他们两者之间的区别:
1)首先单例模式会提供给你一个全局唯一的对象,静态类只是提供给你很多静态方法,这些方法不用创建对象,通过类就可以直接调用;
2)单例模式的灵活性更高,方法可以被override,因为静态类都是静态方法,所以不能被override;
3)如果是一个非常重的对象,单例模式可以懒加载,静态类就无法做到;
那么时候时候应该用静态类,什么时候应该用单例模式呢?首先如果你只是想使用一些工具方法,那么最好用静态类,静态类比单例类更快,因为静态的绑定是在编译期进行的。如果你要维护状态信息,或者访问资源时,应该选用单例模式。还可以这样说,当你需要面向对象的能力时(比如继承、多态)时,选用单例类,当你仅仅是提供一些方法时选用静态类。
如何实现单例模式
- 饿汉模式
所谓饿汉模式就是立即加载,一般情况下再调用getInstancef方法之前就已经产生了实例,也就是在类加载的时候已经产生了。这种模式的缺点很明显,就是占用资源,当单例类很大的时候,其实我们是想使用的时候再产生实例。因此这种方式适合占用资源少,在初始化的时候就会被用到的类。
class SingletonHungary {private static SingletonHungary singletonHungary = new SingletonHungary();//将构造器设置为private禁止通过new进行实例化private SingletonHungary() {}public static SingletonHungary getInstance() {return singletonHungary;}
}
懒汉模式
懒汉模式就是延迟加载,也叫懒加载。在程序需要用到的时候再创建实例,这样保证了内存不会被浪费。针对懒汉模式,我们暂时给出了1种最简单实现方式,有线程安全的问题,我们在学习多线程后,在完善这里的写法:
class SingletonLazy1 {private static SingletonLazy1 singletonLazy;private SingletonLazy1() {}public static SingletonLazy1 getInstance() {if (null == singletonLazy) {singletonLazy = new SingletonLazy1();}return singletonLazy;}
}
学到这里,你可能会对设计模式感到难以理解,单列模式其实就是一种最常用的设计模式。
设计模式(Design pattern)
代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
现阶段的你,我的意见或者经验就是,不懂先记住,留待以后随着学习的知识越来越多,越来越深入后慢慢理解!
final,static关键字
final表面意思就是不可更改的,恒量的意思;指的是无法改变的量,这与静态标量static是有区别的,静态变量指的是只有一份存储空间,值是可以改变的。使用final一定原因是出于软件设计的角度,因为别人看到final这个关键字就知道是什么意思,达到心领神会的效果,但也正是由于这种"语义"的存在,在程序设计中要谨慎使用,以免误用。
在Java中final修饰的就是常量,而且变量名要大写;
Math类:
public static final double PI = 3.14159265358979323846;
......java源码中好多变量都用final修饰
final的作用
final根据修饰位置的不同作用也不相同,针对三种情况:
- 修饰变量,被final修饰的变量必须要初始化,赋初值后不能再重新赋值。注意:局部变量不在我们讨论的范畴,因为局部变量本身就有作用范围,不使用private、public等词修饰。虽然final可以修饰局部变量,但是一般情况下,我们在实际应用中几乎不会这么干!没多大的意义!
- 修饰方法,被final修饰的方法代表不能重写。
- 修饰类,被final修饰的类,不能够被继承。
注意:final修饰的类,类中的所有成员方法都被隐式地指定为final方法。
final修饰变量
被final修饰的变量必须显示的初始化,初始化可以以三种方式:1)定义时初始化,2)在构造器中设置值,3)在非静态块中为final实例变量设置值。
final修饰变量指的是:这个变量被初始化后便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可变,即不能再指向其他的对象。
public class FinalTest {//直接赋值final int x1= 10000;final int x2;final int x3;//初始化块中 {x2 = 20000;}//构造器中 public FinalTest() {this.x3 = 3000;}}
final和static的区别
static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变,看一下例子:
public class Test {public static void main(String[] args) {MyClass myClass1 = new MyClass();MyClass myClass2 = new MyClass();System.out.println(myClass1.i);System.out.println(myClass1.j);System.out.println(myClass2.i);System.out.println(myClass2.j);//myClass1.i = 1233; //这里不可以改的}
}
class MyClass {public final double i = Math.random();public static double j = Math.random();
}
--------------------------------------------------------------------
//由于i是两个对象的成员,所以值不一样,并不是说它可以改final变量
//j是程序一加载到JVM中,只初始分配一次,后面不管创建多少对象,都是共享这一块内存
0.2356062719054033
0.7981894049184048
0.7240468555989844
0.7981894049184048
基于final和static的特性,我们往往在实际的程序开发中,需要要给全局范围内的常数,一般定义为:如
public static final int CHANGSHU=100;
枚举
理解枚举类型
枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。下面先来看看如何写一个枚举?
枚举的定义语法
在没有枚举类型时定义常量常见的方式
public class DayDemo {public static final int MONDAY =1;public static final int TUESDAY=2;public static final int WEDNESDAY=3;public static final int THURSDAY=4;public static final int FRIDAY=5;public static final int SATURDAY=6;public static final int SUNDAY=7;
}
上述的常量定义常量的方式称为int枚举模式,这样的定义方式并没有什么错,但它存在许多不足,如在类型安全和使用方便性上并没有多少好处,如果存在定义int值相同的变量,容易混淆,因此这种方式在枚举出现后并不提倡,现在我们利用枚举类型来重新定义上述的常量,定义周一到周日的常量
枚举类型,使用关键字enum
enum Day {MONDAY, TUESDAY, WEDNESDAY,THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
相当简洁,在定义枚举类型时我们使用的关键字是enum,与class关键字类似,只不过前者是定义枚举类型,后者是定义类类型。
枚举类型Day中分别定义了从周一到周日的值,这里要注意,值一般是大写的字母,多个值之间以逗号分隔。同时我们应该知道的是枚举类型可以像类(class)类型一样,定义为一个单独的文件,当然也可以定义在其他类内部,更重要的是枚举常量在类型安全性和便捷性都很有保证,如果出现类型问题编译器也会提示我们改进,但务必记住枚举表示的类型其取值是必须有限的,也就是说每个值都是可以枚举出来的,比如上述描述的一周共有七天。
写好后该如何使用呢?如下:
enum Day {MONDAY, TUESDAY, WEDNESDAY,THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class EnumDemo {public static void main(String[] args){//直接引用Day day =Day.MONDAY;}
}
就像上述代码那样,直接引用枚举的值即可,这便是枚举类型的最简单模型。