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

    类和接口的关系

    • 类与类的关系:继承关系,只能单继承,但是可以多层继承
    • 类与接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
    • 接口与接口的关系:​ 继承关系,可以单继承,也可以多继承
  • 相关阅读:
    解决 Mac launchpad 启动台 Gitter 图标无法删除的问题
    React 与 React-Native 使用同一个 meteor 后台
    解决 React-Native mac 运行报错 error Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65. To debug build logs further, consider building your app with Xcode.app, by ope
    一行命令更新所有 npm 依赖包
    swift学习笔记
    IOS语言总结
    focusSNS学习笔记
    别小看锤子,老罗真的很认真
    windowsphone开发页面跳转到另一个dll中的页面
    【令人振奋】【转】微软潘正磊谈DevOps、Visual Studio 2013新功能、.NET未来
  • 原文地址:https://www.cnblogs.com/wurengen/p/13261438.html
Copyright © 2011-2022 走看看