抽象

:::tips

概述:

  • 在java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类

    修饰类:

  • 如果一个类中存在抽象方法,那么该类就必须声明为抽象类。

  • 访问修饰符 abstract 类名{}

    修饰方法:

  • 将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体实现,该方法就可以定义为抽象方法。

  • 访问修饰符 abstract 返回类型 方法名(参数列表);
  • 抽象类价值更多在于设计,设计者设计好后让子类继承并实现抽象类

特点:

  • 抽象类和抽象方法必须使用abstract关键字修饰
  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
  • 抽象类不能实例化,但可通过子类对象实例化,这叫抽象类多态
  • 抽象类的子类要么重写抽象类中所有方法要么是抽象类

抽象类和普通类的区别:(有得有失)

  • 抽象类得到定义抽象能力
  • 抽象类失去创建对象能力
  • 除此之外普通类可以定义的,抽象类都可以

成员特点:

  • 成员变量:
    • 可以是变量和常量
  • 构造方法:
    • 有构造方法但不能实例化,用于子类访问父类数据的初始化
  • 成员方法:

    • 可以有抽象方法:限定子类必须完成某些动作;也可以有非抽象方法,提高代码复用性

      static ,private, final不能和抽象一起修饰方法(因为抽象方法需要重写)

      :::

      接口

      :::tips

      概述:

  • 接口就是一种公共的规范标准,只要符合标准规范,大家都通用,java中接口更多体现在对行为的抽象

接口特点:

  • 接口用关键字interface修饰
  • 类实现接口用implements表示
  • 接口不能实例化
    • 如何实现实例化:通过实现类对象实例化,这叫接口多态
    • 多态的形式:具体类多态,抽象类多态,接口多态
    • 多态的前提:有继承或者实现关系,有方法重写,有父(类/接口)引用指向(子/实现)类对象

接口实现类

  • 要么重写接口中所有抽象方法
  • 要么抽象类

接口成员特点:

  • 成员变量:
    • 只能是常量
  • 默认修饰符:public static final
  • 构造方法:
    • 接口没有构造方法,接口主要是对行为进行抽象的,是没有具体存在
    • 一个类如果没有父类,默认继承Object
  • 成员方法:
    • JDk7及以前, 只能定义抽象方法和常量
      • 原因是所有方法都有默认修饰符:public abstract
    • JDK8以后, 可以带方法体的方法(减少耦合性)
      • 静态方法直接写, 非静态方法要用default修饰
    • JDK9以后, 可以私有方法直接写即可(提高复用性)

类与接口的关系:

  • 类和类的关系:
    • 继承关系,只能单继承,但是可以多层继承
  • 类和接口的关系:
    • 实现关系,可以单实现,也可以多实现,还可以继承一个类的同时实现多个接口
  • 接口和接口的关系:
    • 继承关系,可以单继承,也可以多继承

抽象类和接口区别:

  • 成员区别:
    • 抽象类:变量、常量、构造方法、抽象方法、非抽象方法
    • 接口:常量、抽象方法
  • 关系区别:
    • 类与类:继承、单继承
    • 类与接口:单实现、多实现
    • 接口与接口:单继承、多继承
  • 设计理念区别:
    • 抽象类:对类抽象,包括属性、行为
    • 接口:对行为抽象

对于一个类来讲, 他的父类(继承的关系)中定义的都是:共性内容

对于一个类来讲, 他是父接口(实现的关系)中定义的都是:扩展内容

:::

  1. public interface Usb {
  2. //定义变量public static final为默认修饰可不写
  3. public static final double TYPE = 3.0;
  4. //定义方法public abstract为默认修饰可不写
  5. public abstract void connect();
  6. public abstract void exit();
  7. }
  8. //类实现接口用implements实现
  9. public class Computer implements Usb {
  10. //必须重写接口所有抽象方法
  11. @Override
  12. public void connect() {
  13. System.out.println("USB已安全插入");
  14. }
  15. @Override
  16. public void exit() {
  17. System.out.println("USB已安全断开");
  18. }
  19. }

形参和返回值

:::tips

类名做为参数返回值

  • 方法的形参是类名,其实需要的是该类的对象
  • 方法的返回值的类名,其实返回的是该类的对象

    抽象类名作为形参和返回值

  • 方法的形参是抽象类名,其实需要的是该类的子类对象

  • 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象

    接口名作为形参和返回值

  • 方法的形参是接口名,其实需要的是该接口的实现类对象

  • 方法的返回值是接口名,其实返回的是该接口的实现类对象 :::

    内部类

    :::tips

    概述:

  • 一个类的内部又完整嵌套了另一个类结构

  • [类的五大成员:属性,方法,构造器,代码块,内部类]

访问特点:

  • 内部类可以直接访问外部类成员,包括私有
  • 外部类要访问内部类成员,必须创建对象

局部内部类:(定义在方法或者代码块中)

  • 可以访问外部类所有成员包括私有
  • 不能添加访问修饰符(局部变量),可以使用final修饰
  • 局部内部类是在方法中定义的类,所以外界是无法直接使用的,需要在方法内创建对象并使用
  • 该类可以直接访问外部类的成员,也可访问方法内的局部变量
  • 外部其他类不能访问局部内部类(局部内部类的地位是一个局部变量)
  • 外部类和局部内部类的成员重名时,默认遵循就近原则,可以通过(外部类名.this.成员)去访问外部类的成员

#▲匿名内部类:

  • 本质还是类 属于内部类 该类没有名字(底层会有) 同时还是一个对象
  • 匿名内部类是定义在外部类的局部位置,比如方法中,并且没有名字
  • 存在一个类或接口中,可以具体类也可以抽象类
  • 本质是一个继承了该类或者实现该接口的子类匿名
  • 基本语法:类/接口 对象名 = new 类/接口(参数列表){}

      直接调用:new 类/接口(参数列表).方法名;
    
  • 匿名内部类比较奇特,既是类的定义,同时本身也是一个对象

成员内部类:

  • 成员内部类是定义在外部类的成员位置,并且没有static修饰
  • 可以直接访问外部类所有成员,包含私有
  • 可以添加任意访问修饰符,因为他就是一个成员
  • 作用域和外部类的其他成员一样,为整个类体
  • 内部类访问:直接访问
  • 外部类访问:创建对象访问
  • 外部其他类访问:

    • 外部类名.内部类名 对象名 = 外部类对象.内部类对象
    • 在外部类中编写方法去返回内部类对象

      静态内部类:

  • 定义在外部类成员位置,并且有static修饰

  • 可以访问外部类所有静态成员,但不能访问非静态成员
  • 可以添加任意访问修饰符,因为他就是一个成员
  • 作用域:同其他的成员为一个整体
  • 内部类访问:直接访问
  • 外部类访问:创建对象访问 :::
    class Outer {
      {
          class Inner {
          }
      }
      public void a() {
          class Inner {
          }
      }
    }
    
    ```java //外部其他类 public class AnonymousInnerClass { public static void main(String[] args) {
      Outer outer = new Outer();
      outer.method();
    
    } }

//外部类 class Outer { public void method() { //方法 //基于接口的匿名内部类(当有些类只使用一次后不再使用) //编译类型:IA //运行类型:匿名内部类 / 底层:(类名:外部类名 + $1) class Outer$1 implements IA() { @Override public void cry() { System.out.println(“老虎叫唤”); } } / //jdk底层在创建匿名内部类Outer$1,会立即马上创建Outer$1实例并且把地址返回给tiger //匿名内部类在使用一次就不能在使用,但对象可以反复调用 IA tiger = new IA() { @Override public void cry() {} }; tiger.cry(); //打印运行类型类名称 System.out.println(tiger.getClass());//class 包名.Outer$1

    //基于方法的匿名内部类
    //编译类型:IB
    //运行类型:匿名内部类
    /*
        底层会创建匿名内部类
        class Outer$2 extends IB(){}
    */

    //同时会返回匿名内部类Outer$2的对象
    //参数列表会传递给构造器
    IB ib = new IB(){};
    ib.test();
    System.out.println(ib.getClass());//class 包名.Outer$2

    //基于抽象类的匿名内部类
    IC ic = new IC(){
        @Override
        void test() {}
    };
    ic.test();
    System.out.println(ic.getClass());//class 包名.Outer$3
}

}

//接口 interface IA { public void cry(); }

//将只使用一次的类优化为匿名内部类 /class Tiger implements IA { @Override public void cry() { System.out.println(“老虎叫唤”); } }/

//外部其他类 class IB { //构造器 public IB() {} //方法 public void test() {} }

//抽象类 abstract class IC{ abstract void test(); }

```java
public class AnonymousInnerClass01 {
    public static void main(String[] args) {
        //匿名内部类当做实参进行传递,简洁高效
        num(new ID() {
            @Override
            public void show() {
                System.out.println("匿名内部类应用");
            }
        });
    }
    //静态方法,形参是接口
    public static void num(ID id){
        id.show();
    }
}

//接口
interface ID{
    void show();
}
/*
    定义铃声接口Bell,里面有ring方法
    定义手机类CellPhone,具有闹钟功能alarmClock
    通过匿名内部类(对象)作为参数打印:懒猪起床了
    再传入匿名内部类(对象)打印:小伙伴上课了

*/
public class AnonymousInnerClass02 {
    public static void main(String[] args) {
        //创建手机类对象
        CellPhone cP = new CellPhone();
        //调用闹钟方法将匿名内部类作为实参传递
        cP.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了");
            }
        });
        cP.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了");
            }
        });
    }
}
//接口
interface Bell{
    //方法
    void ring();
}
//手机类
class CellPhone{
    //方法闹钟功能
    public void alarmClock(Bell bell) {
        bell.ring();
    }
}
class Outer {
    class Inner {
        public void a() {}
    }
}

枚举

:::tips 概述:

  • 枚举类编译后本质是final修饰的java类,并且继承了java.lang.Enum类
  • 枚举类的构造方法都是private修饰的,所以枚举类无法在外部创建对象
  • 每个枚举值都是该类的对象,并且都是public static final修饰的
  • 枚举本质是一个java类,所以枚举中可以有成员变量、成员方法、构造方法等成分
  • 枚举类可以实现接口

自定义实现枚举

  • 构造器私有化
  • 本类内部创建对象
  • 对外暴露对象(通过public final static修饰)
  • 提供get不提供set方法

enum关键字实现枚举

  • 使用关键字enum代替class
  • 常量名(实参列表)等同public final static 类名 常量名 = new 类名(实参列表);
  • 使用:类名.枚举值 ::: ```java public class Test { public static void main(String[] args) {
      Person person = new Person("jack", Gender.MAN);
      System.out.println(person);
    
    } }

public enum Gender { MAN, WOMEN; }

public class Person { private String name; private Gender sex; //构造方法 //setget //toString } ``` | abstract | /ˈæbstrækt/ | adj. 抽象的 | | —- | —- | —- | | interface | /ˈɪntəfeɪs/ | 接口 | | implements | /‘ɪmplɪm(ə)nts/ | 实现 | | default | /dɪˈfɔːlt/ | 默认 | | enum | /ɪˌnjuːm/ | 枚举 |