抽象类和接口

目录

抽象类

接口

基本概念

 多接口使用

为什么接口解决了Java的多继承问题?

接口的继承 

克隆

Clonable接口

拷贝 

Object类


抽象类

1.使用abstract修饰的方法称为抽象方法

2.使用abstract修饰的类称为抽象类

3.抽象类不可以被实例化 e.g.Shape shape = new Shape()//err

4.抽象类当中可以和普通类一样定义成员变量和方法

5.继承抽象类?当一个普通的类继承了抽象类,需要重写这个抽象类中所有的抽象方法!

所以抽象类不能和final共存,因为final这个关键字就是不让类重写的

6.抽象类的出现为了被继承:如果有些工作应由子类完成而非父类,那么父类是抽象类的话可以在实例化的时候报错,因为抽象类本身不能被实例化,要想使用,只能创建该抽象类的子类,然后重写抽象方法,这样可以让我们更容易发现问题。(作用)

7.不可以用private,static修饰抽象类方法


一开始没有重写方法,后面也需要重写方法

abstract class A extends Shape {public abstract void testA();
}class B extends A {@Overridepublic void draw() {}@Overridepublic void testA() {}
}

接口

接口就是公共的行为规范标准

基本概念

1.接口是使用interface修饰的

2.接口当中不能有被实现的方法,只能有抽象方法,但是被static和default方法修饰的方法除外

3.接口当中的抽象方法默认都是public abstract修饰的!

4.接口当中的成员变量默认都是public static final修饰的

5.接口不能进行实例化

6.类和接口之间的关系,可以使用implements来进行关联

7.系统给出两种选择,要么抽象要么重写

重写接口方法的时候不能使用默认的访问权限

因为子类的访问权限要大于等于父类的,父类默认是public abstract,子类有可能是private,就error了,子类必须是public

8.接口虽然不是类,但也是有对应的字节码文件.class的

    private static void drawMap(Shape shape){shape.draw();}public static void main(String[] args) {//Shape shape = new Shape();//无法实例化,抽象的抽象类Shape shape1 = new Rect();Shape shape2 = new Flower();drawMap(shape1);drawMap(shape2);System.out.println("===========");Shape[] shapes = {new Rect(), new Rect(), new Flower(), new Flower()};//多态,接口也可以发生向上转型和动态绑定for(Shape shape: shapes){shape.draw();}}

9.接口中不能有代码块和构造方法 


例子: 

//接口USB
package demo1;public interface USB {void openDevice();void closeDevice();
}
//类KeyBoard
public class KeyBoard implements USB{@Overridepublic void openDevice() {System.out.println("插上键盘");}@Overridepublic void closeDevice() {System.out.println("关上键盘");}public void input(){System.out.println("疯狂敲打键盘.......");}
}
//类Mouse
public class Mouse implements USB{@Overridepublic void openDevice() {System.out.println("鼠标开始工作");}public void click(){System.out.println("疯狂点击鼠标......");}@Overridepublic void closeDevice() {System.out.println("鼠标停止工作");}}

 多接口使用

为什么接口解决了Java的多继承问题?

//抽象类Animal
abstract class Animal{public String name;public int age;public Animal(String name, int age){this.name=name;this.age=age;}
//    public void fly(){}
//    public void run(){}
//    public void swim(){}public abstract void eat();
}

在动物里面,有的会飞有的会游有的会跑
但我们不能在Animal类里面定义这三个方法因为不是每个动物都会飞或游或跑

因为Java不能同时继承多个类,所以这三个方法还不能直接写成不同的类

一个类可以实现多个接口,所以我们把他封装成接口如下:

//三个房卡其实可以看作个行为标准
//三个接口
interface IFly{void fly();
}
interface IRun{void run();
}
interface ISwim{void swim();
}

想办法让三种动物执行多继承 

//狗是一个动物,具备跑的功能
//鼠标放extends ALT+ENTER可以快速构造方法
//鼠标放Animal抽象类 ALT+ENTER可以快速重写方法
class Dog extends Animal implements IRun{Dog(String name, int age){super(name,age);}@Overridepublic void run() {System.out.println(this.name+" 在用四条腿跑步");}@Overridepublic void eat() {System.out.println(this.name+" 正在吃");}
}
//蛙会跑会游
class Frog extends Animal implements IRun,ISwim{public Frog(String name, int age){super(name, age);}@Overridepublic void run() {System.out.println(this.name+" 正在用两条腿跑");}@Overridepublic void swim() {System.out.println(this.name+" 正在蛙泳");}@Overridepublic void eat() {System.out.println(this.name+" 正在吃蛙粮");}
}
//鸭会跑会游会飞
class Duck extends Animal implements IRun, ISwim, IFly{public Duck(String name, int age) {super(name, age);}@Overridepublic void fly() {System.out.println(this.name+" 正在用翅膀飞");}@Overridepublic void run() {System.out.println(this.name+" 正在撅着屁股跑");}@Overridepublic void swim() {System.out.println(this.name+" 正在用两只脚划水");}@Overridepublic void eat() {System.out.println(this.name+" 正在吃鸭粮");}
}
public class Test {public static void func1(Animal animal){animal.eat();}public static void main1(String[] args) {//多态func1(new Duck("唐老鸭",10));func1(new Dog("二狗子",10));func1(new Frog("青蛙",10));}
class Robot implements IRun{@Overridepublic void run() {System.out.println("机器人 正在用两只脚跑路");}
}
public class Test {public static void func1(Animal animal){animal.eat();}public static void running(IRun iRun){iRun.run();}public static void flying(IFly iFly){iFly.fly();}public static void swimming(ISwim iSwim){iSwim.swim();}//接口的意义:只要具备这个功能,我都能用public static void main(String[] args) {running(new Duck("唐老鸭",10));running(new Dog("二狗子",10));running(new Frog("青蛙",10));running(new Robot());//不管是不是动物System.out.println("================");flying(new Duck("唐老鸭",10));System.out.println("================");swimming(new Duck("唐老鸭",10));swimming(new Frog("青蛙",10));}

接口的继承 

interface A{void testA();
}
interface B extends A{void testB();
}

B接口不仅仅具备了B自己的功能,还具备了A接口的功能

用一个test来测试,发现既得重写A的方法,还得重写B的方法

关系:

1.类和接口:implements 实现

2.接口和接口:extends 拓展

接口使用实例

正常数字比较大小

    public static void main1(String[] args) {int a = 10;int b = 20;System.out.println(a>b);//输出false}

但是到了类的引用,就比较不了了,因为地址无法比较

class Student{public String name;public int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

我们要解决这两个学生要根据什么比较?年龄?姓名?

我们需要实现一个接口 

Java里面有一个Comparable接口,表示当前的类是可以比较的

重写compareTo方法

    @Overridepublic int compareTo(Student o) {if (this.age > o.age){return 1;} else if (this.age == o.age) {return 0;}else{return -1;}}

调用

分析:

返回结果: 


现在我想根据姓名比较,但如果要改变compareTo的逻辑得先复制后注释掉原来的方法再进行修改后单个比较,这样巨麻烦,(这也叫做对类的侵入性比较强,一旦写好了规定的比较方式,那么以后只能以这种方式进行比较),这不是我们想要的,那有没有另一种方法可以及能按照年龄比较又能按照姓名比较呢?

我们可以设计一个年龄比较器

comparator里面有一个方法

重写这个方法

class AgeComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.age-o2.age;}
}

调用

姓名也是同理

class NameComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);}
}

这里的compareTo我们点进去看是这样的

因为String类实现了Compare接口(用ASCII码来计算),所以我们调用的是String自己重写的compareTo方法

调用方法

这种方法好处就是比较灵活,只需要传入两个要比较的对象


数组的排序方法

       /* int[] array = {1,2,31,14};Arrays.sort(array);System.out.println(Arrays.toString(array));*/

定义五个学生并组成数组

Student[] students = new Student[] {
new Student("张三", 95),
new Student("李四", 96),
new Student("王五", 97),
new Student("赵六", 92),
};

我们是否可以沿用数组的排序思想给学生排序呢?

Arrays.sort(students);
System.out.println(Arrays.toString(students));
// 运行出错, 抛出异常.
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable
对于 sort 方法来说 , 需要传入的数组的每个对象都是 " 可比较 " , 需要具备 compareTo 这样的能力 . 通过重写 compareTo 方法的方式 , 就可以定义比较规则 .
//修改comparable的sort方法底层public static void bubbleSort(Comparable[] comparables) {for (int i = 0; i < comparables.length-1; i++) {for (int j = 0; j < comparables.length-1-i; j++) {if(comparables[j].compareTo(comparables[j+1]) > 0) {Comparable tmp = comparables[j];comparables[j] = comparables[j+1];comparables[j+1] = tmp;}}}}public static void main(String[] args) {Student[] students = new Student[3];students[0] = new Student("zhangsan",10);students[1] = new Student("lisi",4);students[2] = new Student("abc",5);System.out.println("排序前: "+Arrays.toString(students));//bubbleSort(students);Arrays.sort(students);System.out.println("排序后: "+Arrays.toString(students));}

克隆

Clonable接口

        Person person = new Person("张三",10);Person person1 = person;//clone

 现在想用第一个person克隆一个新的person1出来,Java的Obeject类里面有一个克隆方法


因为是protected修饰的,我们没办法直接在person后面.clone调用方法,所以需要super.clone()

    //可能会抛出异常,这个异常叫做不知处克隆异常,是编译时期的异常@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}

 

所以我们改一下main函数?

还报错?克隆方法的返回值是Object,person1的类是Person,父类Object给子类Person是不允许的,所以我们需要强转

        Person person1 = (Person) person.clone();//clone

当我们来打印这两个person的时候,程序爆出问题

这说明我们自己写的类型要支持克隆的时候,要给它实现一个克隆接口Cloneable

但是点进去这个接口我们发现居然是空的,结果也没错,那实现这个接口意义在哪

 这种接口叫做空接口或者标记接口,作用是表明当前类是可以被克隆的


拷贝 

打印结果是什么呢?

分析:

目前这种情况叫做浅拷贝(只有一个对象的时候)就像两个人抢一个遥控器,遥控器变了(19.9->99.99),两个人抢的遥控器也跟着改变

深拷贝:把对象里面引用等信息拷贝出来一份

接下来我们要来实现深拷贝

Person类里面的super.clone()还在克隆person,还没有克隆money,我们可以借助一个中间变量来帮助克隆

Person tmp = (Person) super.clone();

 再把Money类复制一份

tmp.money = (Money)this.money.clone();

这里的this就是person ,money的地址改成0x999(假设),再把这个0x999给到tmp

person1用来接收tmp的值

整个的深拷贝分析流程 

深拷贝完成,打印结果如下

深拷贝相当于把一个遥控器复制一份分给另一个人,一个人拿到新的遥控器(99.99),另一个人还拿着老的遥控器(19.9)


Object类

红色🔒代表private修饰,绿色🔒代表public修饰,一把🔑代表protected修饰

equals方法

 

    public static void main(String[] args) {Person person = new Person("张三",10);Person person1 = new Person("张三",10);//System.out.println(person == person1);System.out.println(person.equals(person1));//直接调用跟上一句没区别}

两个学生名字年龄都一样,但是因为地址不一样所以比较结果false(equals默认比较对象的地址),这背离我们的初衷(这两个学生得相等)

我们就在Person类里面重写这个方法

    //重写equals方法@Overridepublic boolean equals(Object obj) {Person tm = (Person) obj;return this.name.equals(tm.name) && this.age == tm.age;}

也可以再generate里面重写

    @Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}

hashcode方法可以看我以后的博客😀

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机毕业设计 基于SSM+Vue的农业信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Docker概念通讲

目录 什么是Docker&#xff1f; Docker的应用场景有哪些&#xff1f; Docker的优点有哪些&#xff1f; Docker与虚拟机的区别是什么&#xff1f; Docker的三大核心是什么&#xff1f; 如何快速安装Docker&#xff1f; 如何修改Docker的存储位置&#xff1f; Docker镜像常…

shell脚本学习教程(一)

shell脚本学习 一、什么是 Shell&#xff1f;1. shell概述2. Shell 的分类3. 第一个shell脚本4. 多命令执行 二、Shell 变量3.1 变量的命名规则3.2 变量的特殊符号3.3 用户自定义变量3.4 环境变量3.5 位置参数变量3.6 预定义变量3.7 接受键盘输入 三、Shell 运算符3.1 算术运算…

解决 SQLyog 连接 MySQL8.0+ 报错:错误号码2058

文章目录 一、问题现象二、原因分析三、解决方案1. 方案1&#xff1a;更新SQLyog版本2. 方案2&#xff1a;修改用户的授权插件3. 方案3&#xff1a;修复my.cnf 或 my.ini配置文件 四、最后总结 本文将总结如何解决 SQLyog 连接 MySQL8.0 时报错&#xff1a;错误号码2058 一、问…

管理类联考——数学——汇总篇——知识点突破——代数——等差数列——最值

等差数列 S n S_n Sn​的最值问题 1.等差数列前n项和 S n S_n Sn​有最值的条件 &#xff08;1&#xff09;若 a 1 < 0 &#xff0c; d > 0 a_1<0&#xff0c;d>0 a1​<0&#xff0c;d>0时&#xff0c; S n S_n Sn​有最小值。 &#xff08;2&#xff09;若…

Linux网络基础

一.协议的概念 1.1协议的概念 什么是协议 从应用的角度出发&#xff0c;协议可理解为“规则”&#xff0c;是数据传输和数据的解释的规则。假设&#xff0c;A、B双方欲传输文件。规定: 第一次&#xff0c;传输文件名&#xff0c;接收方接收到文件名&#xff0c;应答OK给传输方…

LeetCode(力扣)134. 加油站Python

LeetCode134. 加油站 题目链接代码 题目链接 https://leetcode.cn/problems/gas-station/description/ 代码 class Solution:def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:cursum 0minfuel float(inf)for i in range(len(gas)):rest gas[i…

[EI复现】基于主从博弈的新型城镇配电系统产消者竞价策略(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

数据库连接工具Chat2DB介绍

1、Chat2DB介绍 Chat2DB 是一款有开源免费的多数据库客户端工具&#xff0c;支持windows、mac本地安装&#xff0c;也支持服务器端部署&#xff0c;web网页访问。和传统的数据库客户端软件Navicat、DBeaver 相比Chat2DB集成了AIGC的能力&#xff0c;能够将自然语言转换为SQL&a…

vue+element-ui el-descriptions 详情渲染组件二次封装(Vue项目)

目录 1、需求 2.想要的效果就是由图一变成图二 ​编辑 3.组件集成了以下功能 4.参数配置 示例代码 参数说明 5,组件 6.页面使用 1、需求 一般后台管理系统&#xff0c;通常页面都有增删改查&#xff1b;而查不外乎就是渲染新增/修改的数据&#xff08;由输入框变成输…

安卓恶意应用识别(三)(批量反编译与属性值提取)

前言 上篇说到对安卓APK反编译&#xff0c;本篇实现批量反编译和批量特征提取及计算&#xff0c;主要就是通过python代码与cmd进行批量化交互&#xff0c;我在写文章之前&#xff0c;尝试批量下载了安卓apk&#xff08;大约10来个&#xff09;&#xff0c;发现现在这个应用软件…

腾讯mini项目-【指标监控服务重构】2023-08-23

今日已办 进度和问题汇总 请求合并 feature/venus tracefeature/venus metricfeature/profile-otel-baserunner-stylebugfix/profile-logger-Syncfeature/profile_otelclient_enable_config 完成otel 开关 trace-采样metrice-reader 已经都在各自服务器运行&#xff0c;并接入…

SmartSQL 一款开源的数据库文档管理工具

建议直接蓝奏云下载安装 蓝奏云下载&#xff1a;https://wwoc.lanzoum.com/b04dpvcxe 蓝奏云密码&#xff1a;123 项目介绍 SmartSQL 是一款方便、快捷的数据库文档查询、导出工具&#xff01;从最初仅支持 数据库、CHM文档格式开始&#xff0c;通过不断地探索开发、集思广…

【C刷题】day2

一、选择题 1、以下程序段的输出结果是&#xff08; &#xff09; #include<stdio.h> int main() { char s[] "\\123456\123456\t"; printf("%d\n", strlen(s)); return 0; } A: 12 B: 13 C: 16 D: 以上都不对【答案】&#xff1a; A 【解析】…

springboot和vue:二、springboot特点介绍+热部署热更新

springboot特点介绍 能够使用内嵌的Tomcat、Jetty服务器&#xff0c;不需要部署war文件。提供定制化的启动器Starters&#xff0c;简化Maven配置&#xff0c;开箱即用。纯Java配置&#xff0c;没有代码生成&#xff0c;也不需要XML配置。提供了生产级的服务监控方案&#xff0…

Linux Day15:线程安全

一、线程安全方法 线程安全即就是在多线程运行的时候&#xff0c;不论线程的调度顺序怎样&#xff0c;最终的结果都是 一样的、正确的。那么就说这些线程是安全的。 要保证线程安全需要做到&#xff1a; 1&#xff09; 对线程同步&#xff0c;保证同一时刻只有一个线程访问临…

Spring 的注入

目录 一、注入&#xff08;Injection&#xff09; 1、什么是注入 &#xff08;1&#xff09;为什么需要注入 &#xff08;2&#xff09;如何进行注入 2、Spring 注入原理分析&#xff08;简易版&#xff09; 二、Set 注入详解 1、JDK 内置类型 &#xff08;1&#xff09…

CountDownLatch 使用例子和代码流程

目录 CountDownLatch意思理解普通多线程运行Thread.join()实现CountDownLatch实现CountDownLatch流程new CountDownLatch(3)countDown 方法await方法 CountDownLatch意思理解 单词1: countdown 常见释义: 英[ˈkaʊntdaʊn] 美[ˈkaʊntdaʊn] n. 倒数读秒&#xff0c;倒计时(…

推荐一个高质量专栏:「前端面试必备」

文章目录 专栏作者介绍专栏介绍目录&#xff08;前25篇&#xff09;目录&#xff08;后25篇&#xff09;专栏文章部分摘抄JavaScriptVue网络请求和HTTPNode.jswebpackBabelVite微信小程序Vuexuni-appGitECharts前端工程化 写在结尾 专栏作者介绍 &#x1f90d; 前端开发工程师&…

Vulnhub系列靶机---Deathnote: 1死亡笔记

文章目录 信息收集主机发现端口扫描目录扫描dirsearchgobusterdirb扫描 漏洞利用wpscan扫描Hydra爆破 总结 靶机文档&#xff1a;Deathnote: 1 下载地址&#xff1a;Download (Mirror) 难易程度&#xff1a;so Easy 信息收集 主机发现 端口扫描 访问靶机的80端口&#xff0c;报…