栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Javase——抽象类与接口

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Javase——抽象类与接口

抽象类和接口 一、抽象类
  1. 什么是抽象类?

    类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类。类本身是不存在的,所以抽象类无法创建对象(无法实例化)。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5h8vEwkj-1633269397150)(C:UsersdellAppDataRoamingTyporatypora-user-imagesimage-20211001235508415.png)]

  2. 抽象类属于什么类型?

    抽象类也是属于引用数据类型。

  3. 抽象类怎么定义?

    语法:

    ​ { 修饰符列表 } abstract class 类名{

    ​ 类体;

  4. 抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承。

  5. final和abstract不能联合使用,这两个关键字是对立的。

  6. 抽象类的子类可以是抽象类也可以是非抽象类。

  7. 抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法供子类使用。

  8. 抽象类关联到抽象方法的概念,抽象方法表示没有实现的方法,没有方法体的方法,例如:

    ​ public abstract void doSome();

    抽象方法的特点:

    ​ 特点1:没有方法体,以分号结尾。

    ​ 特点2:前面修饰符列表中有abstract关键字。

  9. 抽象类中不一定有抽象方法。抽象方法必须出现在抽象类中。

  10. 一个非抽象的类继承抽象类,必须将抽象类中的抽象方法进行覆盖/重写,或者也可以叫做“实现“。

    **面试题(判断题):**java语言中,凡是没有方法体的方法都是抽象方法。

    ​ 错误。Object类中有很多方法都没有方法体,都是以“;”结尾的,但它们都不是抽象方法,例如:

    ​ public native int hashCode();

    ​ 前面修饰符列表中没有abstract。有同一个native。表示调用JVM本地程序。


二、接口 (一)接口的基础语法
  1. 接口也是一种“引用数据类型”。编译之后也是一个class字节码文件。

  2. 接口是完全抽象的。(抽象类是半抽象的)或者也可以说接口是特殊的抽象类。

  3. 接口怎么定义?

    { 修饰符列表 } interface 接口名 { }

  4. 接口支持多继承,一个接口可以继承多个接口。

  5. 接口中只包含两部分内容,一部分是:常量。一部分是:抽象方法。接口中没有其它内容。

  6. 接口中所有的元素都是public修饰的。(都是公开的。)

  7. 接口中的抽象方法定义时:public abstract修饰符可以省略。

  8. 接口中的方法都是抽象方法,所以接口中的方法不能有方法体。

  9. 接口中的常量的public static final可以省略。

  10. 类实现接口要实现所有方法。

    (1)类和类之间叫做继承,类和接口之间叫做实现。【仍然可以将“实现”看做“继承”】

    ​ 继承使用extends关键字完成。

    ​ 实现使用implements关键字完成。

    (2)当一个非抽象的类实现接口的话,必须将接口中所有的抽象方法全部实现(覆盖、重写)

public class Test01 {
    public static void main(String[] args) {
        //父类型的引用指向子类型的对象
        MyMath mm = new MyMathImpl();
        //调用接口里面的方法(面向接口编程)
        int result1 = mm.sum(10 ,20);
        System.out.println(result1);

        int result2 = mm.sub(20 ,10);
        System.out.println(result2);

    }
}
interface MyMath{
    double PI = 3.1415926;
    int sum(int a, int b);
    int sub(int a, int b);
}
class MyMathImpl implements MyMath{
    public int sum(int a, int b){
        return a+b;
    }
    public int sub(int a, int b){
        return a-b;
    }
}
  1. 一个类可以同时实现多个接口。

    这种机制弥补了单继承带来的缺陷。

     public class Test02{
            public static void main(String[] args) {
                // 多态该怎么用呢?
                // 都是父类型引用指向子类型对象
                A a = new D();
                //a.m2(); 
                // 这时编译报错。A接口中没有m2()方法。
                B b = new D();
                C c = new D();
    
                // 这个编译没问题,运行也没问题。
                // 调用其他接口中的方法,你需要转型(接口转型。)
                B b2 = (B)a;
                b2.m2();
    
                // 直接向下转型为D可以吗?可以
                D d = (D)a;
                d.m2();
            }
        }
    interface A{
        void m1();
    }
    
    interface B{
        void m2();
    }
    
    interface C{
        void m3();
    }
    
    // 实现多个接口,其实就类似于多继承。
    class D implements A,B,C{
        // 实现A接口的m1()
        public void m1(){
    
        }
        // 实现B接口中的m2()
        public void m2(){
            System.out.println("m2 ....");
        }
        // 实现接口C中的m3()
        public void m3(){
    
        }
    }
    
    

    接口A和接口B虽然没有继承关系,但是写代码的时候,可以互转。
    编译器没意见。但是运行时可能出现:ClassCastException

    public class Test03{
        public static void main(String[] args){
        
            M m = new E();
            // 经过测试:接口和接口之间在进行强制类型转换的时候,没有继承关系,也可以强转。
            // 但是一定要注意,运行时可能会出现ClassCastException异常。
            // 编译没问题,运行有问题。
            if(m instanceof K){
                K k = (K)m;
            }
        }
    }
    
    interface K{
    }
    
    interface M{
    }
    
    class E implements M{
    }
    
    

    之前有一个结论:
    无论向上转型还是向下转型,两种类型之间必须要有继承关系,
    没有继承关系编译器会报错。(这句话不适用在接口方面。)
    最终实际上和之前还是一样,需要加:instanceof运算符进行判断。
    向下转型养成好习惯。转型之前先if+instanceof进行判断。

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

      extends 关键字在前。

      implements 关键字在后。

      public class Test03{
          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("我是一只会飞的猪!!!");
          }
      }
      
      class Fish implements Flyable{ //没写extends,也是有的,默认继承Object。
          public void fly(){
              System.out.println("我是六眼飞鱼!!!");
          }
      }
      
( 二)接口在开发中的运用

​ 分析:

​ 中午去餐餐馆吃饭,这个过程中有接口吗?

​ 菜单是一个接口。(菜单上有一个抽象的照片:西红柿炒鸡蛋)

​ 谁面向接口调用。(顾客面向菜单点菜,调用接口)

​ 谁负责实现这个接口。(后台的厨师负责把西红柿鸡蛋做好!是接口的实现者。)

​ 这个接口的作用是:这个“菜单”,让“顾客”和“后厨”解“耦合”了。

​ 顾客不用找后厨,后厨不用找顾客。他们之间完全依靠这个抽象的菜单沟通。

package Restaurant;
//接口:菜单,抽象的
public interface FoodMenu {
    // 西红柿炒蛋
    void shiZiChaoJiDan();

    // 鱼香肉丝
    void yuXiangRouSi();
}
package Restaurant;

// 顾客
public class Customer{
    // 顾客手里有一个菜单
    private FoodMenu foodMenu;

    // 如果以下这样写,就表示写死了(焊接了。没有可插拔了。)
    // 中餐厨师
    //ChinaCooker cc;

    // 西餐厨师
    //AmericCooker ac

    // 构造方法
    public Customer(){
    }
    public Customer(FoodMenu foodMenu){
        this.foodMenu = foodMenu;
    }

    // setter and getter
    public void setFoodMenu(FoodMenu foodMenu){
        this.foodMenu = foodMenu;
    }
    public FoodMenu getFoodMenu(){
        return foodMenu;
    }

    // 提供一个点菜的方法
    public void order(){
        // 先拿到菜单才能点菜
        // 调用get方法拿菜单。
        //FoodMenu fm = this.getFoodMenu();
        // 也可以不调用get方法,因为在本类中私有的属性是可以访问
        foodMenu.shiZiChaoJiDan();
        foodMenu.yuXiangRouSi();
    }
}
package Restaurant;

//中餐厨师
// 实现菜单上的菜
// 厨师是接口的实现者。
    public class ChinaCooker implements FoodMenu{

        // 西红柿炒蛋
        public void shiZiChaoJiDan(){
            System.out.println("中餐师傅做的西红柿炒鸡蛋,东北口味!");
        }

        // 鱼香肉丝
        public void yuXiangRouSi(){
            System.out.println("中餐师傅做的鱼香肉丝,东北口味!");
        }
    }


package Restaurant;

//西餐厨师
// 实现菜单上的菜
// 厨师是接口的实现者。
public class AmericaCooker implements FoodMenu{

    // 西红柿炒蛋
    public void shiZiChaoJiDan(){
        System.out.println("西餐师傅做的西红柿炒鸡蛋!");
    }

    // 鱼香肉丝
    public void yuXiangRouSi(){
        System.out.println("西餐师傅做的鱼香肉丝!");
    }
}

package Restaurant;

public class Test{
    public static void main(String[] args){

        // 创建厨师对象
        FoodMenu cooker1 = new ChinaCooker();

        // 创建顾客对象
        Customer customer = new Customer(cooker1);

        // 顾客点菜
        customer.order();
    }
}

注意:

​ 类和类之间的关系:

​ 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的表示“关联关系”

​ 关联关系通常以“属性”的形式存在。

​ A{

​ B b;

​ }

​ like a:

​ cooker like a FoodMenu(厨师像一个菜单一样)

​ 凡是能够满足like a 关系的表示“实现关系”

​ 实现关系通常是:类实现接口。

​ A implements B


(三)抽象类和接口的区别

抽象类是半抽象的,接口是完全抽象的。

抽象类中构造方法,接口中没有构造方法。

接口和接口之间支持多继承,类和类之间只能是单继承。

一个类可以同时实现多个接口,一个抽象类只能继承一个类。(单继承)

接口中只允许出现常量和抽象方法。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/287312.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号