Java类和对象(五)—— 抽象类、接口、Object类和内部类

抽象类

在继承体系下,父类有些方法可能是要被重写的,如果我们事先就知道某些方法需要重写的话,我们可以不用在父类里面具体实现这个方法,这时候我们会用到抽象方法,这时候我们会用到关键字abstract关键字来修饰

public abstract class Animal {
    protected abstract void eat();
}

例如上面的Animal 类,每一个动物都会吃,但是每一个动物却吃的食物不同,父类的eat方法无法完全描述某个对象,这时候子类就需要重写这个方法,如果我们不想在父类具体实现这个eat方法的话,我们可以写成抽象方法~~

说完抽象方法,我们来类比一下抽象类:

如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

抽象类也是用abstract 修饰的~~

注意要点

有抽象方法的类,一定是抽象类,所以如果方法被abstract修饰,那类也必须由abstract修饰,否则编译报错

抽象类是不能进行实例化的,但是可以有继承的向上转型和向下转型~~

被private、static、final 修饰的方法不能是抽象方法
因为抽象方法就是为了被子类重写的,根据重写的规则,被private、static、final修饰的方法确实不能被重写

抽象类被继承后,继承后子类要重写父类中的抽象方法除非子类也是抽象类,必须要使用 abstract 修饰,无论是谁继承了抽象类都必须重写所有的抽象方法,否则编译报错~~

在这里插入图片描述

在这里插入图片描述
当Dog继承Animal,必须重写Aniaml所有的抽象方法~~


在这里插入图片描述

在这里插入图片描述

如果Dog还是抽象类,Cat 继承 Dog,并且在 Cat 不是抽象的情况下,我们要在 Cat 这个类重写所有的抽象方法(即包括 Animal 也包括 Dog 的抽象方法)

抽象类的作用

抽象类就是用来被继承的
谁继承了抽象类,都必须重写抽象方法,否则编译报错,这也是为了多加一层编译器的校验

接口

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

我们使用 intarface 来定义接口,就是把class替换成interface

,

public interface Ieat {
    void eat();
}

接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
在这里插入图片描述

接口的使用规则

接口的成员方法是默认都是public static final 修饰的
接口的成员方法默认都是 public abstract 修饰的

当你在接口里定义了一个成员变量的时候,你必须对其进行初始化!!!
在这里插入图片描述

如果你想具体实现某些方法,你可以使用 static 或者 default 来进行修饰

public interface Ieat {
    static void eat(){
        //...
    }
    
    default void eat2(){
        //...
    }
}

访问权限也是和之前讲的是一样的,被static就是默认权限的静态方法,被default 修饰就是默认访问权限。


接口不能有实例化代码块、静态代码块,也不能有构造方法~~

在这里插入图片描述


如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类,如果被继承就必须重写所有的抽象方法!!!
这个和抽象类是类似的~~

在这里插入图片描述


软性规则:

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

接口的继承

接口与接口之间可以多继承。即:用接口可以达到多继承的目的。
接口可以继承一个或者多个接口, 达到复用的效果. 使用 extends 关键字

interface IA{
    void eat();
}

interface IB{
    void sleep();
}

interface C extends IA,IB{

}

接口的作用

解决了 Java 不能多继承的问题!!!
意味着一个类可以有多个接口!!!

如果子类由继承父类还有多个接口的时候,我们要先继承后接口(先extends 再 implements)

在这里插入图片描述

快捷键(搭建接口当中的抽象方法)

IDEA 中使用 ctrl + i 快速搭建接口当中的抽象方法~~

或者使用 alt + enter 进行选择implements methods 进行快速搭建接口,你选择Make ‘Dog’ abstract 的话就是讲这个类变为抽象类~~
在这里插入图片描述

接口的好处

public class Animal {
    protected String name;
    protected int age;
}

public interface Irun {
    void run();
}

public class Cat extends Animal implements Irun{
    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在跑步");
    }
}

public class Dog extends Animal implements Irun{
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在跑步");
    }
}

public class Test {

    public static void walk(Irun irun){
        irun.run();
    }

    public static void main(String[] args) {
        walk(new Dog("旺财",11));
        walk(new Cat("小咪",10));
    }
}

在这里插入图片描述

接口也可以有动态绑定和多态~~
由于接口可以实现多态,所以程序员可以不关注类型,只要有这个接口的类,都能调用里面的接口方法,而不用去关心这是什么类。

Object 类

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

在这里插入图片描述
我们这里先重点关注一下上面标出来的三个方法:toString,equals,hashCode,

toString(打印对象)

class Person{
    public String name;
    public int age;

}

public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person);
    }
}

我们在数组里知道直接打印数组名的话会出现包含数组的地址的一串字符串~~
如果直接打印对象的话,也会出现和数组类似的情况,这是为什么?

Java所有的类都会继承Object类,在调用println的时候,我们来看看一共调用了哪些方法:

首先println 方法如下:

在这里插入图片描述

之后无论是走if 语句还是else 语句,都会调用toString方法

在这里插入图片描述
在这里插入图片描述
最后就会来到toString 方法,这里getClass.getName()就是类名,然后加@符号,最后调用hashCode找到地址。


但是如果我们重写了 toString 方法的话,根据前面的知识,优先调用子类的方法来打印对象内容。

class Person{
    public String name;
    public int age;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

这样的话,我们就会优先调用子类自己的toString 方法

在这里插入图片描述


我们可以使用编译器自动生成toString方法:

在这里插入图片描述

在这里插入图片描述

和之前搭建getter、setter还有构造方法是一样的,只是这里选择的是toString()

class A{
    public String name;
    public int age;

    @Override
    public String toString() {
        return "A{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

equals

在Java当中,如果使用 == 来进行比较时
如果比较的是基本数据类型的话,就是比较两个的数值相不相同
如果比较的是引用数据类型,就会比较他们的地址相不相同

来我们看一下源码:

在这里插入图片描述

还是一样的,直接调用equals方法,还是比较两个对象的地址,所以如果想比较两个对象的内容相不相同就必须重写equals方法~~

    public 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);
    }
class Person{
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public 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);
    }
}

public class Test {
    public static void main(String[] args) {
        Person person1 = new Person("张三",10);
        Person person2 = new Person("张三",10);

        System.out.println(person1.equals(person2));
    }
}

在这里插入图片描述

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

hashCode

源码:

在这里插入图片描述

native 说明这是本地方法,这个是有C/C++代码编写的,我们是看不到的


简单来说,hashCode方法可以找到对象的内存地址

public class Test {
    public static void main(String[] args) {
        Person person1 = new Person("张三",10);
        Person person2 = new Person("张三",10);

        System.out.println(person1.hashCode());
        System.out.println(person2.hashCode());
    }
}

在这里插入图片描述

由于这是两个不同的对象,所以他们的内存地址是不一样的~~

但是如果我们认为当两个对象的内容是一样的,那地址就应该是一样的话,我们就需要重写hashCode 方法~~

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

在这里插入图片描述

这样他们的地址就会是一样的显示~~


快捷键搭建

以上三个方法都能使用快捷键快速搭建:

在这里插入图片描述

内部类

内部类就是在类里面再定义一个类,这个类定义的位置和外部类的成员是相同的。

静态内部类

static修饰的内部成员类称为静态内部类。

class A{
    public int age;
    public static int price;

    public A(){
        System.out.println("A()......");
    }

    public void methodA1(){
        System.out.println("methodA1()......");
    }

    public static void methodA2(){
        System.out.println("methodA2()......");
    }

    static class B{

        public void methodB(){
            //age = 10;//err,静态内部类只能访问外部类的静态成员
            //A();//不要在静态内部类中调用外部类的构造方法,构造方法是没有静态的,所以构造方法一定不是静态方法
            //methodA1(); //err,静态内部类只能访问外部类的静态成员,methodA1不是类方法(静态成员方法)
            price = 10;
            methodA2();
        }

    }

    //.....
}

注意事项

静态内部类只能访问外部类的静态成员

创建静态内部类

A.B b = new A.B();

我们可以将静态内部类当成外部类的一个静态成员,静态成员的访问不需要创建对象,我们可以通过类名来访问,于是我们通过 A.B 就访问到了静态内部类,然后就通过new A.B 就可以完成创建了

实例内部类

未被static 修饰的实例内部类就是实例内部类

实例内部类可以自由访问外部类的任意成员,如果实例内部类和外部类有重名的成员时,在内部类中优先访问自己的,如果真的相访问外部类同名的成员时,我们可以使用 外部类类名.this.成员 即可~~

class A{
    public int age;
    public static int price;

    public A(){
        System.out.println("A()......");
    }

    public void methodA1(){
        System.out.println("methodA1()......");
    }

    public static void methodA2(){
        System.out.println("methodA2()......");
    }

    public void methodA3(){
        System.out.println("methodA3()......");
    }

    class C{

        public int age = 10;

        public void methodC(){
            System.out.println(age);
            methodA3();
            System.out.println(A.this.age);
            methodA1();
            A.this.methodA1();
        }

        public void methodA1(){
            System.out.println("C::methodA1()......");
        }
    }

    //.....
}

public class Test{
    public static void main(String[] args) {
        A.C c = new A().new C();
        c.methodC();
    }
}

在这里插入图片描述


创建实例内部类

我们要先创建外部类,再去创建实例内部类

A.C c = new A().new C();

当然也可以分部去写:

A a = new A();
A.C c = a.new C();

注意事项

1.外部类中的任何成员都 可以在实例内部类方法中直接访问
2.实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
3.在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名
称.this.同名成员 来访问
4.实例内部类对象必须在先有外部类对象前提下才能创建
5.实例内部类的非静态方法中包含了一个指向外部类对象的引用
6.外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。


匿名内部类

class A{
    public void test1(){
        System.out.println("heihei");
    }
}

public class Test{

    public static void main(String[] args) {
        new A(){

        }.test1();
    }

}

在这里插入图片描述

通过后面的 .方法 来调用相应的方法。


我们也可以重写匿名内部类的方法

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
但是要注意不能使用对象来接收匿名内部类


接口也可以使用:

interface A{
    void test1();
}

public class Test{

    public static void main(String[] args) {
        new A(){
            public void test1(){
                System.out.println("haha");
            }
        };

    }

}

和上面不一样的是,接口是一定要重写其中的抽象方法的,并且花括号后面是不能直接 .方法 的,而是要通过被接收后,然后去再去调用相应的方法~~

因此接口是可以被接收的,接收后也是可以继续使用的:

在这里插入图片描述
在这里插入图片描述

局部内部类

局部内部类是定义在方法里的,因此它的生命周期和方法是一样。

    public void A() {
        //...
        
        class D{ 
            //......
        }
        
        //...
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Thinkphp内核开发盲盒商城源码v2.0 对接易支付/阿里云短信/七牛云存储

源码简介 这套系统是我从以前客户手里拿到的,100完整可用,今天测试防红链接失效了,需要修改防红API即可!前端页面展示我就不放了,懂的都懂 优点是Thinkphp开发的,二开容易。 源码图片 资源获取:Thinkphp内核开发盲盒商城源码v2.0 对接易支付/阿里云短…

有些错误,常犯常新、常新常犯:记录一个使用element-plus的tooltip组件的错误

使用element-plus的tooltip组件&#xff0c;最开始的写法是这样的&#xff1a; <el-tooltipclass"box-item"effect"dark"content"tooltip content" ><el-button v-if"isDisabled" :underline"false" type"pr…

【实战】SpringBoot整合Websocket、Redis实现Websocket集群负载均衡

文章目录 前言技术积累什么是Websocket什么是Redis发布订阅Redis发布订阅与消息队列的区别 实战演示SpringBoot整合WebsoketWebsoket集群负载均衡 实战测试IDEA启动两台服务端配置nginx负载均衡浏览器访问模拟对话 前言 相信很多同学都用过websocket来实现服务端主动向客户端推…

Web前端一套全部清晰 ⑨ day5 CSS.4 标准流、浮动、Flex布局

我走我的路&#xff0c;有人拦也走&#xff0c;没人陪也走 —— 24.5.24 一、标准流 标准流也叫文档流&#xff0c;指的是标签在页面中默认的排布规则&#xff0c;例如:块元素独占一行&#xff0c;行内元素可以一行显示多个。 二、浮动 作用: 让块级元素水平排列。 属性名:floa…

瑞米派Ubuntu系统移植指南-米尔RemiPi

1.概述 Linux系统平台上有许多开源的系统构建框架&#xff0c;这些框架方便了开发者进行嵌入式系统的构建和定制化开发&#xff0c;目前比较常见的有Buildroot, Yocto, OpenEmbedded等等。 同时更多的传统的桌面系统也加入到嵌入式环境体系中&#xff0c;如Ubuntu&#xff0c…

启动docker报错:Failed to listen on Docker Socket for the API.

说明&#xff1a; 1、安装部署docker完成后&#xff0c;启动docker报错&#xff1a;Failed to listen on Docker Socket for the API&#xff0c;如下图所示&#xff1a; 2、将SocketGroupdocker更改成&#xff1a;SocketGrouproot即可 一、解决方法&#xff1a; 1、执行命令…

用智能插件(Fitten Code: Faster and Better AI Assistant)修改好了可以持久保存的vue3留言板

天际 第一修改是选项式&#xff1a; <!-- 模板结构 --> <template><div><textarea placeholder"请输入备注内容" v-model"newItem"></textarea><button click"addItem">添加</button><hr><…

Redis 主从复制、哨兵与集群

一、Redis 主从复制 1. 主从复制的介绍 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(Master)&#xff0c;后者称为从节点(Slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。 默认情况下&a…

【MySQL精通之路】InnoDB(6)-磁盘结构(2)-索引

主博客&#xff1a; 【MySQL精通之路】InnoDB(6)-磁盘上的InnoDB结构-CSDN博客 上一篇&#xff1a; 下一篇&#xff1a; 【MySQL精通之路】磁盘上的InnoDB结构-表空间-CSDN博客 目录 1.聚集索引和二级索引 1.1 Innodb 如何建立聚集索引 1.2 聚集索引如何加快查询速度 1…

大语言模型的工程技巧(一)——GPU计算

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型&#xff1a;从线性回归到通用人工智能》&#xff0c;欢迎有兴趣的读者多多支持。 本文涉及到的代码链接如下&#xff1a;regression2chatgpt/ch07_autograd/gpu.ipynb 本文将讨论如何利用PyTorch实现GPU计算。本…

第十一节 SpringBoot Starter 面试题

一、面试题 很多同学的简历都写着熟悉 SpringBoot&#xff0c; 而 Starter 的实现原理被当作的考题的的情况越来越多。 来源牛客网关于 starter 的一些面试题 情景一、路虎一面 情景二、蔚来 情景三、同花顺 Starter 频频出现&#xff0c;因此在面试准备时&#xff0c;这道题…

Qt_电脑wifi相关操作

项目描述: 在做项目时用到了获取wifi的操作。在网上查找了好久资料,这里做一些总结。 这里有显示当前电脑wifi连接状态,列出wifi列表,连接断开wifi等函数。欢迎大家留言添加文章内容。 使用范围: windows电脑(中文的环境) 使用技术:windows的cmd命令。和对字符串的解析…

概念解析 | 3D Referring Expression Comprehension (3D-REC):让计算机“听懂“人类的3D语言指令

注1:本文系"概念解析"系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:3D Referring Expression Comprehension (3D-REC)。 概念解析 | 3D Referring Expression Comprehension (3D-REC):让计算机"听懂"人类的3D语言指令 PDF]…

FIFO-Diffusion,一个无需额外训练即可生成长视频的框架。通过确保每个帧引用足够多的先前帧来生成高质量、一致的长视频。

简单来讲&#xff0c;FIFO-Diffusion先通过一些模型如VideoCraft2、zeroscope、Opem-Sora Plan等与FIFO-Diffusion的组合生成短视频&#xff0c;然后取结尾的帧&#xff08;也可以取多帧&#xff09;&#xff0c;再用这一帧的图片生成另一段短视频&#xff0c;然后拼接起来。FI…

工大智信智能听诊器:开启个人健康管理的全新模式

工大智信智能听诊器&#xff1a;开启个人健康管理的全新模式 在快节奏的现代生活中&#xff0c;健康管理已成为人们关注的焦点。工大智信智能听诊器&#xff0c;作为一款创新的医疗设备&#xff0c;不仅提供高级数据管理功能&#xff0c;而且成为了个人健康管理的得力助手。 这…

6款网站登录页(附带源码)

6款网站登录页 效果图及部分源码123456 领取源码下期更新预报 效果图及部分源码 1 部分源码 <style>* {margin: 0;padding: 0;}html {height: 100%;}body {height: 100%;}.container {height: 100%;background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);}.l…

Application Development using Large Language Models笔记

诸神缄默不语-个人CSDN博文目录 这是2023年NeurIPS Andrew Ng和Isa Fulford做的tutorial&#xff0c;关于如何用LLM来开发新产品的技术和思路&#xff1a;NeurIPS Tutorial Application Development using Large Language Models 文章目录 1. LLM基础2. 提示工程技巧3. 微调4.…

图片、视频画质增强变清晰工具分享(免费)

生活中可能会修一下模糊图片那么这就有一款用来修图片的管理工具&#xff0c;也有可能会修一下模糊的视频&#xff0c;在吾爱上有大佬开发了这么一款工具&#xff0c;免费的&#xff0c;不需要开任何VIP&#xff0c;我试了一下&#xff0c;好用&#xff0c;分享出来&#xff0c…

linux 上除了shell、python脚本以外,还有什么脚本语言用得比较多?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「 Linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;说到在 Linux下的编程&#xf…

TypeScript-泛型

泛型(Generics) 指在定义接口&#xff0c;函数等类型的时候&#xff0c;不预先指定具体的类型&#xff0c;而在使用的时候再指定类型的一种特性&#xff0c;使用泛型可以复用类型并且让类型更加灵活 泛型接口-interface 语法&#xff1a;在 interface 接口类型的名称后面使用…