【JAVA】抽象类与接口--下

news2024/11/16 14:25:10

⭐ 作者:小胡_不糊涂
🌱 作者主页:小胡_不糊涂的个人主页
📀 收录专栏:浅谈Java
💖 持续更文,关注博主少走弯路,谢谢大家支持 💖

抽象类与接口

  • 1. 实现多个接口
  • 2. 接口间的继承
  • 3. Clonable接口和深拷贝
  • 4. 抽象类和接口的区别
  • 5. Object类
    • 5.1 获取对象信息
    • 5.2 对象比较equals方法
    • 5.3 hashcode方法

在这里插入图片描述

1. 实现多个接口

在Java中,类和类之间是单继承的,一个类只能有一个父类,即Java中不支持多继承,但是一个类可以实现多个接口。

通过类来表示一组动物:

class Animal {
	protected String name;
	public Animal(String name) {
	this.name = name;
	}
}

另外我们再提供一组接口,分别表示“会飞的”,“会跑的”,“会游泳的”:

interface IFlying {
	void fly();
}
interface IRunning {
	void run();
}
interface ISwimming {
	void swim();
}

接下来我们创建几个具体的动物:

猫,是会跑的

class Cat extends Animal implements IRunning {
	public Cat(String name) {
	super(name);
	}
	@Override
	public void run() {
	System.out.println(this.name + "正在用四条腿跑");
	}
}

鱼,是会游的

class Fish extends Animal implements ISwimming {
	public Fish(String name) {
		super(name);
	}
	@Override
	public void swim() {
		System.out.println(this.name + "正在用尾巴游泳");
	}
}

青蛙,既能跑,又能游

class Frog extends Animal implements IRunning, ISwimming {
	public Frog(String name) {
		super(name);
	}
	@Override
	public void run() {
		System.out.println(this.name + "正在往前跳");
	}
	@Override
	public void swim() {
		System.out.println(this.name + "正在蹬腿游泳");
	}
}

当一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类。

例如:鸭子,会游、会飞、会跑

class Duck extends Animal implements IRunning, ISwimming, IFlying {
    public Duck(String name) {
        super(name);
    }
    @Override
    public void fly() {
        System.out.println(this.name + "正在用翅膀飞");
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在用两条腿跑");
    }
    @Override
    public void swim() {
        System.out.println(this.name + "正在漂在水上");
    }
}

对上述代码的实现:

public class test {
    public static void main(String[] args) {
        Cat cat=new Cat("小花");
        cat.run();

        Fish fish=new Fish("jiujiu");
        fish.swim();

        Frog frog=new Frog("青蛙王子");
        frog.run();
        frog.swim();

        Duck duck=new Duck("可达鸭");
        duck.run();
        duck.fly();
        duck.swim();

    }
}

🍤 运行结果:

在这里插入图片描述

上面的代码展示了 Java 面向对象编程中最常见的用法:一个类继承一个父类,同时实现多种接口。

🍩继承表达的含义是 is - a 语义,而接口表达的含义是具有 xxx 特性

🍩有了接口之后,类的使用者就不必关注具体类型,而只关注某个类是否具备某种能力

例如,现在实现一个方法,叫“散步”

public static void walk(IRunning running) {
	System.out.println("我带着伙伴去散步");
	running.run();
}

在这个 walk 方法内部,我们并不关注到底是哪种动物,只要参数是会跑的就行。

2. 接口间的继承

在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的
接口可以继承一个接口,达到复用的效果。使用 extends 关键字。

interface IRunning {
	void run();
}
interface ISwimming {
	void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
}
class Frog implements IAmphibious {
	...
}

通过接口继承创建一个新的接口 IAmphibious 表示“两栖的”,此时实现接口创建的 Frog 类,就继续要实现 run 方法,也需要实现 swim 方法。

🍩接口间的继承相当于把多个接口合并在一起

3. Clonable接口和深拷贝

Java 中内置了一些很有用的接口,Clonable 就是其中之一。
Object 类中存在一个 clone 方法,调用这个方法可以创建一个对象的“拷贝”。但是要想合法调用 clone 方法,必须要先实现 Clonable 接口,否则就会抛出CloneNotSupportedException 异常。

class Animals implements Cloneable {
    private String name;
    @Override
    public Animals clone() {
        Animals o = null;
        try {
            o = (Animals)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }
}
public class Test1 {
    public static void main(String[] args) {
        Animals animal = new Animals();
        Animals animal2 = animal.clone();
        System.out.println(animal == animal2);
    }
}

🍤 运行结果:

在这里插入图片描述
Cloneable 拷贝出的对象是一份“浅拷贝”

class Money {
    public double m = 99.99;
}
class Person implements Cloneable{
    public Money money = new Money();
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test1 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person();
        Person person2 = (Person) person1.clone();
        System.out.println("通过person2修改前的结果");
        System.out.println(person1.money.m);
        System.out.println(person2.money.m);
        person2.money.m = 13.6;
        System.out.println("通过person2修改后的结果");
        System.out.println(person1.money.m);
        System.out.println(person2.money.m);
    }
}

🍤 运行结果:

在这里插入图片描述
如上代码,我们可以看到,通过clone,我们只是拷贝了Person对象。但是Person对象中的Money对象,并没有拷贝。通过person2这个引用修改了m的值后,person1这个引用访问m的时候,值也发生了改变。这里就是发生了浅拷贝。

4. 抽象类和接口的区别

核心区别: 抽象类中可以包含普通方法和普通字段,这样的普通方法和字段可以被子类直接使用(不必重写),而接口中不能包含普通方法,子类必须重写所有的抽象方法。

区别抽象类(abstract)接口(interface)
1结构组成普通类+抽象方法抽象方法+全局变量
2权限各种权限public
3子类使用使用extends关键字继承抽象类使用implements关键字实现接口
4关系一个抽象类可以实现若干接口接口不能继承抽象类,但是接口可以使用extends关键字继承多个父接口
5子类限制一个子类只能继承一个抽象类一个子类可以实现多个接口

5. Object类

Object 是 Java 默认提供的一个类。Java里面除了 Object类,所有的类都是存在继承关系的。默认会继承 Object父类。即所有类的对象都可以使用 Object 的引用进行接收。

实例:使用Object接收所有类的对象

class Person{}
class Student{}
public class Test {
	public static void main(String[] args) {
		function(new Person());
		function(new Student());
	}
	public static void function(Object obj) {
		System.out.println(obj);
	}
}
//执行结果:
Person@1b6d3586
Student@4554617c

在开发之中,Object类是参数的最高统一类型。
但是Object类也存在有定义好的一些方法。如下:

在这里插入图片描述

5.1 获取对象信息

如果要打印对象中的内容,可以直接重写Object类中的toString()方法

// Object类中的toString()方法实现:
public String toString() {
	return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

5.2 对象比较equals方法

在Java中,进行比较时:

  • 如果==左右两侧是基本类型变量,比较的是变量中值是否相同
  • 如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同
  • 如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的:
// Object类中的equals方法
public boolean equals(Object obj) {
	return (this == obj); // 使用引用中的地址直接来进行比较
}

实例:判断相等

class Person{
    private String name ;
    private int age ;
    public Person(String name, int age) {
        this.age = age ;
        this.name = name ;
    }
}
public class Test1 {
    public static void main(String[] args) {
        Person p1 = new Person("gaobo", 20) ;
        Person p2 = new Person("gaobo", 20) ;
        int a = 10;
        int b = 10;
        System.out.println(a == b); // 输出true
        System.out.println(p1 == p2); // 输出false
        System.out.println(p1.equals(p2)); // 输出false
    }
}

Person类重写equals方法后,然后比较:

class Person{
    private String name ;
    private int age ;
    public Person(String name, int age) {
        this.age = age ;
        this.name = name ;
    }
    public boolean equals(Object obj) {
        if (obj == null) {
            return false ;
        }
        if(this == obj) {
            return true ;
        }
// 不是Person类对象
        if (!(obj instanceof Person)) {
            return false ;
        }
        Person person = (Person) obj ; // 向下转型,比较属性值
        return this.name.equals(person.name) && this.age==person.age ;
    }
}
public class Test1 {
    public static void main(String[] args) {
        Person p1 = new Person("gaobo", 20) ;
        Person p2 = new Person("gaobo", 20) ;
        int a = 10;
        int b = 10;
        System.out.println(a == b); // 输出true
        System.out.println(p1 == p2); // 输出false
        System.out.println(p1.equals(p2)); // 输出true
    }
}

所以比较对象中内容是否相同的时候,一定要重写equals方法。

5.3 hashcode方法

hashcode方法源码:

public native int hashCode();
//该方法是一个native方法,底层是由C/C++代码写的。

我们认为两个名字相同,年龄相同的对象,将存储在同一个位置,如果不重写hashcode()方法,我们可以来看示例代码:

class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class Test1 {
    public static void main(String[] args) {
        Person per1 = new Person("gaobo", 20) ;
        Person per2 = new Person("gaobo", 20) ;
        System.out.println(per1.hashCode());
        System.out.println(per2.hashCode());
    }
}

🍤 运行结果:

在这里插入图片描述
从运行结果可以发现:两个对象的hash值是不一样的。

重写hashcode()方法:

import java.util.Objects;
//重写hashCode
class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
public class Test1 {
    public static void main(String[] args) {
        Person per1 = new Person("gaobo", 20) ;
        Person per2 = new Person("gaobo", 20) ;
        System.out.println(per1.hashCode());
        System.out.println(per2.hashCode());
    }
}

🍤 运行结果:

在这里插入图片描述
此时,哈希值是一样。

注:

  • hashcode方法用来确定对象在内存中存储的位置是否相同
  • 事实上hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/929356.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux常用命令_文件处理命令

文章目录 1. 命令格式与目录处理命令ls1.1 命令格式1.2 目录处理命令:ls 2. 目录处理命令2.1 目录处理命令:mkdir2.2 目录处理命令:cd2.3 目录处理命令:pwd2.4 目录处理命令:rmdir2.5 目录处理命令:cp2.6 目…

openGauss学习笔记-50 openGauss 高级特性-DB4AI

文章目录 openGauss学习笔记-50 openGauss 高级特性-DB4AI50.1 关键字解析50.2 使用指导 openGauss学习笔记-50 openGauss 高级特性-DB4AI openGauss当前版本支持了原生DB4AI能力,通过引入原生AI算子,简化操作流程,充分利用数据库优化器、执…

【PHP】字符串数组

文章目录 字符串类型字符串转义字符串相关函数 数组定义方式数组特点二维数组数组遍历foreach遍历语法for循环遍历数组相关函数相关题目 字符串类型 定义语法 引号方式:比较适合定义那些比较短(不超过一行)或者没有结构要求的字符串 1&#…

基于Python的图书馆大数据可视化分析系统设计与实现【源码+论文+演示视频+包运行成功】

博主介绍:✌csdn特邀作者、博客专家、java领域优质创作者、博客之星,擅长Java、微信小程序、Python、Android等技术,专注于Java、Python等技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 …

vscode 与 C++

序 具体流程的话,官方文档里都有的:C programming with Visual Studio Code 浏览器下载一个mingw64,解压,配置环境变量vscode里安装c相关的插件没了 第一步只看文字,可能有点抽象,相关视频: …

云计算企业私有云平台建设方案PPT

导读:原文《云计算企业私有云平台建设方案PPT》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。 喜欢文章,您可以点赞评论转发本文,…

Linux常用命令_权限管理命令

文章目录 1. 权限管理命令: chmod2. 其他权限管理命令2.1 权限管理命令: chown2.2 权限管理命令: chgrp2.3 权限管理命令: umask 1. 权限管理命令: chmod {ugoa}中分别为:u-user、g-group、a-all;谁创建文件,谁是所有者;所属组为所…

HOOPS Exchange SDK 2023 Service Pack 2 Crack

内容摘自互联网,具体功能以官网介绍为准。。。 HOOPS SDK是全球领先开发商TechSoft 3D旗下的原生产品,专注于Web端、桌面端、移动端3D工程应用程序的开发。长期以来,HOOPS通过卓越的3D技术,帮助全球600多家知名客户推动3D软件创新…

Qt ui对某控件进行全局提升报错:no such file or directory

问题 在Qt项目中,设计师界面,对某一控件进行提升,设置完“提升的类名称”、“头文件”、全局包含后,构建时,报“no such file or directory”错误,但文件命名存在呀。 解决 根据问题就应该明白&#xf…

并查集(C++实现)

目录 一、并查集原理 二、并查集应用 2.1 并查集举例 2.2 并查集数组规律 2.3 并查集功能 三、并查集实现 3.1 并查集 3.2 根据名字查找 四、例题 4.1 省份数量 4.2 等式方程的可满足性 一、并查集原理 再一些应用问题中,需要将n个不同的元素划分成一些…

Python读取Excel:实现数据高效处理的利器

目录 一、Python读取Excel的常用库二、Python读取Excel的步骤三、具体案例和使用场景四、Python读取Excel的优势与其他编程语言比较 摘要 本文将介绍Python读取Excel的方法,并通过具体案例和使用场景展示如何实现数据高效处理。我们将介绍常用的Python库&#xff0c…

QT基础使用:组件和代码关联(信号和槽)

自动关联 ui文件在设计环境下,能看到的组件可以使用鼠标右键选择“转到槽”就是开始组件和动作关联。 在自动关联这个过程中软件自动动作的部分 需要对前面头文件进行保存,才能使得声明的函数能够使用。为了方便,自动关联时先对所有文件…

【Hello Algorithm】堆和堆排序

本篇博客简介: 讲解堆和堆排序相关算法 堆和堆排序 堆堆的概念堆的性质堆的表示形式堆的增加删除堆的最大值 堆排序堆排序思路时间复杂度为N的建堆方法已知一个近乎有序的数组 使用最佳排序方法排序 堆 堆的概念 这里注意!!! 这…

日志系统——性能测试

日志系统项目已经编写完成&#xff0c;在本节完成性能测试之后就正式结束了 测试代码如下 #include "../logs/mjwlog.h" #include <vector> #include <thread>//参数&#xff1a;日志器名称&#xff0c;线程数量&#xff0c;输出日志条数&#xff0c;单…

nginx(七十八)nginx配置http2

一 ngx_http_v2模块 1、本文不讲解HTTP2的知识2、只讲解nginx中如何配置HTTP2 ① 前置条件 1、openssl的版本必须在1.0.2e及以上2、开启https加密,目前http2.0只支持开启了https的网站编译选项&#xff1a;--with-http_ssl_module --with-http_v2_module 特点&#xff1a…

【翻译】RISC-V指令集手册第Ⅱ卷:特权体系结构

第三章 机器级ISA&#xff0c;版本1.11 本章描述RISC-V系统中最高权限的机器模式(M-mode)下的机器级操作。M模式用于对硬件平台的低级访问&#xff0c;是复位时进入的第一个模式。M模式还可以用于实现在硬件中直接实现过于困难或代价过高的特性。RISC-V机器级ISA包含一个公共核…

Android Studio升级到Android API 33版本后,XML布局输入没有提示

低版本的Android Studio升级到Android API 33版本后&#xff0c;XML布局输入没有提示。查一下我目前使用的Android Studio 是2021年发布&#xff0c;而Android API 33是2022年发布的&#xff0c;这是由低版本升级到高版本造成不兼容的问题。解决方法有两种&#xff1a; 第一种…

1 Hadoop入门

1.Hadoop是什么&#xff1f; (1)Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 (2)主要解决&#xff0c;海量数据的存储和海量数据的分析计算问题。 (3)广义上来说&#xff0c;Hadoop通常是指一个更广泛的概念——Hadoop生态圈 2.Hadoop的优势 3 Hadoop组成 4 HDF…

如何将储存在Mac或PC端的PDF文件传输到移动设备呢?

iMazing是一款iOS设备管理软件&#xff0c;用户借助它可以将iPad或iPhone上的文件备份到PC或Mac上&#xff0c;还能实现不同设备之间的文件传输&#xff0c;能很大程度上方便用户进行文件管理。 在阅读方面&#xff0c;iPad和iPhone是阅读PDF的优秀选择&#xff0c;相较于Mac或…

IDEA常用配置之类Tab页多行显示

文章目录 IDEA常用配置之类Tab页多行显示 IDEA常用配置之类Tab页多行显示 默认在Idea中打开类过多&#xff0c;后面会隐藏显示&#xff0c;这里修改配置&#xff0c;将类设置为多行显示&#xff0c;方便查找已经打开的类 修改后显示样式