抽象类和接口以及Object类

抽象类

在面对对象的概念中,所有对象的创建都是通过类来创建的。但是并不是所有的类都会创建对应的对象。如果一个类中没有足够的数据创建一个对象,这样的类就是抽象类。

如同经常使用的Animal动物类,Dog类,Cat类,Dog类和Cat类都是继承于Animal类,但是Animal类中没有足够的数据去创建Animal动物,所以我们就可以将Animal设置为抽象类。

在日常书写代码中,我们发现创建动物类时,会给里面定义Eat方法,并且这个方法中也不进行具体。我们将这种方法中不实现任何功能的方法设置为抽象方法,包含抽象方法的类称为抽象类。

抽象类的基本语法

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

抽象类的特点

 不能实例化对象

 抽象方法不能设置为private

 

 抽象方法不能被final和static修饰,因为抽象类中的方法需要被重写

 抽象类必需被继承,并且继承后的子类一定要重写父类中的抽象方法,否则子类也是抽象方法。抽象类一定要用abstract修饰。

abstract class Animal {//抽象方法:被abstract修饰的方法,没有方法体abstract public void Eat();//抽象类也是类,也可以增加普通方法和属性abstract public void Run();protected int  age;//年龄}class Dog extends Animal{public void Eat(){System.out.println("吃骨头");}public  void  Run(){System.out.println("用腿跑");}
}

 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类。

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

抽象类的作用

使用抽象类相当于多了一重编译器的校验.
使用抽象类的场景就如上面的代码,实际工作都不通过父类完成,而通过子类完成.那么此时如果不小心误用成父类了,使用普通类编译器是不会报错的.但是父类是抽象类就会在实例化的时候提示错误,让我们尽早发现问题。
很多语法存在的意义都是为了"预防出错",例如我们曾经用过的final也是类似.创建的变量用户不去修改,不就相当于常量嘛?但是加上final能够在不小心误修改的时候,让编译器及时提醒我们。
充分利用编译器的校验,在实际开发中是非常有意义的.

接口

  接口的概念

  接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。

  接口的基本语法

  接口的定义和类的定义格式基本相同,将class关键词换成interface关键字

    public interface接口名称{
                   //抽象方法
                   public abstract void method1(); // public abstract是固定搭配,可以不写
                   public void  method2();
                   abstract void method3();
                   void method4();
                   //在接口中上述写法都是抽象方法,跟推荐方式4,代码更简洁
}

创建接口时,接口的命名一般以大写字母开头
接口的命名一般使用"形容词"词性的单词
接口中的方法和属性不要加任何修饰符号,保持代码的简洁性

 接口的使用

接口不能直接使用,必须要有一个实现类来实现该接口,实现接口中的抽象方法。
public class  类名称  implements  接口名称{
}

子类和父类之间是extends继承关系,类与接口之间是implents实现关系。

如请实现

笔记本电脑使用USB鼠标、USB键盘的例子

        USB接口:包含打开设备、关闭设备功能
笔记本类:包含开机功能、关机功能、使用USB设备功能

鼠标类:实现USB接口,并具备点击功能
键盘类:实现USB接口,并具备输入功能


//USB接口interface USB {void openDevice();void closeDevice();
}//鼠标类,实现USB接口class Mouse implements USB{@Overridepublic void openDevice() {System.out.println("打开鼠标");}@Overridepublic void closeDevice(){System.out.println("关闭鼠标");}public void click(){System.out.println("鼠标点击");}
}//键盘类,实现USB接口class KeyBoard implements USB{@Overridepublic void openDevice() {System.out.println("打开键盘");}@Overridepublic void closeDevice() {System.out.println("关闭键盘");}public void inPut(){System.out.println("键盘输入");}
}//笔记本类:使用USB设备class Computer {public void powerOn(){System.out.println("打开笔记本电脑");}public void powerOff(){System.out.println("关闭笔记本电脑");}public void useDevice(USB usb){usb.openDevice();if(usb instanceof Mouse){Mouse mouse =(Mouse)usb;mouse.click();}else if(usb instanceof KeyBoard){KeyBoard keyBoard = (KeyBoard)usb;keyBoard.inPut();}usb.closeDevice();}
}public class Main {public static void main(String[] args) {Computer computer = new Computer();computer.powerOn();//使用鼠标设备computer.useDevice(new Mouse());//使用键盘设备computer.useDevice(new KeyBoard());computer.powerOff();}
}

类似上述的使用就实现了接口的用法。切记在继承接口时一定不用忘记重写他的所有方法。

  接口特性

  接口类型是一种引用类型,但是不能直接new接口的对象


public class Main {public static void main(String[] args) {USB usb = new USB();}
}

  会发生报错,因为接口是抽象的,所以无法实例化对象。

 接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)

 

 interface USB {priavte void openDevice();//会发生报错无法解析privateprotected pvoid closeDevice();//和上述情况一样
}

接口中的方法是不能在接口中实现的,只能由实现接口的类来实现

interface USB {void openDevice();void closeDevice(){//接口中的方法默认为抽象方法不能在其中实现System.out.println("...");};
}

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

//USB接口interface USB {void openDevice();void closeDevice();
}//鼠标类,实现USB接口class Mouse implements USB{@Overridevoid openDevice() {//'Mouse'中的 ‘openDevice()'与'USB'中的 'openDevice()冲突,尝试分配较弱的访问权限(package-private');曾为'public'System.out.println("打开鼠标");}@Overridepublic void closeDevice(){System.out.println("关闭鼠标");}public void click(){System.out.println("鼠标点击");}
}

接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量

interface USB {int n = 3;void openDevice();void closeDevice();
}
public class Main {public static void main(String[] args) {System.out.println(USB.n);//可以通过类名直接输出,其为静态变量USB.n = 2;//不能修改,其被final修饰}
}

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

接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

jdk8中:接口中还可以包含default方法

实现多个接口

一个类可以实现多个接口

interface lFlying {void fly();
}
interface lRunning {void run();
}
interface lSwimming {void swim();
}class Frog implements lRunning, lSwimming {青蛙这个类实现了游泳和跑这两个接口private String name ;public Frog(String name){this.name = name;
}@Overridepublic void run() {System.out.println(this.name+"正在往前跳");}@Overridepublic void swim(){System.out.println(this.name +"正在蹬腿游泳");}
}

  接口之间也可以继承

   在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到 多继承的目的。 

   接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字。

interface lRunning {void run();
}
interface lSwimming {void swim();
}
interface IAmphibious extends  lRunning,lSwimming{//接口与接口之间的继承,可以达到复用,达到了拼接的效果一个接口有几个接口的特性}class Frog implements IAmphibious{private String name ;public Frog(String name){this.name = name;
}@Overridepublic void run() {System.out.println(this.name+"正在往前跳");}@Overridepublic void swim(){System.out.println(this.name +"正在蹬腿游泳");}
}

   案例使用接口

   给对象数组排序

import java.util.Arrays;class Student {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic String toString(){return "[" + this.name + ":" + this.score + "]";}
}public class Main {public static void main(String[] args) {Student[] students = new Student[] {new Student("张三",95),new Student("李四",96),new Student("王五",97),new Student("赵六",92),};Arrays.sort(Student);}
}

建立一个学生数组想要通过sort方法来对学生数组进行排序发生报错,其只能对整数类型的数组进行排序,要想实现排序只能通过实现Comparable接口,并实现其中的compareTo方法.

import java.util.Arrays;class Student implements Comparable{private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic String toString(){return "[" + this.name + ":" + this.score + "]";}public int compareTo(Object o){Student s = (Student)o;if (this.score > s.score){return -1;}else if (this.score < s.score) {return 1;}else {return 0;}}}public class Main {public static void main(String[] args) {Student[] students = new Student[] {new Student("张三",95),new Student("李四",96),new Student("王五",97),new Student("赵六",92)};Arrays.sort(students);}
}

通过在Student类中重写comparTo方法会使Array.sort中会多出来一个这个为Student类的对象比较大小的sort方法。

注 对于 sort 方法来说, 需要传入的数组的每个对象都是 "可比较" 的, 需要具备 compareTo 这样的能力. 通过重写 compareTo 方法的方式, 就可以定义比较规则.

抽象类和接口的区别

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

使用抽象类的意义是为了让编译器更好的校验, 像 Animal 这样的类我们并不会直接使用, 而是使用它的子类. 万一不小心创建了 Animal 的实例, 编译器会及时提醒我们.




 

Object类

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

案例

class Person{}
class Student{}
public class Main {public static void function(Object obj){System.out.println(obj);}public static void main(String[]args){function(new Person());function(new Student());}}

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

toString()方法,equals()方法,hashcode()方法

toString方法

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

public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

对象比较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 Main {public static void main(String[] args) {Person p1 = new Person("李四", 20);Person p2 = new Person("李四", 20);System.out.println(p1 == p2);// 输出falseSystem.out.println(p1.equals(p2));//输出false}
}

因为Person是引用类型所以其比较的是引用变量地址是否相同,equals默认也是比较地址.改正这种错误只能进行重写equals.

class Person{private String name ;private int age;public Person(String name, int age){this.age = age ;this.name = name ;}@Overridepublic boolean equals(Object obj) {if (obj == null) {return false ;}if(this == obj) {return true ;}//如果不是Person对象 instanceof判断左边是不是右边创建的对象是返回true否则是falseif (!(obj instanceof Person)) {return false;}Person person = (Person) obj ; // 将传进来的参数重新变为要比较的形式向下转型,比较属性值return this.name.equals(person.name) && this.age==person.age ;}
}
public class Main {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);//输出trueSystem.out.println(p1 == p2);// 输出falseSystem.out.println(p1.equals(p2));//输出false}
}

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

hashcode方法

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

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

可以看出两个对象的hash值不一样重写hash方法

import java.util.Objects;class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}public int hashCode() {return Objects.hash(name, age);}
}
public class Main{public static void main(String[] args) {Person per1 = new Person("李四", 20) ;Person per2 = new Person("李四", 20) ;System.out.println(per1.hashCode());System.out.println(per2.hashCode());}
}
26104872
26104872

这一次两者的hash值相同因为这一次的hash的值是根据姓名和年龄来判断的。

hashcode方法用来确定对象在内存中存储的位置是否相同

事实上hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的 散列码,进而确定该对象在散列表中的位置。

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

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

相关文章

selenium实战之爬取虎牙直播列表页

文章目录 声明实现流程给你主播列表页面分析登录遮罩层处理解析直播列表的数据分页处理 完整的代码 声明 前面有了 selenium的基础&#xff0c;这里就拿虎牙直播页面来做一个实战测试&#xff0c;这是作为学习&#xff0c;测试使用&#xff0c;并不用作为商业用途&#xff0c;不…

实战 | 微调训练TrOCR识别弯曲文本

导 读 本文主要介绍如何通过微调训练TrOCR实现弯曲文本识别。 背景介绍 TrOCR&#xff08;基于 Transformer 的光学字符识别&#xff09;模型是性能最佳的 OCR 模型之一。在我们之前的文章中&#xff0c;我们分析了它们在单行打印和手写文本上的表现。 TrOCR—基于Transforme…

HarmonyOS 应用开发之Want的定义与用途

Want 是一种对象&#xff0c;用于在应用组件之间传递信息。 其中&#xff0c;一种常见的使用场景是作为 startAbility() 方法的参数。例如&#xff0c;当UIAbilityA需要启动UIAbilityB并向UIAbilityB传递一些数据时&#xff0c;可以使用Want作为一个载体&#xff0c;将数据传递…

C#实现身份证格式验证(自建异常实现提醒)

基本信息 中国居民身份证的格式包括18位数字&#xff0c;这些数字分别代表不同的信息&#xff1a; 第1、2位数字表示省份代码。 第3、4位数字表示城市代码。 第5、6位数字表示区县代码。 第7至14位数字表示出生年、月、日&#xff08;其中7、8、9、10位是年&#xff0c;11、12…

ZK友好代数哈希函数安全倡议

1. 引言 前序博客&#xff1a; ZKP中的哈希函数如何选择ZK-friendly 哈希函数&#xff1f;snark/stark-friendly hash函数Anemoi Permutation和Jive Compression模式&#xff1a;高效的ZK友好的哈希函数Tip5&#xff1a;针对Recursive STARK的哈希函数 随着Incrementally Ve…

Uibot6.0 (RPA财务机器人师资培训第5天 ) 报销汇总机器人案例实战

训练网站&#xff1a;泓江科技 (lessonplan.cn)https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981https…

独立游戏《星尘异变》UE5 C++程序开发日志3——UEC++特供的数据类型

本篇日志将介绍FString&#xff0c;FText、FName的用法和相互转换&#xff0c;以及容器TMap&#xff0c;TArray的增删查改 一、字符串相关数据类型&#xff1a;FString、FText、FName FString是最接近std::string的类型&#xff0c;字符串本身可以看做一个存储char型的动态数…

「15」操作非常简单,小白也能在直播间一键添加色源

「15」色源添加指定色彩的纯色画面素材 在OBS软件里&#xff0c;在来源里可以增加色源&#xff0c;添加一个色块到您的场景中&#xff0c;作为一个背景色或辅助色。 图中的显示器就是加了色源的 实操步骤 第1步 添加色源 在「来源」的左下角&#xff0c;点「」选择「色源」&a…

快速上手Pytrch爬虫之爬取某应图片壁纸

一、前置知识 1 爬虫简介 网络爬虫&#xff08;又被称作网络蜘蛛、网络机器人&#xff0c;在某些社区中也经常被称为网页追逐者)可以按照指定的规则&#xff08;网络爬虫的算法&#xff09;自动浏览或抓取网络中的信息。 1.1 Web网页存在方式 表层网页指的是不需要提交表单&…

【Leetcode每日一题】模拟 - 提莫攻击(难度⭐)(42)

1. 题目解析 题目链接&#xff1a;495. 提莫攻击 2.算法原理 一、分情况讨论 要计算中毒的总时长&#xff0c;我们需要考虑时间点之间的差值&#xff0c;并根据这些差值来确定中毒的实际持续时间。 情况一&#xff1a;差值大于等于中毒时间 假设你的角色在时间点A中毒&#…

【Python】python+requests+excel+unittest+ddt实现接口自动化实例

目录 测试需求实现思路框架代码实例1. 环境准备和配置文件2. Excel接口数据及测试结果3. API封装4. 读取Excel数据5. 测试用例6. 日志和配置文件处理7. HTMLTestRunner生成可视化的html报告8. 报告通过飞书/邮件发送报告通过飞书发送报告通过邮件发送9. 入口函数10. 飞书Webhoo…

idea开发工具DEBUG调试java8stream流

1.在使用到stream()的行打断点 2.执行请求拦截到断点,依次按图点击 3.进入stream断点分析 4.如上图点击flat mode进入完整的每一步处理过程 5.Ok,完结