Java开发 | 抽象类 | 接口 | Object类 | equals方法
创始人
2025-06-01 16:00:10
0

前言

大家好,我还是那个不会打拳的程序猿。本期给大家带来的是抽象类、接口、Object类的讲解。文章通过抽象类的基本概念、抽象类的具体实现和接口的基本概念、接口的实现。再到Object的基本概念以及Object实现重写equals方法来讲解,文章图文并茂值得阅读。

目录

1.抽象类

1.1抽象类的概念

1.2抽象类语法

1.3抽象类的特性

2.接口

2.1接口的概念

2.2语法规则

2.3接口的特性

2.4接口间的继承

2.5继承与接口同时继承

2.6接口使用实例

2.7抽象类与接口类的区别

3.Object类

3.1对象比较equals方法


1.抽象类


1.1抽象类的概念

在面向对象中,所有对象都是依靠类来描述的。但是如果一个类中无法完整的描述到另一个类的具体信息时,这样我们就把这个类叫做抽象类。比如:

说明:

  1. 在蔬菜Vegetable类中,拥有eat()方法,eat()方法代表蔬菜可以吃。但不能代表所有蔬菜的口味,因此无法实现各个蔬菜的eat()方法。
  2. 小白菜是蔬菜,因此Pakchou与蔬菜Vegetable类为继承关系,但小白菜吃起来是清甜的,只有自己的eat()方法能够实现。
  3. 西红柿也是蔬菜,因此Tomato与蔬菜Vegetable类为继承关系,但西红柿吃起来是酸甜的,只有自己的eat()方法能够实现。
  4. 苦瓜也是蔬菜,因此Bitter与蔬菜Vegetable类为继承关系,但苦瓜吃起来是苦,只有自己的eat()方法能够表示。
  5. 因此Vegetable可以设计为“抽象类”。

1.2抽象类语法

抽象类语法格式为:abstract class 类名{}式,抽象类是由abstract修饰的,再就是类的统一标志class再加上类名。如一个蔬菜类:

abstract class Vegetable {//成员变量public int num;//成员方法public void fun(){}//抽象方法abstract void show();//构造方法public void Vegetable() {}
}

抽象类也是类,内部可以包含普通方法和属性,甚至构造方法。


1.3抽象类的特性

特性1,抽象类中不一定要有抽象方法

abstract class Vegetable {public void eat() {System.out.println("蔬菜好处");}
}

抽象类里面有普通的方法也是可以的,并不局限于只能有抽象方法。


 特性2,抽象类里面的抽象方法可以不初始化定义

abstract class Vegetable {abstract void show();
}

抽象类里面的抽象方法可以不用初始化,直接用分号(;)结束。


 特性3,一个类继承了抽象类,那么这个类一定要重写抽象类中的抽象方法

abstract class Vegetable {abstract void show();
}
class Tomato extends Vegetable {
}

运行后输出

 因此,当我们抽象类里面有抽象方法时,只要是有子类继承了这个抽象类就必须在子类中覆盖抽象方法,我们应该这样去写代码:

abstract class Vegetable {abstract void show();
}
class Tomato extends Vegetable {public void show() {}
}

特性4,抽象类不能被实例化,但能实例化子类对象。

abstract class Vegetable {public void eat() {System.out.println("蔬菜好吃");}
}
public class Test {public static void main(String[] args) {Vegetable vegetable = new Vegetable();}
}

运行后输出:

 但我们使用抽象类实例化子类对象时。

abstract class Vegetable {public void eat() {System.out.println("蔬菜好处");}
}
class Tomato extends Vegetable {@Overridepublic void eat() {System.out.println("西红柿酸甜");}
}
public class Test {public static void main(String[] args) {Vegetable vegetable = new Tomato();vegetable.eat();}
}

运行后输出

 我们可以看到,抽象类Vegetable可以实例化它的子类对象Tomato。


特性5,抽象方法不能被private、static、final修饰,要满足重写的规则

abstract class Vegetable {abstract private void show();abstract final void fun();abstract private void show();
}

运行后输出:


特性6,抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

abstract class Vegetable {public Vegetable(int a,int b ) {System.out.println(a+b);}
}
class Tomato extends Vegetable {public Tomato(int a,int b) {super(a,b);}public void show() {}
}
public class Test {public static void main(String[] args) {Vegetable vegetable = new Tomato(2,3);}
}

运行后输出:


2.接口


2.1接口的概念

接口在我们生活中有USB接口,插排接口等等。USB接口专门是用来传输数据或者充电的,插排接口有两孔插排与三孔插排。

那么这些接口都是有规定的,规定了实现什么样的操作。USB接口就连接数据,插排就用来充电,这就是他们的规范。因此Java里面也有自己的规范和操作,这些规范和操作我们称之为接口


2.2语法规则

接口是通过关键字interface来定义的,在类的基础上把class改为interface即可。

interface IUSB {//...
}

以上就是一个接口的定义,定义了一个名为IUSB的接口。

提示:

  1. 创建接口时, 接口的命名一般以大写字母 I 开头.
  2. 接口的命名一般使用 "形容词" 词性的单词.
  3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性. 

2.3接口的特性

(1)接口不能被实例化

interface Usb {//...
}
public class Test {public static void main(String[] args) {//接口不能被实例化Usb usb = new Usb();}
}

运行后输出: 

 当我们,实例化一个接口后,编译会认为这个接口为抽象的,因此我们认为接口不能实例化。


(2)接口中定义成员变量时必须初始化

interface Usb {//接口内的成员变量未初始化public int num;public String name;
}
public class Test {public static void main(String[] args) {}
}

运行后输出: 

当我们没有对接口内的成员变量进行初始化就运行后,就会报错,因此我们应该初始化接口内成员变量。


(3)接口内的成员变量默认为public static final类型 

interface Animal {//完整的定义public static final int num = 10;//编译器会默认加上public static finalString nam = "abc";
}

如果我们的变量没有,加上public static final的话,编译器会默认给这些变量加上。


 (4)接口内的方法默认为抽象方法

interface Usb {//抽象方法public abstract void show();//省略了public abstract 但编译器会默认加上void fun();
}

(5)接口里面的方法不能有内容

interface Usb {//有方法体的方法public void show() {}
}
public class Test {public static void main(String[] args) {}
}

运行后输出:

以上代码展示接口内定义方法时,方法里面不能带有方法体也就是{},但在接口内方法是可以定义的不初始化的。如:

interface Usb {//没有方法体的方法public void show();
}
public class Test {public static void main(String[] args) {}
}

我们只需要在这个方法后面用分号(;)结束就好了。 


(6)要实现接口中的方法得加上default

//名为Usb的接口
interface Usb {//default修饰的方法可以在接口内有方法体default void show(){System.out.println("今天");}
}

(7)接口内不能有构造方法

interface Usb {public int num = 10;//接口中不能有构造方法public int Usb(int num){}
}

 运行后输出:

以上代码运行后结果跟接口里面的方法不能有内容是一样的。


(8)接口内可以有static修饰的方法 

interface Animal {public static void eat() {System.out.println("动物爱吃粮");}
}

当我们运行以上代码是完全可以通过的。


 (9)继承接口时,用implements来修饰接口名

interface Usb {public int num = 10;
}//继承接口用implements
class Fun implements Usb {}

 跟普通类继承不一样,普通类是靠extends来继承,而接口是靠implements来继承的。


2.4接口间的继承

接口之间的继承也是用到extends关键字,接口可以实现单继承和多继承与多层继承

(1)单继承

interface A {}
interface B extends A {}

所谓单继承,就像接口2继承接口1,在上述代码中展现的就是B接口继承A接口。 

(2)多层继承

interface A {}
interface B extends A {}
interface C extends B {}

 多层继承就是接口3继承接口2,接口2继承接口1这种,上述代码展现的是C继承B,B继承A。

(3)多继承 

interface A {}
interface B {}
interface C extends A,B {}

多继承,就是一个接口继承多个接口。在我们的类之间继承中这样是不可行的,但是在接口之间这样是完全可以的。


2.5继承与接口同时继承

当有以下代码:

abstract class Animal {public void run() {System.out.println("跑");}
}class Dog extends Animal  {@Overridepublic void run() {super.run();}
}class Bird extends  Animal {@Overridepublic void run() {super.run();}
}public class Test {public static void main(String[] args) {Dog dog = new Dog();Bird bird = new Bird();dog.run();bird.run();}
}

 运行后输出:

以上代码中,当Dog类继承Animal类时里面的run方法是适合Dog类的因为狗的行走方式是跑,而Bird类继承Animl后里面的run方法并不适合Bird类。因为鸟的行走方式是飞,因此我们可以通过一个接口来提供鸟类需要的方法。

abstract class Animal {public void run() {System.out.println("跑");}
}class Dog extends Animal  {@Overridepublic void run() {super.run();}
}interface Irun {void run();
}class Bird extends  Animal implements Irun{@Overridepublic void run() {System.out.println("飞");}
}
public class Test {public static void main(String[] args) {Dog dog = new Dog();Bird bird = new Bird();dog.run();bird.run();}
}

运行后输出: 

 我们可以发现,Bird类继承了Animal类并且继承了Irun接口。最终到了鸟可以飞的一个效果。


2.6接口使用实例

(1)实现简单继承接口

我们知道,接口内的方法是抽象方法。因此,当子类继承了这个接口时,子类里面应当重写接口内的方法。

interface Animal {void eat();
}class Dog implements Animal {@Overridepublic void eat() {System.out.println("吃狗粮");}
}
public class Test {public static void main(String[] args) {Animal animal = new Dog();animal.eat();}
}

运行后输出: 

 以上代码就很好的展示了,继承接口重写方法并输出。


(2)实现类名引用

从上方2.4中我学到了接口里面可以有static修饰的方法,因此当我们的接口里有静态方法时,也是可以直接使用类名来引用的。

interface Animal {public static void eat() {System.out.println("动物爱吃粮");}
}public class Test {public static void main(String[] args) {Animal.eat();}
}

 运行后输出:


(3)实现USB接口

//IUSB.java文件下
public interface IUSB {//打开void open();//结束void close();}
//Mouse.java文件下
public class Mouse implements IUSB{@Override//重写打开public void open() {System.out.println("鼠标点击开始");}//重写关闭@Overridepublic void close() {System.out.println("鼠标点击结束");}//鼠标的操作public void mouseSerive() {System.out.println("点击中~~~~");}
}
//KeyBoard.java文件下
public class KeyBoard implements IUSB{@Override//重写打开public void open() {System.out.println("键盘打印开始");}//重写关闭@Overridepublic void close() {System.out.println("键盘打印结束");}//键盘的操作public void keyBoardSerive() {System.out.println("打印中~~~~");}
}
//Computer.java文件下
public class Computer {public static void serive(IUSB str) {str.open();if (str instanceof Mouse) {//向下转型,因为IUSB接口内没有mouseSerive方法Mouse mouse = (Mouse) str;mouse.mouseSerive();}else if (str instanceof KeyBoard) {//向下转型,因为IUSB接口内没有keyBoardSerive方法KeyBoard keyBoard = (KeyBoard) str;keyBoard.keyBoardSerive();}str.close();}public static void main(String[] args) {//Mouse的匿名对象传给servie方法serive(new Mouse());//KeyBoard的匿名对象传给servie方法serive(new KeyBoard());}
}

运行后输出:

鼠标点击开始
点击中~~~~
鼠标点击结束
键盘打印开始
打印中~~~~
键盘打印结束

通过以上几个例子,我们可以发现接口是可以向上转型、向下转型、可以实现多态等效果的。


2.7抽象类与接口类的区别

抽象类使用abstract加上class修饰,而接口类使用interface代替class修饰。

abstract class Animal {}
interface IUSB{}

 接口里面的成员方法以及成员变量默认为public static final修饰的。

interface IUSB{//全面写法public static final int num = 10;//编译器默认为public static final name = "张三";String name = "张三";
}

抽象类里面的方法被子类继承时子类不必重写此方法,接口类里面的方法被继承时子类必须重写此方法。继承抽象类用关键字extends,继承接口类用implements。

interface IUSB{void show();
}class Try implements IUSB {@Overridepublic void show() {}
}
abstract class Animal {public void fun() {}
}
class Dog extends Animal {
}

 抽象类里面的成员变量可以不初始化,而接口类里面的成员变量必须初始化。

interface IUSB{public String name;public int age;
}
abstract class Animal {public String name;public int age;
}

出现警告:


抽象类里面的方法可以有代码块,而接口类里面的方法不能有代码块。

interface IUSB{void show(){}
}
abstract class Animal {public void show() {}
}

运行后输出: 


3.Object类

Object类是所有类的父类,从何体现,请看下方代码:

//一个狗类继承了Object类
class Dog extends Object{}
//一个猫类继承了Object类
class Cat extends Object{}
//一个抽象类继承了Object类
abstract class Brid extends Object {}public class Test {public static void main(String[] args) {//obj引用了一个Object类对象Object obj = new Object();}
}

通过以上代码,我们可以看到。我们的普通类、抽象类、实例化对象。都可以用Object类来继承或产生对象。


3.1对象比较equals方法

当我们有这样一个代码:

class Student {public String name;public int age;public int score;}public class Test {public static void main(String[] args) {Student student1 = new Student();Student student2 = new Student();student1.name = "zhangsan";student2.name = "zhangsan";boolean flag = student1.equals(student2);System.out.println(flag);}
}

运行后输出:

此时我们就有了疑问,明明student1和student2引用了两个对象值是一样为啥还返回false呢?因为此时我们在调用equals方法的时候,调用的是Object类里面的equals方法,我们可以看到毫无用处。以下为Object类里面的equals方法:

而我们真正需要调用的是String里面的equals方法,也就是以下的代码:

    public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}

 因此我们得在Student类里面重写一个equals方法来达到我们想要的效果。

class Student {public String name;public int age;public int score;@Overridepublic boolean equals(Object obj) {Student student = (Student) obj;if (this.name.equals(student.name)) {return true;}return false;}
}public class Test {public static void main(String[] args) {Student student1 = new Student();Student student2 = new Student();student1.name = "zhangsan";student2.name = "zhangsan";boolean flag = student1.equals(student2);System.out.println(flag);}
}

运行后输出:

我们可以看到输出的是true,唯一的难点就是Class类里面的this.name是哪个对象。我们知道在对象的创建时第一条被创建的对象,就是该类的的对象。因此我们的student1这个引用代表的就是Student类。因此student1为当前的对象,所以this.name为student1中的name。而我们在main方法中传参给我们重写的equals方法的参数是student2引用的对象中的name。相信大家把这两个引用区分开了,就不难理解了。

因此,我们可以发现所有的类都可以引用到Object类但是如果我们没有利用好Object类就不会达到我们想要实现的效果。因此我们在使用Object类的时候要三思而行。


好了,本次的博文到这里就结束了,感谢您的阅读。如有收获还请给博主一个小小的关注,感谢您的支持。

下期预告:图书管理系统

相关内容

热门资讯

原生安卓系统怎样升级,从基础到... 你有没有发现,你的安卓手机用久了,有时候就像老牛拉车一样,慢吞吞的?别急,今天就来给你支个招,让你的...
安卓13系统怎么开发,开发者的... 你有没有听说安卓13系统已经发布了?这可是个大新闻呢!作为一个热衷于手机开发的小伙伴,你是不是也跃跃...
安卓q系统镜像下载,轻松升级体... 你有没有听说安卓Q系统已经发布了?这可是安卓家族里的一大亮点呢!今天,我就要来给你详细介绍一下安卓Q...
安卓系统色彩校正软件,打造个性... 你有没有发现,手机屏幕的色彩有时候会让人感觉不太对劲?有时候,画面看起来有点灰蒙蒙的,有时候又太艳丽...
苹果能否下个安卓系统,开启新篇... 你有没有想过,苹果的iOS系统会不会有一天突然宣布,它要拥抱安卓的大家庭呢?想象iPhone和iPa...
树莓派 装 安卓系统,轻松安装... 你有没有想过,用树莓派装上安卓系统,那会是怎样一番景象呢?想象一个迷你电脑,竟然能运行起我们日常使用...
安卓系统怎么打印小票,安卓系统... 你是不是也遇到了这样的烦恼:手机里存了好多重要的小票,但是想打印出来保存或者报销,却发现安卓系统里的...
安卓10安装系统应用,轻松上手... 你有没有发现,你的安卓手机最近是不是有点儿“慢吞吞”的?别急,别急,今天就来给你支个招——升级安卓1...
美国不提安卓系统华为,迈向自主... 华为与美国:一场关于技术、市场与政策的较量在当今这个数字化的世界里,智能手机已经成为我们生活中不可或...
安卓系统怎么打开ppt,选择文... 你有没有遇到过这种情况:手里拿着安卓手机,突然需要打开一个PPT文件,却怎么也找不到方法?别急,今天...
谷歌退回到安卓系统,探索创新未... 你知道吗?最近科技圈可是炸开了锅,谷歌竟然宣布要退回到安卓系统!这可不是一个简单的决定,背后肯定有着...
安卓系统待机耗电多少,深度解析... 你有没有发现,手机电量总是不经用?尤其是安卓系统,有时候明明没怎么用,电量就“嗖”的一下子就下去了。...
小米主题安卓原生系统,安卓原生... 亲爱的手机控们,你是否曾为手机界面单调乏味而烦恼?想要给手机换换“衣服”,让它焕然一新?那就得聊聊小...
voyov1安卓系统,探索创新... 你有没有发现,最近你的手机是不是变得越来越流畅了?没错,我要说的就是那个让手机焕发青春的Vivo V...
电脑刷安卓tv系统,轻松打造智... 你有没有想过,家里的安卓电视突然变得卡顿,反应迟钝,是不是时候给它来个“大保健”了?没错,今天就要来...
安卓系统即将要收费,未来手机应... 你知道吗?最近有个大消息在科技圈里炸开了锅,那就是安卓系统可能要开始收费了!这可不是开玩笑的,这可是...
雷凌车载安卓系统,智能出行新体... 你有没有发现,现在的汽车越来越智能了?这不,我最近就体验了一把雷凌车载安卓系统的魅力。它就像一个聪明...
怎样拍照好看安卓系统,轻松拍出... 拍照好看,安卓系统也能轻松搞定!在这个看脸的时代,拍照已经成为每个人生活中不可或缺的一部分。无论是记...
安卓车机系统音频,安卓车机系统... 你有没有发现,现在越来越多的汽车都开始搭载智能车机系统了?这不,咱们就来聊聊安卓车机系统在音频方面的...
老苹果手机安卓系统,兼容与创新... 你手里那台老苹果手机,是不是已经陪你走过了不少风风雨雨?现在,它竟然还能装上安卓系统?这可不是天方夜...