单例模式

  • 目的:使得类的一个对象成为该类系统中的唯一实例
  • 定义:一个类有且仅有一个实例,并且自行实例化向整个系统提供
  • 要求:
    • 某个类只能有一个实例
    • 必须自行创建实例
    • 必须自行向整个系统提供该实例
  • 实现:
    • 只提供私有的构造方法
    • 含有一个该类的静态私有对象
    • 提供一个静态的公有方法用于创建、获取静态私有对象
  • 代码实现方案:
    • 饿汉式
      • 饿汉式在类加载时就创建实例,第一次加载速度快
      • 空间换时间
    • 懒汉式
      • 懒汉式第一次使用时才进行实例化,第一次加载速度慢
      • 时间换空间
    • 饿汉式线程安全;懒汉式存在线程风险
      • 解决方案
        • 同步锁
        • 双重校验锁
        • 静态内部类
        • 枚举
  • 优点:
    • 在内存中只有一个对象,节省内存空间
    • 避免频繁的创建销毁对象,提高性能
    • 避免对共享资源的多重利用
  • 缺点:

    • 扩展比较困难
    • 如果实例化后的对象长期不使用,系统将默认认为垃圾进行回收,造成对象状态丢失

      Java多态

      一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在有程序运行期间才能决定

      分类

  • 编译时多态(设计时多态):方法重载

  • 运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法
  • 平时说得多态多指运行时多态

    必要条件

  • 满足继承关系(继承是多态的前提)

  • 父类引用指向子类对象

    向上类型转换(Upcast)

    将子类型转换为父类型

  • 隐式/自动类型转换,是小类型到大类型的转换

  • 对于向上的类型转换,不需要显示指定,即不需要加上前面的小括号和父类类型名

    向下类型转换(Downcast)

    将父类型转换为子类型

  • 将一个指向子类对象的父类引用赋值给一个子类的引用

  • 强制类型转换,是大类型转为小类型
  • 父类型的引用必须指向转型的子类型的对象,即指向谁才能转换成谁,不然会编译报错
  • 通过instanceof判断父类型的引用是否指向子类型的对象。

    注意点

  1. 父类引用指向子类实例时,可以调用子类重写父类的方法以及直接继承父类的方法,但不能调用子类特有的方法
  2. 静态static方法属于特殊情况,静态方法只能继承,不能重写,调用的时候用谁的引用,则调用谁的版本

    抽象类&抽象方法

    使用抽象类限制类的实例化(原因:一些类实例化是没有意义的)—-abstract
  • 抽象方法 —- 加abstract
    • 抽象方法没有方法体
    • 抽象方法必须在抽象类中
    • 抽象方法必须在子类中被重写,除非子类也定义为抽象类
  • 使用规则

    • abstract定义抽象类
    • 抽象类不能实例化只能被继承,可以通过向上转型实例化抽象类
    • abstract定义抽象方法不需要具体实现
    • 包含抽象方法的类是抽象类
    • 抽象类中可以不包含抽象方法
    • 子类如果没有重写父类的抽象方法,则子类也要定义为抽象类
    • abtract不能和static、final、private共存
      • static定义的方法可以继承但不能重写
      • final定义的方法不能被重写,但可以被重载
      • private定义的方法为父类独有的方法,不能继承
    • 抽象方法在子类实现时访问权限必须大于等于父类方法

      接口

      提供一个统一规范,不关心内部数据以及内部实现,只规定类必须提供某些方法

      语法规则

  • 访问权限默认为:public 或 默认

  • 常量默认添加static final关键字
  • 抽象方法默认添加abstract关键字
  • 只有default方法及static方法可以添加方法体
  • 实现接口的类如果不能实现接口中的所有方法则要定义为抽象类
  • 接口可以实现多继承,即一个接口可以继承多个父接口
  • 一个类可以继承一个父类同时实现多个接口
  • 当一个类实现多个接口时,如果多个接口中含有相同方法,则这个类必须重写这个相同方法,否则编译会报错

    内部类

    成员内部类

    最常见,也称为普通内部类

    1. public class Person{
    2. int age;//年龄
    3. public Heart getHeart(){
    4. return new Heart();
    5. }
    6. //内部类:心脏
    7. class Heart{
    8. public String beat(){
    9. System.out.println("心脏在跳动~");
    10. }
    11. }
    12. }
  • 相当于一个成员变量,可以使用任意修饰符修饰

  • 可以直接访问外部类,不受修饰符影响
  • 外部类不能直接使用内部类的成员和方法,需要借助内部类对象
  • 需要通过外部类对象来创建内部类实例
  • 外部类内部类如果具有相同的成员,内部类默认访问自己的,可以通过“外部类.this.对象成员”以及“外部类.静态成员(static)”方式访问外部类成员
  • 编译后产生的字节码文件名:外部类$内部类.class

    静态内部类

    1. public class Person{
    2. int age;//年龄
    3. public Heart getHeart(){
    4. return new Heart();
    5. }
    6. //静态内部类:心脏
    7. static class Heart{
    8. public String beat(){
    9. System.out.println("心脏在跳动~");
    10. }
    11. }
    12. }
  • 静态内部类可以不通过外部类直接创建对象

  • 静态内部类不能直接访问外部类的非静态成员,可以通过外部类对象.成员的方式访问
  • 外部类可以直接通过内部类.成员名的方式访问内部类的静态成员

    方法内部类

    1. public class Person{
    2. int age;//年龄
    3. public void getHeart(){
    4. //方法内部类:心脏
    5. class Heart{
    6. public String beat(){
    7. System.out.println("心脏在跳动~");
    8. }
    9. }
    10. new Heart().beat;
    11. }
    12. }
  • 定义在外部类方法中的类也称为局部内部类

  • 方法内部可见,只有在方法内可以使用
  • 不能使用static,但能使用final、abstract
  • 编译后产生:外部类$数字.class

    匿名内部类

    ```java interface Animal{//动物接口 //跑方法 public void run(); } public static void main(String[] args){ Animal dog = new Animal(){
    1. public void run(){
    2. System.out.println("小狗快跑~");
    3. }
    }; dog.run(); }

```

  • 场景
    • 只用到类的一个实例
    • 类在定义后马上使用
    • 给类命名不会导致类更容易被理解
  • 使用原则:
    • 不能有构造方法,可以有构造代码块
    • 不能定义静态成员、静态方法
    • 不能使用public、protected、private、static、abstract、final修饰
    • 也是局部内部类,所以局部内部类的限制对匿名内部类都生效
    • 一定是在new的后面,用其实现一个接口或继承一个类,二者不可兼得
    • 只能创建匿名内部类的一个实例
    • 匿名内部类在编译后由系统自动起名为:Outter$1.class
    • 一般来说,用于继承其他类或实现接口,不需要新增新的方法,重写类或接口的方法即可
    • 通过匿名内部类返回的是一个对象的引用,所以可以直接使用或将其复制给一个对象变量