Java面向对象抽象类/接口类/内部类

抽象类/抽象方法

抽象类

抽象类除了定义抽象方法外,与普通类一样
  • 可定义成员变量/方法,由于抽象类无法实例化,因此只具有语法意义;
  • 可定义static变量/方法,可通过类名直接访问;
  • 可继承/实现其他类/接口;
子类继承抽象父类,
  • 子类为非抽象类:强制重写抽象父类中的所有抽象方法,继承其他成员变量与成员方法;
  • 子类为抽象类:不必强制实现抽象父类中的抽象方法,继承其他成员变量与成员方法,由于抽象子类也无法实例化,因此继承只具有语法意义;
抽象类只能作为父类被子类继承,因此抽象类不可实例化,无法创建实例对象
抽象类中可以没有抽象方法有抽象方法的类必须是抽象类
抽象类命名使用Abstract或者Base开头;

抽象方法

  1. // 抽象方法不可有方法体,{}表示方法体为空,不代表没有
  2. public abstract double sum();

抽象方法只有声明,没有方法体;
  • 抽象方法的存在意义在于子类继承重写
  • private/staticabstract不能同时修饰方法;


接口(interface)

接口定义了完全抽象的类,体现规范与实现分离的设计理念;
  1. // 接口可继承多个父接口
  2. [publc/包访问权限] interface 接口名 extends 接口1, 接口2, ... {
  3. ...
  4. }
接口访问修饰符是public/包访问权限,可通过extends关键字继承多个直接父接口,获得父接口内的所有方法/常量;(任何使用C++函数指针的地方,考虑使用Java中的接口)

接口成员

接口中不包含构造器,包含:
成员变量:只能为static常量,默认使用public static final修饰,可通过接口名直接访问
接口方法
  • 抽象方法:形式上定义普通方法系统将自动使用public abstract修饰,编写时不加任何修饰符,保持代码简洁;
  • static方法(不推荐使用):必须要有方法体,可通过接口名直接访问; 
  • default方法(不推荐使用):必须要有方法体;
    • Java8引入用于最终能顺畅使用Lambda表达式;
    • 子类不必强制重写default方法,子类内部通过interfaceName.super.defaultMethodName()调用;
  1. // 默认方法只需在普通方法头前加default关键字
  2. defalut String test();
  • 内部类/内部接口/内部枚举均默认用public abstract修饰;

子类实现接口

类可使用implements关键字实现多个接口,语法格式:
  1. [修饰符] class 类名 extends 父类名 implements 接口1, 接口2... {
  2. 类体部分;
  3. }
  • 类实现接口后,类中必须重写接口内的所有抽象方法,所有方法必须是public方法否则该类必须定义为抽象类(因为保留了从父接口继承到的抽象方法)
  • 子类可以向上转型为多个父类接口类型,实现多态;
    

接口与抽象类辨析

比较项接口抽象类 
普通变量NY
static变量YY
构造器NY
普通方法NY
抽象方法YY
static方法YY
default方法YN
创建实例NN
“继承”机制可实现多接口单一继承
abstract class和interface所反映出的设计理念不同。
  • abstract class表示的是"is-a"关系;
  • interface表示的是"like-a"关系;
接口/抽象类不能定义实例,但是可以定义引用变量指向子类对象(向上转型),实现多态;


回调(call-back) / 钩子(Hook)

回调机制可通过
  • public stract方法,强制子类重写方法;
  • 接口定义,子类重写实现;
回调/钩子函数定义参数为抽象类/接口变量,根据实际需要传入实际的子类引用,实现回调/钩子,本质上是多态的应用;



对象克隆

浅拷贝(默认,默认为Object类中的clone方法):原始变量和拷贝变量引用同一个对象,拷贝域分为;
  • 数值或基本数据类型:对应拷贝;
  • 子对象引用:拷贝结果会使两个域引用同一个对象,导致原始对象域克隆对象共享该部分信息;
深拷贝(必须实现):对象所在类实现Object类中的clone方法,对象中包含:
  • 实现Cloneable接口;
  • 使用public修饰自定义clone()方法;
  1. class Person implements Cloneable{
  2. ...
  3. // 重写clone方法
  4. public Person clone() throws CloneNotSupportException {
  5. Person cloned = (Person) super.clone(); // 调用默认浅拷贝
  6. cloned.boy = (Boy) boy.clone(); // 拷贝子对象
  7. }
  8. }
Cloneable接口是Java提供的标记接口(tagging interface)之一,标记接口内部没有方法;


内部类(inner class)

定义在类中的类叫“内部类”,与之相对的类是“外部类”;
内部类方法对同一个包中的其他类透明;
内部类时一种编译器现象,与JVM无关;



内部类自动拥有访问外部类所有成员的权限(无视控制符),当外部类对象创建一个内部类对象时,该内部类对象会秘密捕获一个外部类对象引用(显式表示为OutClassName.this),内部类通过外部类引用来访问外部类所有成员
 

局部内部类

局部内部类:定义在方法内部的类,只对所在方法可见;
局部内部类只能引用外部类的final变量;
局部类不可用public, private控制符声明;
 



非static内部类

非静态内部类访问外部类:
非静态内部类作为『外部类的成员』可访问外部类成员变量/成员方法;
—>机制:在非静态内部类实例中,保存了外部类实例的引用:
  1. // 内部类在内部访问内部类成员
  2. this.内部类成员;
  3. // 内部类在内部访问外部类成员
  4. OutClass.this.外部类成员;
非静态内部类中不可以定义static成员;

外部类内部访问非静态内部类:与平常使用普通类无差别;
—>外部类中的静态方法,不可访问非静态内部类;
外部类以外使用非静态内部类:
  1. OuterClass.InnerClass Instance = new OuterClass().new InnerConstructor();



static/静态内部类

  1. // 外部类不可用static修饰
  2. static class StaticInnerClass {
  3. 成员:static/非static;
  4. }
static内部类属于外部类本身/不属于外部类实例,
static内部类访问外部类:
—>static内部类对象寄生在外部类的类本身中,不是寄生在外部类实例中;
—>static内部类对象只持有外部类的类引用,不持有外部类对象的引用;
—>static内部类不能访问外部类的实例成员;
      static内部类只可访问外部类的static成员;
接口内可定义内部接口,默认用public static修饰,使用场景少;

外部类内部访问静态内部类
  1. StaticInnerClass.static成员; // 通过静态内部类名直接访问静态内部类成员;
外部类以外使用静态内部类:
静态内部类是外部类类相关的—>创建静态内部类对象时无须创建外部类对象
  1. StaticOutClass.StaticInnerClass Instance = new StaticOutClass.StaticInnerClassConstructor();
















所有博文来自个人为知笔记,内容多为读书笔记和理解内容;
原文地址:https://www.cnblogs.com/yzwall/p/6637153.html