[Java] 抽象类、final类和接口

信仰:一个人走得远了,就会忘记自己为了什么而出发,希望你可以不忘初心,不要随波逐流,一直走下去
博客主页:程序喵正在路上 的博客主页
欢迎关注点赞收藏留言
本文由 程序喵正在路上 原创,CSDN首发!
系列专栏:Java学习
首发时间:2022年5月10日
✅如果觉得博主的文章还不错的话,希望小伙伴们三连支持一下哦

目录

  • 抽象类
    • 抽象方法
  • final类与final方法
    • 为何需要final类
    • 为何需要final方法
  • Java中的接口
    • 定义接口
    • 实现接口

抽象类

Java 中有两个特殊的类,分别为抽象类final 类。抽象类的特殊性在于,在抽象类中包含只做声明不去实现的方法,抽象类不能被实例化(也就是不能使用 new 关键字来创建对象)。

所谓抽象类,就是只声明方法的存在而不去具体实现它的类。抽象类不能被实例化,也就是不能创建其对象。在定义抽象类时,要在关键字 class 前面加上关键字 abstract,具体格式如下。

abstract class 类名 {
	类体
}

抽象类提供了一个继承的出发点。具体类则不同,具体类可以实例化,因此若一个程序员设计了一个抽象类,那一定是用来继承的,而若声明了一个具体类,那一定不是用来被继承的。

下面我们定义一个名称为 Fruit 的抽象类。

abstract class Fruit {			//定义抽象类
	public String color;		//定义颜色成员变量
	//定义构造方法
}

抽象方法

在抽象类中创建的没有实际意义的必须要子类重写的方法称为抽象方法。抽象方法只有方法的声明,没有方法的实现代码,用关键字 abstract 进行修饰。声明一个抽象方法的基本格式如下。

abstract <方法返回值类型> 方法书 (参数列表)

方法返回值类型:必选参数,用于指定方法的返回值类型,如果该方法没有返回值,
可以使用关键字 void 进行标识。方法返回值的类型可以是任意 Java 数据类型。

方法名:选参数,用于指定抽象方法的名称,方法名必须是合法的Java标识符。

参数列表:可选参数,用于指定方法中所需的参数。当存在多个参数时,各参数之间应使用逗号分隔。方法的参数可以是任意 Java 数据类型。

在上面定义的抽象类中添加一个抽象方法。

//定义抽象方法
public abstract void harvest(); 	//收获的方法

注意

(1) 抽象方法不能使用 privatestatic 关键字进行修饰。
(2) 包含一个或多个抽象方法的类必须被声明为抽象类,这是因为抽象方法没有定义方法的实现部分,如果不声明为抽象类,这个类将可以生成对象,这时当用户调用抽象方法时,程序就不知道如何处理了。

下面通过一个具体的实例介绍如何定义抽象类及抽象方法。定义一个抽象类水果类 Fruit,并在该类中定义一个抽象方法,同时在其子类中通过覆盖的方法实现该抽象方法。

(1) 创建一个抽象类 Fruit

abstract class Fruit {          //定义抽象类
    public String color;        //定义成员变量 color

    //构造方法
    public Fruit(){
        color = "绿色";           //对变量 color 进行初始化
    }

    //定义抽象方法
    public abstract void harvest();     //收获的方法
}

(2) 创建一个 Fruit 类的子类 Apple

public class Apple extends Fruit {
    public void harvest() {
        System.out.println("苹果已经收获");
    }
}

(3) 创建一个 Fruit 类的子类 Orange

public class Orange extends Fruit {
    public void harvest() {
        System.out.println("桔子已经收获");
    }
}

(4) 创建一个包含 main() 方法的测试类 FruitDemo,在测试类中执行 Fruit 类的两个子类的 harvest() 方法

public class FruitDemo {
    public static void main(String[] args) {
        System.out.println("调用Apple类的harvest()方法的结果是:");
        Fruit apple = new Apple();      //声明 Apple 类的一个对象 apple,并为其分配内存
        apple.harvest();                //调用 Apple 类的 harvest()方法

        System.out.println("调用Orange类的harvest()方法的结果是:");
        Fruit orange = new Orange();    //声明 Orange 类的一个对象 orange,并为其分配内存
        orange.harvest();               //调用 Orange 类的 harvest()方法
    }
}

测试类执行结果如下:

调用Apple类的harvest()方法的结果是:
苹果已经收获
调用Orange类的harvest()方法的结果是:
桔子已经收获

final类与final方法

如果希望一个类不允许任何类继承,并且不允许别人对这个类进行任何改动,可以将这个类设置为 final 类。如果希望定义一个不能被改动的方法,可以将这个方法定义为 final 方法。

为何需要final类

使用关键字 final 进行修饰的类称为 final 类,该类不能被继承,即不能有子类。有时为了程序的安全性,可以将一些重要的类声明为 final 类,例如,Java 提供的 System 类和 String 类,这两个类对编译器和解释器的正常运行起到很大的作用,不能被轻易改变,所以被声明为 final 类。

final 类的基本声明格式如下。

final class 类名 {
	类体
}

声明一个名称为 FinalClass 的 final 类,在该类的主方法中对变量进行自增操作。

final class FinalClass {
    int a = 3;

    void show() {
    }

    public static void main(String[] args) {
        FinalClass f = new FinalClass();
        f.a++;
    }
}

为何需要final方法

将方法定义为 final 类型,可以防止任何子类修改该类的定义与实现方式,同时,final 方法的执行效率要高于非 final 方法。在修饰权限中有 private修饰符,如果一个父类的某个方法被设置为 private 修饰符,子类将无法访问该方法,自然无法覆盖该方法,所以一个定义为 private 的方法隐式被指定为 final 类型,这样就无须将一个定义为 private 的方法再定义为 final 类型。

创建父类 Parent,在该类中定义 final 方法与普通方法,创建该类的子类 Son,覆盖父类方法。

Parent 类代码如下:

public class Parent {
    final void show1(){
        System.out.println("父类.show1()");
    }

    public void show2(){
        System.out.println("父类.show2()");
    }
}

Son 类代码如下:

public class Son extends Parent {
    public void show2() {
        System.out.println("子类.show2()");
    }
}

如果将父类的 show2() 方法的修饰符改为 final,那么程序就会出错。

Java中的接口

提到接口,相信大家都不会感到陌生,在日常生活中就会接触到一些接口,如 USB 接口。为什么在购买 U 盘的时候,商家不需要问你 USB 是什么型号,也不需要问满足什么要求?这是因为 USB 接口是统一的,是固定不变的一种型号,是一种规范。所有的厂家都会按照这个规范制造相应 USB 接口的U盘。规范也就是指要求 U 盘该做什么,但并不说明应该如何去做。

Java 中的接口也是一种规范,在接口中只定义方法名,但是没有方法体,也就是说,接口只定义了类应该做什么,但是不关心如何去做。定义接口是为了方便沟通,因为大家都使用同一个接口,所以在沟通上就会变得很容易,不用为当别人提问时应用什么话来应答而烦恼。

定义接口

Java 中的接口是一些方法特征的集合,接口中只有方法的特征,没有方法的实现,也就是说,接口中的方法都是抽象方法。接口更加灵活,一个对象可以实现多个接口,使用接口可以实现 C++ 语言中的多继承,但是使用方法更加简单了。

定义接口可以通过 interface 关键字,接口的定义与类的定义类似,也是分为接口的声明和接口体两部分。其中,接口体由常量定义和方法定义两部分组成。定义接口的基本格式如下。

[修饰符] interface 接口名 [extends 父接口名列表] {
  [public] [static] [final] 常量;
  [public] [abstract] 方法;
}

修饰符可选,用于指定接口的访问权限,可选值为 public。如果省略,则使用默认的访问权限。

接口名必选参数,用于指定接口的名称,接口名必须是合法的 Java 标识符,一般情况下要求首字母大写。

extends 父接口名列表:可选参数,用于指定要定义的接口继承自哪个父接口。当使用 extends 关键字时,父接口名为必选参数。

方法:接口中的方法只有定义而没有实现。

因为接口是为外界提供访问服务的,因此接口中的方法必须为 public,即使在接口中技巧声明方法时不使用 “public”,也默认为 public,并且在接口中不允许定义 privateprotected 方法。

例如,定义一个用于计算的接口,在该接口中定义一个常量 PI 和两个方法。

public interface Calculate {
    final float PI = 3.14159f;      //定义一个用于表示圆周率的常量 PI
    float getArea(float r);         //定义一个用于计算面积的方法 getArea()
    float getCircumstance(float r); //定义一个用于计算周长的方法 getCircumstance()
}

Java 的类文件一样,接口文件的文件名必须与接口的名称相同。

实现接口

Java 不支持多继承,要想实现多继承,可以通过实现接口来进行。实现接口可以通过关键字 implements,其基本格式如下。

[修饰符] class <类名> [extends父类名] [implements 接口列表] {
}

修饰符:可选参数,用于指定类的访问权限,可选值为 publicabstractfinal

类名:必选参数,用于指定类的名称,类名必须是合法的 Java 标识符,一般情况下要求首字母大写。

extends父类名:可选参数,用于指定要定义的类继承自哪个父类。当使用 extends 关键字时,父类名为必选参数。

implements 接口列表:可选参数,用于指定该类实现的是哪些接口。当使用 implements 关键字时,接口列表为必选参数。当接口列表中存在多个接口名时,各个接口名之间使用逗号分隔。

在类中实现接口时,方法的名字、返回值类型、参数的个数及类型必须与接口中的完受全一致,并且必须实现接口中的所有方法。

编写一个名称为 Calculater 的类,该类实现自定义的接口 Calculate

public class Calculater implements Calculate {
    //定义计算圆面积的方法
    public float getArea(float r) {
        float area = PI * r * r;
        return area;
    }

    //定义计算圆周长的方法
    public float getCircumference(float r) {
        float circumference = 2 * PI * r;
        return circumference;
    }
}

在类的继承中,只能做单重继承,而在实现接口时,一次可以实现多个接口,每个接口间使用逗号 “,” 分隔。这时就可能出现常量名或方法名冲突的情况。如果常量名冲突,则需要明确指定常量的接口,这可以通过 “接口名.常量” 实现;如果出现方法名冲突,则只要实现一个方法就可以了。下面通过一个具体的实例详细介绍以上问题的解决方法。

定义两个接口,并且在这两个接口中声明一个同名的常量和一个同名的方法,然后再定义一个同时实现这两个接口的类。

(1) 创建一个名称为 Calculate 的接口,在该接口中声明一个常量和两个方法,具体代码如下。

public interface Calculate {
    final float PI = 3.14159f;      //定义一个用于表示圆周率的常量 PI
    float getArea(float r);         //定义一个用于计算面积的方法 getArea()
    float getCircumstance(float r); //定义一个用于计算周长的方法 getCircumstance()
}

(2) 创建一个名称为 GeometryShape 的接口,在该接口中声明一个常量和 3 个方法,具体代码如下。

public interface GeometryShape {
    final float PI = 3.14159f;          //定义一个用于表示圆周率的常量 PI
    float getArea(float r);             //定义一个用于计算面积的方法 getArea()
    float getCircumference(float r);    //定义一个用于计算周长的方法 getCircumstance()
    void draw();                        //定义一个绘图方法
}

(3) 创建一个名称为 Circ 的类,该类实现 CalculateGeometryShape 接口,具体代码如下。

public class Circ implements Calculate, GeometryShape {
    //定义计算圆面积的方法
    public float getArea(float r) {
        float area = Calculate.PI * r * r;
        return area;
    }

    //定义计算圆周长的方法
    public float getCircumference(float r) {
        float circumference = 2 * Calculate.PI * r;
        return circumference;
    }

    //定义一个绘图的方法
    public void draw() {
        System.out.println("画一个图形");
    }

    //定义主方法测试程序
    public static void main(String[] args) {
        Circ circ = new Circ();
        float r = 3;
        float area = circ.getArea(r);
        System.out.println("圆的面积为:" + area);

        float circumference = circ.getCircumference(r);
        System.out.println("圆的周长为:" + circumference);

        circ.draw();
    }
}

(4) 运行本实例,结果如下:

圆的面积为:28.274311
圆的周长为:18.84954
画一个图形

这次的分享就到这里啦,继续加油哦^^
有出错的地方欢迎在评论区指出来,共同进步,谢谢啦

你可能感兴趣的:(Java学习,java,开发语言)