单利模式、继承

单利模式

  • 定义
  • 1、一个类只产生一个实例
  • 2、单利类必须自己创建自己的唯一实例。
  • 3、单利类必须给所有其他对象提供这一实例 =====》提供一个全局访问点
  • 场景:(什么时候用单利模式)
    一个类可以定义无数个对象,“但是只能有一个实例” =====》 控制构造函数
    • 懒汉式单利模式
 //懒汉式单利模式 =====》 线程不安全   (new的时候才调用一个对象     不是线程安全的)
 // 1、将构造函数写成私有的
//2、提供一个全局访问点
  class MysingleTon{   //单例类
  private static MysigleTon sigleTon = null;
  //public MysingleTon(){    //无参的构造函数  ( 通过在主函数中new一下,产生对象)new无数个对象 }
  private MysingleTon(){
  System.out.println("MysingleTon {} init"); //私有的,只能在当前类中使用
  } 
  //得到对象
  //单利模式访问的时候必须提供一个全局的访问点  ===  通过类名调用 
   publlic static MysingleTon getInstance(){
   //懒汉式的竟态条件代码段
      if(singleTon == null){
      singleTon = new MysingleTon();  //new分两步,1、创建内存2、创建对象
}
 return singleTon;     
}
}
public class Test1030 {
public static void main(String[] args) {
 MysingleTon  mysingleTon  = MysingleTon.getInstance();
 MysingleTon  mysingleTon2  = MysingleTon.getInstance();
 MysingleTon  mysingleTon3  = MysingleTon.getInstance();
 MysingleTon  mysingleTon4  = MysingleTon.getInstance();
 System.out.println( mysingleTon );
 System.out.println( mysingleTon2 );
 System.out.println( mysingleTon3 );
 System.out.println( mysingleTon4 );
//打印的地址都一样    一个类只生成了一个实例
}

}
  • 饿汉式单利模式
//饿汉式单利模式 ====>线程安全   只初始化一次
class MysingleTon2{
   private static MysingleTon2 sigleTon = new MysingleTon2();    //  “static"只初始化一次    已经得到对象

  private MysingleTon2() {
       System.out.println("MysingleTon2() init");
   }
   //单利模式访问的时候必须提供一个全局的访问点  ===  通过类名调用
   public static MysingleTon2 getInstance() {
       return sigleTon;
   }
   }
  • 线程安全的单利模式
  • 线程安全======》是否有竟态条件 》 临界区代码段》原子性操作(一个线程执行的时候,另一个不能执行)=====》加锁(互斥锁、自旋锁、读写锁)
  • 每一个线程都有自己的执行时间,执行时间取决于CPU

class MysingleTon {
    private static Object lock = new Object();  //实例化新建锁
    private static MysingleTon singleTon = null;
    private MysingleTon() {
        System.out.println("MysingleTon() init");   //私有的,只能在当前类中使用
    }
    //单利模式访问的时候必须提供一个全局的访问点  ===  通过类名调用
    public static MysingleTon getInstance() {
        //加锁
        // 4、可重入函数======》线程安全的函数
        // double--checked  llocking  双重检验
        if (singleTon == null) {
            synchronized (lock) {
                if (singleTon == null) {
                }
                singleTon = new MysingleTon();
            }
        }
        
        //单线程可以   单线程进来加锁,得到对象,释放锁
        // 多线程不合适  第一个线程还没有将对象MysigleTon()赋值给sigleTon,第二个线程会从if中进来在锁外等待第一个线程释放锁
        /*
        3、if (sigleTon == null) {
            synchronized (lock) {
                sigleTon = new MysigleTon();   //临界区代码段
                 //同时有两个线程,次处至少执行两遍
            }
        }*/

       //多线程安全 第一个线程先进来,判断为空,赋值,释放锁,第二个线程才能进来
        //单线程不合适   来一个线程,加锁===释放锁 (浪费CPU)
        /*2、synchronized (lock) {
            if (sigleTon == null) {
                sigleTon = new MysigleTon();   //CPU浪费
            }*/

       /* //懒汉式的竟态条件代码段
        1、if (sigleTon == null) {
            sigleTon = new MysigleTon();   //new分两步,1、创建内存2、创建对象
        }*/
            return singleTon;     //返回对象

        }  //释放锁
    }
  • 静态内部类实现单利模式
class MysingleTon3 {
    private MysingleTon3(){
    }
    //只有访问静态内部类的时候,才会创建对象
    private static class SingleTon{
        public static MysingleTon3 c = new MysingleTon3();
    }
    public static MysingleTon3 getInstance(){
        return SingleTon.c;
    }
}

继承

  • 继承: 一种机制,可以进行代码的重用
  • 面试问题1、派生类继承了父类的除什么没继承?? 除构造函数外的所有属性(包括:数据)
  • 继承了基类,还要为基类的数据成员进行构造函数
  • 派生类的构造函数只能构造自己的数据成员
  • 基类的构造函数没有被继承,只是调用构造函数 用super调用 super写在第一行
  • super:

  • super()===》调用基类的构造函数 ( 必须放在第一行)
  • super.data===》访问基类的数据成员
  • super.func()=====》调用基类的成员方法

class Base {
    public 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);     //super关键字  必须放在第一行  基类的构造函数没有被继承,只是调用构造函数  用super调用基类的数据成员
    super.ma = 10;
    super.fun1();   //调用基类的成员方法
    // ma = a; //error
    this.mb = b;  //派生类的构造函数只能构造自己的数据成员
    System.out.println("Derieve.init{}");
}
     } 
class Base {
    public int ma;
    public Base (int ma) {
     System.out.println("Base.init()");
        this.ma = ma;
    }
     public void fun1() {
        System.out.println("Base.fun1()" + this.ma);
    }
    public static void fun2() {
        System.out.println("Base.fun2()");
    }
}
    class  Derieve extends Base{
     private int mb;
      public Derieve(int a,int b){   //派生类的构造函数
      super(a);     //super关键字  必须放在第一行  基类的构造函数没有被继承,只是调用构造函数  用super调用基类的数据成员
    super.ma = 10;
    super.fun1();   //调用基类的成员方法
    // ma = a; //error
    this.mb = b;  //派生类的构造函数只能构造自己的数据成员
    System.out.println("Derieve.init{}");
    }
public void fun1() {
    System.out.println("Derieve.fun1()");
    }
public static void fun2() {
    System.out.println("Derieve.fun2()");
}
  }
  public class Test10301 {
  public static void main1(String[] args) {
    Base base = new Base(100);
    Derieve derieve = new Derieve(1000, 9999);
    }
    }
结果:Base.init()
    Base.fun1()10
  • 对象的初始化过程: 静态代码块初始化====》实例代码块初始化====》构造函数

class Base {
    public int ma;
    public Base (int ma) {
     System.out.println("Base.init()");
        this.ma = ma;
    }
      //基类
//  静态代码块
  static {
      System.out.println("Base.static{}");
  }
 //实例代码块
 {
     System.out.println("Base.instance{}");

 }
     public void fun1() {
        System.out.println("Base.fun1()" + this.ma);
    }
    public static void fun2() {
        System.out.println("Base.fun2()");
    }
}
    class  Derieve extends Base{
     private int mb;
      public Derieve(int a,int b){   //派生类的构造函数
      super(a);     //super关键字  必须放在第一行  基类的构造函数没有被继承,只是调用构造函数  用super调用基类的数据成员
    super.ma = 10;
    super.fun1();   //调用基类的成员方法
    // ma = a; //error
    this.mb = b;  //派生类的构造函数只能构造自己的数据成员
    System.out.println("Derieve.init{}");
    }
    //派生类
//  静态代码块
static {
    System.out.println("Derieve.static{}");
}
//实例代码块
{
    System.out.println("Derieve.instance{}");

}public void fun1() {
    System.out.println("Derieve.fun1()");
    }
public static void fun2() {
    System.out.println("Derieve.fun2()");
}
  }
    public class Test10301 {
  public static void main1(String[] args) {
    Base base = new Base(100);
    Derieve derieve = new Derieve(1000, 9999);
    }
    }
结果:Base.static {}
    Derieve.static{}
    Base.instance{}
    Base.init{}
    Derieve.instance{}
    Base.fun1()10
    Derieve.init{}

派生类构造对象的初始化顺序:

  • Base.static{}

  • Derieve.static{}

  • Base.instance{}

  • Base.init()

  • Derieve.instance{}

  • Derieve.init{}

  • 基类和派生类之间的相互赋值 =====>多态的基础
    ( 派生类可以赋值给基类,基类不能赋值给派生类)

  • 重载: overload: 函数名相同,参数列表不同,与函数返回值无关
    ( 并不一定在同一个类当中,在继承关系上也可以构成重载)

public void fun1() {
    System.out.println("Derieve.fun1()");
}
public void fun1(int a) {
    System.out.println("Derieve.fun1(int)");
}
public void fun1(int a) {
    System.out.println("Derieve.fun1(int)");
}
public void fun1() {

    System.out.println("Base.fun1()"+this.ma);
}
  • 重写/覆盖overwrite: 函数名相同,参数列表相同,函数返回值相(基类和派生类) 可以遵守协变类型
 public void fun1() {
        System.out.println("Base.fun1()"+this.ma);
 public void fun1() {
        System.out.println("Derieve.fun1()");
    }
  • 方法表是在编译的时候生成的
  • 多态:基类引用 引用了派生类的对象,并且,基类和派生类都有同名的覆盖方法
  • 动多态: 运行期间发生的多态 地址被覆盖 基类引用 引用了派生类的对象
    在这里插入图片描述
public static void main2(String[] args) {
    Base base = new Base(100 );  //调用的是基类的fun()方法
    base.fun1();
    System.out.println("==========");
    Derieve derieve = new Derieve(100, 9999);  //调用的是派生类的fun()方法
    derieve.fun1();
  • 静多态: 发生在编译期间
public static void main3(String[] args) {
    Base base = new Derieve(100, 999);
   Base.fun2();//静多态

构造函数内能发生多态


class Base {
    public int ma;
    public Base (int ma) {
        fun1();
        System.out.println("Base.init()");
        this.ma = ma;
    }
  • (public基类)基类的数据成员在派生类中的访问权限
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43301647/article/details/83684720