一、单例模式
单例模式是一种常用的软件设计模式,在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中应用该模式的类,一个类只能有一个实例,即一个类只有一个对象实例。
-
Java中单例模式定义:一个类有且仅有一个实例,并且自行实例化向整个系统提供。
-
构建方式:
- 懒汉模式:指全局的单例实例在第一次被使用时构建
class MySingleTon {
private static MySingleTon singleTon = null;
private MySingleTon() {
//构造方法体;
}
//提供一个全局的访问点
public static MySingleTon getInstance() {
//临界区代码段
if (singleTon == null) {
singleTon = new MySingleTon();
}
return singleTon;
}
}
- 饿汉模式:指全局的单例实例在类装载时构建
class MySingleTon2 {
private static MySingleTon2 singleTon2 = new MySingleTon2();
private MySingleTon2() {
//构造方法体
}
//提供一个全局访问点
public static MySingleTon2 getInstance() {
return singleTon2;
}
}
- 双重加锁机制:双重检验,可重入函数
class MySingleTon {
private static MySingleTon singleTon = null;
private static Object lock = new Object();
private MySingleTon() {
System.out.println("MySigleTon().init");
}
public static MySingleTon getInstance() {
if (singleTon == null) {
synchronized (lock) {
if (singleTon == null) {
singleTon = new MySingleTon();
}
}
}
return singleTon;
}
}
- 内部类实现单例模式
class MySingleTon3 {
private MySingleTon3() {
//类构造方法;
}
//只有访问静态内部类的时候才会创建对象
private static class SingleTon {
private static MySingleTon3 singleTon3 = new MySingleTon3() ;
}
public static MySingleTon3 getInstance() {
return SingleTon.singleTon3;
}
}
二、类的继承
- 继承的概念
继承是面向对象程序设计的主要特征之一,允许重用父类创建子类,子类将继承父类的suo’you数据和行为,还可以定义其他数据和行为。即子类具有两个有效类型:子类的类型以及继承的父类的类型。
- 继承的类型
Java包含两种继承类型:
- 类继承
类继承一般用于增加现有类型的功能,或许多相关的类型共享一组重要的公共功能的场合。
- 接口继承
接口继承表示一个类实现若干接口,接口仅包含方法的签名,故接口继承不继承任何实现代码。接口继承一般用于指定该类型具有某类可用的特征。
- 派生类的声明
在声明派生类时可以指定要继承的类,如果在类定义时没有指定基类,Java编译器将假定Object是基类,派生类使用关键字extends
指定要继承的类,
派生类声明的基本形式:
[类修饰符] class 类名 [extends 基类] {
//类体;
}
- super关键字
super关键字用于从派生类中访问基类的成员
- 指定创建派生类实例时应调用基类的构造方法;
super(参数);
- 调用基类上已被其他方法重写的方法;
super.方法名(参数);
- 访问基类的数据成员;
super.字段名;
注意:不能再静态方法中使用super关键字,super关键字只能在实例构造方法、实例方法或实例访问器中使用。
- 类成员的继承
- 通过继承,派生类继承基类中除构造方法以外的所有成员;
- 派生类构造对象的初始化顺序
基类的静态块–>派生类的静态块–>基类的实例代码块–>基类的构造方法–>派生类的实例代码块–>派生类的构造方法
- 基类的数据成员在派生类当中的访问权限
同包子类 | 同包非子类 | 不同包子类 | 不同包非子类 | |
---|---|---|---|---|
public | 可以 | 可以 | 可以 | 可以 |
private | 不可以 | 不可以 | 不可以 | 不可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
默认权限 | 可以 | 可以 | 不可以 | 不可以 |
三、多态
-
在面向过程的程序设计中,函数不能重名否则会产生歧义从而导致编译错误,所以在面向对象的程序设计中,有时需要利用“重名”来提高程序的抽象度和简洁性。
-
类方法多态性的实现方式有两种
-
方法重载(Overloade) :可以声明多个同名但参数的个数、类型、顺序都不同的方法,编译时根据参数的个数、类型和顺序判定采用的方法。这种编译时确定的模式,又称为“静态绑定”。
(函数名相同,参数列表不同,和返回值无关) -
方法重写/覆盖(Override):派生类声明从基类继承的方法签名一致的方法即重写方法,程序运行时根据运行时对象的类型,调用相应类的重写方法。这种运行时确定的模式,又称为“动态绑定”。
(函数名相同,参数列表相同,函数返回值相同。可以遵守协变类型。)
- 多态性:派生对象可以表示多个类型的能力,称为对象多态性。
- 继承是多态的基础,基类引用引用了派生类对象,并且基类和派生类有同名的重写方法。
例:
class Base {
private int ma;
public Base(int ma) {
this.ma = ma;
}
public void fun1() {
System.out.println("Base.fun1()");
}
public static void fun2() {
System.out.println("Base.fun2()");
}
}
class Derieve extends Base {
private int mb;
public Derieve(int a,int b) {
super(a); //调用基类的构造函数,必须放在第一行
this.mb = b;
}
public void fun1() {
System.out.println("Derieve.fun1()");
}
public static void fun2() {
System.out.println("Derieve.fun1()");
}
}
public class test1 {
public static void main(String[] args) {
Base base = new Base(10);
base.fun1();
Derieve derieve = new Derieve(5,15);
derieve.fun1();
}
}
运行结果:
对其进行反编译:
- 动多态:
例:修改上段代码的主函数,用基类去new一个派生类对象,调用基类的fun1()方法;
程序代码:
public class test1 {
public static void main(String[] args) {
Base base = new Derieve(5,10);
base.fun1();
}
}
运行结果:基类调用派生类的fun1()方法;
对其进行反编译:可知运行时基类调用的的确是自己的fun1()方法;
注意:
invokevirtual是调用实例方法;
Involespeacial是调用构造方法;
invokestatic是调用静态方法;
内存分析:在运行时,派生类方法的地址赋值给了基类方法的地址;
注意:方法表跟类型一一对应,Class对象跟类型一一对应,且方法表是在编译期生成;
- 构造函数内也可以发生多态
例:修改上面代码基类的构造函数
public Base(int ma) {
fun1();
System.out.println("Base.init()");
this.ma = ma;
}
主函数
public class test1 {
public static void main(String[] args) {
Base base = new Derieve(5,10);
}
}
运行结果: