day9 9 抽象类与接口、lambda表达式

9、抽象类与接口

9.1 抽象类

Java 语言提供了两种类,分别为具体类和抽象类。
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,那么这样的类称为抽象类。

在 Java 中抽象类的语法格式如下:

<abstract>class<class_name> {
    <abstract><type><method_name>(parameter-iist);
}

其中,abstract 表示该类或该方法是抽象的;class_name 表示抽象类的名称;method_name 表示抽象方法名称,parameter-list 表示方法参数列表。

如果一个方法使用 abstract 来修饰,则说明该方法是抽象方法,抽象方法只有声明没有实现。(无论是在类还是接口)需要注意的是 abstract 关键字只能用于普通方法,不能用于 static 方法或者构造方法中。

抽象方法的 3 个特征如下:

  1. 抽象方法没有方法体
  2. 抽象方法必须存在于抽象类中
  3. 子类重写父类时,必须重写父类所有的抽象方法
注意:在使用 abstract 关键字修饰抽象方法时不能使用 private 修饰,因为抽象方法必须被子类重写,而如果使用了 private 声明,则子类是无法重写的。

抽象类的定义和使用规则如下:

  1. 抽象类和抽象方法都要使用 abstract 关键字声明。
    如果一个方法被声明为抽象的,那么这个类也必须声明为抽象的。而一个抽象类中,可以有 0~n 个抽象方法,以及 0~n 个具体方法。
  2. 抽象类不能实例化,也就是不能使用 new 关键字创建对象。

Demo

1)首先创建一个表示图形的抽象类 Shape,代码如下所示。

package Abstract_Interface;

public abstract class Shape {
    public double height;
    public double weight;

    //构造方法
   public Shape(double height,double weight){
        this.height=height;
        this.weight=weight;
    }
    //
    public abstract double getArea();//抽象类才有抽象方法,而且没有函数体。
}

2)定义一个正方形类,该类继承自形状类 Shape,并重写了 area( ) 抽象方法。正方形类的代码如下:

package Abstract_Interface;

public class Square extends Shape {
    public Square(double height,double weight){
        super(height,weight);
    }
    //这个时候必须重写父类的抽象方法。否则报错,而且使用注解@Override标识,加不加注解都没问题,只是规范
    @Override
    public double getArea(){
        //可以不使用this,隐式 return this.height*this.weight;
        return height*weight;
    }
}

3)定义一个三角形类,该类与正方形类一样,需要继承形状类 Shape,并重写父类中的抽象方法

package Abstract_Interface;

public class Triangle extends Shape {
    public Triangle(double height,double weight){
        super(height,weight);
    }
    //重写抽象方法
    public double getArea(){
        return 0.5*height*weight;
    }
}

4)最后创建一个测试类,分别创建正方形类和三角形类的对象,并调用各类中的 area() 方法,打印出不同形状的几何图形的面积。测试类的代码如下:

package Abstract_Interface;

/**
 * 定义一个抽象类,实现计算面积
 * 抽象类可以实现如必须具备把方法都实现才能实例化
 * 如线的长度,面积,体积——长方形的周长,面积,体积——长方体的周长,面积,体积
 * 抽象类是对一种事物的抽象,即对类抽。.抽象类是对整个类整体进行抽象,包括属性、行为。
 * Java抽象类和Java接口一样,都用来声明一个新的类型。并且作为一个类型的等级结构的起点。
 */

public   class Abstract_Demo {
    public static void main(String[]args){
        //创建父类发现无法实例化
       // Shape sp = new Shape(1,2);

        //创建方形
        Square sq = new Square(12,44);
        System.out.println(sq.getArea());
        //创建三角形
        Triangle tr = new Triangle(23,45);
        System.out.println(tr.getArea());

    }

}
/*
注意事项:
A:抽象类中不一定有抽象方法,但是有抽象方法的类一定要定义为抽象类。
B:在Java语言中,类有两种,一种是具体类,另一种是抽象类。
具体类可以实例化,抽象类不可以实例化。
C:对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;
D:抽象方法只有声明,没有具体的实现。抽象类是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,就等于白白的创建了这个类。
E:对于一个父类,如果它的一个方法在父类中实现没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为了abstract抽象类。
 */


运行结果:
在这里插入图片描述

9.2 接口(Interface)

接口的用法简介

概念
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)。接口是 Java 中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成。(java8后可以有普通方法,静态方法)

定义接口
Java 接口的定义方式与类基本相同,不过接口定义使用的关键字是 interface,接口定义的语法格式如下:

[public] interface interface_name [extends interface1_name[, interface2_name,]] {
    // 接口体,其中可以包含定义常量和声明方法
    [public] [static] [final] type constant_name = value;    // 定义常量
    [public] [abstract] returnType method_name(parameter_list);    // 声明方法
}

对以上语法的说明如下:

  1. public 表示接口的修饰符,当没有修饰符时,则使用默认的修饰符,此时该接口的访问权限仅局限于所属的包;
  2. interface_name 表示接口的名称。接口名应与类名采用相同的命名规则,即如果仅从语法角度来看,接口名只要是合法的标识符即可。如果要遵守 Java 可读性规范,则接口名应由多个有意义的单词连缀而成,每个单词首字母大写,单词与单词之间无需任何分隔符。
  3. extends 表示接口的继承关系,接口可以多继承;
  4. interface1_name 表示要继承的接口名称;
  5. constant_name 表示变量名称,一般是 static 和 final 型的;
  6. returnType 表示方法的返回值类型;
  7. parameter_list 表示参数列表,在接口中的方法是没有方法体的。
注意:一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类。

接口对于其声明、变量和方法都做了许多限制,这些限制作为接口的特征归纳如下:

  1. 具有 public 访问控制符的接口,允许任何类使用;没有指定 public 的接口,其访问将局限于所属的包。
  2. 方法的声明不需要其他修饰符,在接口中声明的方法,将隐式地声明为公有的(public)和抽象的(abstract)。
  3. 在 Java 接口中声明的变量其实都是常量,接口中的变量声明,将隐式地声明为 public、static 和 final,即常量,所以接口中定义的变量必须初始化。
  4. 接口没有构造方法,不能被实例化。
    例如:
public interface A {
    publicA(){}    // 编译出错,接口不允许定义构造方法
}

一个接口不能够实现另一个接口,但它可以继承多个其他接口。**子接口可以对父接口的方法和常量进行重写。**例如:

public interface StudentInterface extends PeopleInterface {
    // 接口 StudentInterface 继承 PeopleInterface
    int age = 25;    // 常量age重写父接口中的age常量
    void getInfo();    // 方法getInfo()重写父接口中的getInfo()方法
}

例如,定义一个接口 MyInterface,并在该接口中声明常量和方法,如下:

public interface MyInterface {    // 接口myInterface
    String name;    // 不合法,变量name必须初始化
    int age = 20;    // 合法,等同于 public static final int age = 20;
    void getInfo();    // 方法声明,等同于 public abstract void getInfo();
}

实现接口

接口的主要用途就是被实现类实现,一个类可以实现一个或多个接口,继承使用 extends 关键字,实现则使用 implements 关键字。因为一个类可以实现多个接口,这也是 Java 为单继承灵活性不足所作的补充。类实现接口的语法格式如下:

<public> class <class_name> [extends superclass_name] [implements interface1_name[, interface2_name…]] {
    // 主体
}

对以上语法的说明如下:

  1. public:类的修饰符;
  2. superclass_name:需要继承的父类名称;
  3. interface1_name:要实现的接口名称。

实现接口需要注意以下几点:
1)实现接口与继承父类相似,一样可以获得所实现接口里定义的常量和方法。如果一个类需要实现多个接口,则多个接口之间以逗号分隔。
2)一个类可以继承一个父类,并同时实现多个接口,implements 部分必须放在 extends 部分之后。
一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些抽象方法);否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类。

Demo
1.定义接口 Circle_Interface

package Abstract_Interface;

public interface Circle_Interface {
    //必须实现的常量,默认属性  public static final
    float pai = 3.14f;

    //定义方法体,在之前是不允许的,后来才加上——java8环境下
    // 方法的声明不需要其他修饰符,在接口中声明的方法,将隐式地声明为公有的(public)和抽象的(abstract)。

    //1.静态方法,可以有函数体,默认public
     static double Volume(){
        System.out.println("Circle_Interface的静态方法");
        return 1;
    }
    //抽象方法
    double getArea();//只要是抽象方法都无法拥有函数体,只能在继承的类或者实现该接口的类重写

    //普通方法的定义,使用default
    default double getLength(){
        System.out.println("Circle_Interface的普通方法");
        return 0;
    }

}

2.实现接口

package Abstract_Interface;

public class InterFace_Demo implements Circle_Interface{
    private double radius;

    //定义一个构造方法
    public InterFace_Demo(double radius){
        this.radius = radius;
    }

    //应该加@Override声明为重写
    @Override
    public double getArea(){
        return pai*radius*radius;
    }
    @Override
    public double getLength(){
        return pai *radius*2;
    }

    public static void main(String[]args){
        InterFace_Demo circle = new InterFace_Demo(4);

        //计算面积,接口的抽象方法必须重写
        System.out.println(circle.getArea());

        //计算周长,如果当前类没有重写接口中的默认方法,默认调用接口的该方法 0
        System.out.println(circle.getLength());

        //调用接口里边的静态方法,但是只能自己调用,通过接口名调用
        System.out.println(Circle_Interface.Volume());
    }
}

运行结果:
在这里插入图片描述

抽象类与接口的一些关系

  • 接口没有构造方法,抽象类具有构造方法;
  • 接口中的成员域默认是具有public、static、final属性的,而抽象类中的成员域要看自己是怎么定义的~
  • 接口,多态,弥补单继承
  • 现在接口和抽象类越来越相似了,现在不同点也就剩下:继承1个和实现多个的区别了。
  • 此外,值得注意的是:面向对象中,java只是支持单继承,不支持多继承,一个类只能继承一个类
  • 接口是对行为的抽象。接口是对类局部(行为)进行抽象。

如果多个接口定义了同样的静态方法,

  • 即使存在实现类,同时实现多个接口,仍然是不可使用实现类名调用接口的方法

如果多个接口定义了同样的默认方法

  • 实现类实现多个接口时,必须重写掉默认方法,否则编译失败。
  • 在接口中可以定义实现的方法体是java8的一大特性,可以定义多个静态或者默认的方法,静态必须加上static,默认方法必须加上default关键字。

使用接口的原因

  • 没有接口,可插入性就没有保证。因为Java是单继承的。
  • 在一个类等级结构中的任何一个类都可以实现一个接口,如果这个类实现了这个接口那么将会影响到此类的所有子类,但是不会影响到此类的所有父类。
  • 一个类最多有一个父类,但是可以同时实现几个接口。

如果一个抽象类不包含任何抽象方法,为何还要设计为抽象类?

个人理解:

  • 抽象类目的是用来继承的,在定义上,可以没有抽象方法,只是用abstract修饰是没有语法错误的,但是没有的实际意义。抽象类中的抽象方法是让子类继承抽象类,来实现抽象类中的抽象方法,根据子类的需求分别来实现不同的功能。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨夜※繁华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值