zoukankan      html  css  js  c++  java
  • javaSE_14_抽象类丶接口

    抽象类概述

    父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有 意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类。类本身是不存在的,所以抽象类无法创建对象《无法实例化》。

    抽象类与抽象方法

    • 用abstract关键字来修饰一个类,这个类叫做抽象类。
    • 用abstract来修饰一个方法,该方法叫做抽象方法。 抽象方法:只有方法的声明,没有方法的实现。以分号结束: 比如:public abstract void talk();

    抽象方法

    使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。

    定义格式:

    抽象类

    如果一个类包含抽象方法,那么该类必须是抽象类。抽象的方法只需在抽象类中,提供声明,不需要实现,起到了一个强制的约束作用,要求子类必须实现

    定义格式:

    抽象类的成员特点

    • 成员变量:既可以是变量也可以是常量
    • 构造方法:可以有空参构造也可以有参构造
    • 成员方法:可以有抽象方法也可以有普通方法

    抽象的使用

    继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父 类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。

    代码演示

    定义抽象类

    /*
    抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。
    抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。
    如何使用抽象类和抽象方法:
    1. 不能直接创建new抽象类对象。
    2. 必须用一个子类来继承抽象父类。
    3. 子类必须覆盖重写抽象父类当中所有的抽象方法。
    覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
    4. 创建子类对象进行使用。
     */
    public abstract class Animal {
     
        // 这是一个抽象方法,代表吃东西,但是具体吃什么(大括号的内容)不确定。
        public abstract void eat();
     
        // 这是普通的成员方法
        public void normalMethod() {
        }
     
    }

    定义实现类

    package cn.itcast.day09.demo11;
     
    public class Cat extends Animal {
     
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
     
    }

    此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法。

    定义测试类

    package cn.itcast.day09.demo11;
     
    public class DemoMain {
     
        public static void main(String[] args) {
        //  Animal animal = new Animal(); // 错误写法!不能直接创建抽象类对象
            Cat cat = new Cat();
            cat.eat();
        }
     
    }

    注意事项

    抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

    • 理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

    抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。

    • 理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
    抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
    • 理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设 计。

    抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

    • 理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。 

    抽象类不能被 final 修饰

    • 抽象方法不能被 final 修饰,因为抽象方法就是被子类实现的

    Java语言中凡是没有方法体的方法都是抽象方法。不对,错误的。

    • Object类中就有很多方法都没有方法体,都是以“;”结尾的,但他们都不是抽象方法,例如:public native int hashCode();这个方法底层调用了C++写的动态链接库程序。前面修饰符列表中没有:abstract。有一个native。表示调用JVM本地程序。

    应用

    • 抽象类中可以包含方法实现,可以将一些公共的代码放到抽象类中,另外在抽象类中可以定义一些抽象的方法,这样就会存在一个约束,而子类必须实现我们定义的方法,如:teacher 必须实现 printInfo 方法,Student 也必须实现 printInfo 方法,方法名称不能修改,必须为 printInfo,这样就能实现多态的机制,有了多态的机制,我们在运行期就可以动态的调用子类的方法。所以在运行期可以灵活的互换实现。

    接口

    什么是接口?

    • 一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方 法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又 没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都支持USB连接。
    • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。继承是一个"是不是"的关系,而接口实现则是 "能不能" 的关系。
    • 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。接口(interface)是抽象方法和常量值定义的集合。

    接口的特点

    • 用interface来定义。
    • 接口中的所有成员变量都默认是由public static final修饰的。
    • 接口中的所有抽象方法都默认是由public abstract修饰的。
    • 接口中没有构造器。
    • 接口采用多继承机制。
    • 接口支持多继承,一个接口可以继承多个接口。

    定义格式

     

    示例:

    /*
        接口:
            1、接口也是一种“引用数据类型”。编译之后也是一个class字节码文件。
            2、接口是完全抽象的。(抽象类是半抽象。)或者也可以说接口是特殊的抽象类。
            3、接口怎么定义,语法是什么?
                [修饰符列表] interface 接口名{}
            4、接口支持多继承,一个接口可以继承多个接口。
            5、接口中只包含两部分内容,一部分是:常量。一部分是:抽象方法。接口中没有其它内容了。只有以上两部分。
            6、接口中所有的元素都是public修饰的。(都是公开的。)
            7、接口中的抽象方法定义时:public abstract修饰符可以省略。
            8、接口中的方法都是抽象方法,所以接口中的方法不能有方法体。
            9、接口中的常量的public static final可以省略。
    */
    public class Test01{
        public static void main(String[] args){
    
            // 访问接口的常量。
            System.out.println(MyMath.PI);
    
            // 常量能重新赋值吗?
            //错误: 无法为最终变量PI分配值
            //MyMath.PI = 3.1415928;
    
            //错误: 无法为最终变量k分配值
            //MyMath.k = 111;
        }
    }
    
    // 定义接口
    interface A{
    
    }
    
    // 接口支持继承
    interface B extends A{
    
    }
    
    // 一个接口可以继承多个接口(支持多继承)
    interface C extends A, B{
    }
    
    // 我的数学接口
    interface MyMath{
    
        // 常量
        //public static final double PI = 3.1415926;
    
        // public static final可以省略吗?
        double PI = 3.1415926;
    
        // k是不是常量????是。
        // 接口中随便写一个变量就是常量。
        // 常量:值不能发生改变的变量。
        int k = 100;
    
        // 抽象方法
        //public abstract int sum(int a, int b);
    
        // 接口当中既然都是抽象方法,那么在编写代码的时候,public abstract可以省略吗?可以的
        int sum(int a, int b);
    
        // 接口中的方法可以有方法体吗?错误: 接口抽象方法不能带有主体 
    
        // 相减的抽象方法
        int sub(int a, int b);
    
    }

    注意事项:

    • 定义Java类的语法格式:先写extends,后写implements class SubClass extends SuperClass implements InterfaceA{ }
    • 一个类可以实现多个接口,接口也可以继承其它接口。
    • 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
    • 接口的主要用途就是被实现类实现。(面向接口编程)
    • 与继承关系类似,接口与实现类之间存在多态性
    • 接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲, 接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义 (JDK7.0及之前),而没有变量和方法的实现。
    • 接口A和接口B虽然没有继承关系,但是写代码的时候,可以互转。编译器没意见。但是运行时可能出现:ClassCastException

    接口和抽象类的区别

    • 接口描述了方法的特征,不给出实现,一方面解决 java 的单继承问题,实现了强大的可接插性
    • 抽象类提供了部分实现,抽象类是不能实例化的,抽象类的存在主要是可以把公共的代码移植到抽象类中
    • 面向接口编程,而不要面向具体编程(面向抽象编程,而不要面向具体编程)
    • 优先选择接口(因为继承抽象类后,此类将无法再继承,所以会丧失此类的灵活性) 

    继承和实现都存在的话,代码应该怎么写?

    /*
        继承和实现都存在的话,代码应该怎么写?
            extends 关键字在前。
            implements 关键字在后。
    */
    public class Test04{
        public static void main(String[] args){
            // 创建对象(表面看Animal类没起作用!)
            Flyable f = new Cat(); //多态。
            f.fly();
    
            // 同一个接口
            Flyable f2 = new Pig();
            // 调用同一个fly()方法,最后的执行效果不同。
            f2.fly();
    
            Flyable f3 = new Fish();
            f3.fly();
        }
    }
    
    // 动物类:父类
    class Animal{
    }
    
    // 可飞翔的接口(是一对翅膀)
    // 能插拔的就是接口。(没有接口你怎么插拔。)
    // 内存条插到主板上,他们之间有接口。内存条可以更换。
    // 接口通常提取的是行为动作。
    interface Flyable{
        void fly();
    }
    
    // 动物类子类:猫类
    // Flyable是一个接口,是一对翅膀的接口,通过接口插到猫身上,让猫变的可以飞翔。
    class Cat extends Animal implements Flyable{
        public void fly(){
            System.out.println("飞猫起飞,翱翔太空的一只猫,很神奇,我想做一只猫!!");
        }
    }
    
    // 蛇类,如果你不想让它飞,可以不实现Flyable接口
    // 没有实现这个接口表示你没有翅膀,没有给你插翅膀,你肯定不能飞。
    class Snake extends Animal{
    }
    
    // 想飞就插翅膀这个接口。
    class Pig extends Animal implements Flyable{
        public void fly(){
            System.out.println("我是一只会飞的猪!!!");
        }
    }
    
    // 鱼(默认实际上是存在继承的,默认继承Object。)
    /*
    class Fish extends Object implements Flyable{
    }
    */
    class Fish implements Flyable{ //没写extends,也是有的,默认继承Object。
        public void fly(){
            System.out.println("我是六眼飞鱼(流言蜚语)!!!");
        }
    }

    Java 7及以前的JDK

    那么接口中可以包含的内容有常量:

    /*
    接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。
    从效果上看,这其实就是接口的【常量】。
    格式:
    public static final 数据类型 常量名称 = 数据值;
    备注:
    一旦使用final关键字进行修饰,说明不可改变。
    注意事项:
    1. 接口当中的常量,可以省略public static final,注意:不写也照样是这样。
    2. 接口当中的常量,必须进行赋值;不能不赋值。
    3. 接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)
     */
    public interface MyInterfaceConst {
     
        // 这其实就是一个常量,一旦赋值,不可以修改
        public static final int NUM_OF_MY_CLASS = 12;
     
    }

    也可以包含的内容抽象方法

    /*
    在任何版本的Java中,接口都能定义抽象方法。
    格式:
    public abstract 返回值类型 方法名称(参数列表);
    注意事项:
    1. 接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
    2. 这两个关键字修饰符,可以选择性地省略。
    3. 方法的三要素,可以随意定义。
     */
    public interface MyInterfaceAbstract {
     
        // 这是一个抽象方法
        public abstract void methodAbs1();
     
        // 这也是抽象方法
        abstract void methodAbs2();
     
        // 这也是抽象方法
        public void methodAbs3();
     
        // 这也是抽象方法
        void methodAbs4();
     
    }

    从Java 8开始

    接口里允许定义默认方法

    /*
    从Java 8开始,接口里允许定义默认方法。
    格式:
    public default 返回值类型 方法名称(参数列表) {
        方法体
    }
    备注:接口当中的默认方法,可以解决接口升级的问题。
     */
    public interface MyInterfaceDefault {
     
        // 抽象方法
        public abstract void methodAbs();
     
     
        // 新添加的默认方法
        public default void methodDefault() {
            System.out.println("这是新添加的默认方法");
        }
     
    }

    从Java 9开始

    接口当中允许定义私有方法

    /*
    问题描述:
    我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题。
    但是这个共有方法不应该让实现类使用,应该是私有化的。
    1. 普通私有方法,解决多个默认方法之间重复代码问题
    格式:
    private 返回值类型 方法名称(参数列表) {
        方法体
    }
    2. 静态私有方法,解决多个静态方法之间重复代码问题
    格式:
    private static 返回值类型 方法名称(参数列表) {
        方法体
    }
     */
    public interface MyInterfacePrivateA {
     
        public default void methodDefault1() {
            System.out.println("默认方法1");
            methodCommon();
        }
     
        public default void methodDefault2() {
            System.out.println("默认方法2");
            methodCommon();
        }
     
        private void methodCommon() {
            System.out.println("AAA");
            System.out.println("BBB");
            System.out.println("CCC");
        }
     
    }

    注意事项

    • 若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接口时,会出现:接口冲突。 解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。
    • 若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有相同名称和参数的默认方法会被忽略。

    接口的使用

    1. 接口不能直接使用,必须有一个“实现类”来“实现”该接口。

    格式:

    public class 实现类名称 implements 接口名称 {
                      // ...
    }

    2. 接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。实现:去掉abstract关键字,加上方法体大括号。

    3. 创建实现类的对象,进行使用。

    接口在开发中的作用

    • 接口在开发中的作用,类似于多态在开发中的作用。多态:面向抽象编程,不要面向具体编程。降低程序的耦合度。提高程序的扩展力。

    总结一句话:三个字“解耦合”

    • 面向接口编程,可以降低程序的耦合度,提高程序的扩展力。符合OCP开发原则。接口的使用离不开多态机制。(接口+多态才可以达到降低耦合度。)
    • 接口可以解耦合,解开的是谁和谁的耦合!!!任何一个接口都有调用者和实现者。接口可以将调用者和实现者解耦合。调用者面向接口调用。实现者面向接口编写实现。
    • 以后进行大项目的开发,一般都是将项目分离成一个模块一个模块的,模块和模块之间采用接口衔接。降低耦合度。

    类型和类型之间的关系:

    is a(继承)、has a(关联)、like a(实现)

    • is a:Cat is a Animal(猫是一个动物)凡是能够满足is a的  表示“继承关系”A extends B
    • has a:I has a Pen(我有一支笔)凡是能够满足has a关系的表示“关联关系” 关联关系通常以“属性”的形式存在。
    • like a: Cooker like a FoodMenu(厨师像一个菜单一样)凡是能够满足like a关系的表示“实现关系”实现关系通常是:类实现接口。A implements B

    类和接口的关系

    • 类与类的关系:继承关系,只能单继承,但是可以多层继承
    • 类与接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
    • 接口与接口的关系:​ 继承关系,可以单继承,也可以多继承
  • 相关阅读:
    Maven安装
    (字符串哈希表)找到字符串中不重复出现字符的最长子串长度
    (动态规划)给定三角形,找到从上到下的最小路径总和
    (链表)删除链表的重复元素
    (树)判断二叉树是否为BST
    (动态规划)机器人走迷宫问题
    (数组)Largest Rectangle in Histogram(栈解问题)
    (树)每一层节点的右指针问题(层次遍历)
    (字符串)count and say
    (贪心)加油站绕圈问题
  • 原文地址:https://www.cnblogs.com/wurengen/p/13261438.html
Copyright © 2011-2022 走看看