Java--接口和内部类

news2024/9/21 17:48:19

目录

  • 接口
    • 接口的使用
    • 接口的特性
    • 多继承问题
    • 对象类型进行比较
    • 深拷贝和浅拷贝
      • 浅拷贝
      • 深拷贝
    • 接口和抽象类区别
  • Object类
  • 内部类
    • 实例内部类
    • 静态内部类
    • 局部内部类
    • 匿名内部类

接口

接口是一种引用数据类型,语法和抽象类类似,只不过需要把abstract换成interface
接口的命名一般以I开头

//语法格式
public interface 接口名称 {
}

接口的使用

接口不可以直接使用,需要有一个类来实现这个接口,并把接口内的抽象方法全部重写。

//接口
public interface IRun {
    void run();
}

//类(实现接口)
public class Dog implements IRun{
    @Override
    public void run() {
        System.out.println("狗在跑");
    }
}

类和类之间是继承关系(extends),类和接口之间是实现(implements)

接口的特性

  • 接口是引用类型,但并不可以直接进行实例化(new 接口)。
  • 接口中的每一个方法都是被public abstract修饰,(我们实际编写代码的时候可以不用加上,接口方法会被隐式指定为public abstract,这样也就保持了我们代码的简洁性)
  • 接口中的方法并不会在接口中有实现,而在实现接口的类中实现。
  • 接口中不可以有被实现的方法,等同于只可以有抽象方法,但是两个除外(static和default修饰的)
  • 接口中可以有成员变量,只不过要被public static final修饰,编写代码的时候可以省略修饰,变量也会被隐式指定为public static final。
  • 重写接口方法的时候,不可以用default来修饰。(子类的访问权限要大于等于父类)
  • 接口中不可以有代码块和构造方法。
  • 如果类没有实现接口的抽象方法,那么类也要设置为抽象类。

多继承问题

  • 在Java中没有多继承,但通过接口却可以解决这个问题。我们来进一步理解一下extends和implements。
//意思为,狗是一个动物具有跑的功能
//!!!当extends和implements同时出现的时候,extends必须在前面
public class Dog extends Animal implements IRun
  • 类不可以多继承,但一个类可以实现多个接口
public class Dog extends Animal implements IRun,IEat
  • 类和接口之间为Implements,接口和接口之间要用extends,并且接口之间支持多继承
interface IAmphibious extends IRunning, ISwimming {
}

对象类型进行比较

对于一般类型我们都可以比较出来大小,但我们如何对一个对象进行比较呢?下面我将来讲述两种方法。

1.如果对象对应的类可以进行比较,它需要实现接口Comparable(用来告诉我们这个类可以进行比较),然后我们需要重写实现的接口中的compareTo方法,然后在main方法中通过调用compareTo方法进行比较。

//Comparable<Student>这个里面尖括号括起来的部分称为泛型,表示可以进行比较的类
class Student implements Comparable<Student>{
    String name;
    int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //这重写了compareTo,这里我编写的逻辑是根据年龄
    //s.compareTo(s1)===>s调用了方法,s就代表this,s1作为参数传过来,所以s1等同于下面的o
    @Override
    public int compareTo(Student o) {
        //根据年龄比较
        if (this.age > o.age) {
            return this.age - o.age;
        } else {
            return o.age - this.age;
        }
    }
}
public class JavaSE731 {
    public static void main(String[] args) {
        Student student = new Student("lisi",18);
        Student student1 = new Student("zhangsan",22);
        System.out.println(student.compareTo(student1));
    }
}

通过方法一我们可以对对象进行比较,但是有个不好的地方是,我们这次想根据年龄比较,然后把代码写死在了compareTo中,无论什么时候调用,他都是根据年龄去比较,但我们想根据姓名比较的时候呢?我们还需要再去compareTo代码中进行修改,很不方便。所以更推荐方法二。
2.通过比较器来比较。

import java.util.Comparator;

class Student {
    String name;
    int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
class AgeCompare implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}
public class JavaSE731 {
    public static void main(String[] args) {
        Student student = new Student("zs",14);
        Student student1 = new Student("ws",22);
        AgeCompare ageCompare = new AgeCompare();
        System.out.println(ageCompare.compare(student,student1));
    }
}

我们通过年龄比较,就可以创建一个类实现接口Comparator接口,后面的泛型填写要比较的那个类。然后重写compare方法,在里面写上比较方法,在main函数中创建创建这个类的对象,将要比较的两个对象传过去。这种方法很灵活。

深拷贝和浅拷贝

Java提供了一个方法clone实现对象的克隆,但是要想调用这个方法必须得实现接口Clonable,否则就会报不支持克隆的异常。那么什么是深拷贝?什么是浅拷贝?

浅拷贝

class Ban {
    int num = 19;

    @Override
    public String toString() {
        return "Ban{" +
                "num=" + num +
                '}';
    }
}
//浅拷贝
class Student implements Cloneable{
    String name;
    int age;
    Ban ban = new Ban();

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                "," + ban +
                '}';
    }
}
public class JavaSE731 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Student student = new Student("zs",14);
        Student student1 = (Student) student.clone();
        student.ban.num = 99;
        System.out.println(student);
        System.out.println(student1);
    }
}

这里需要注意很多易错点:
1.对于要克隆的类必须得实现Cloneable接口,否则会报错(不支持克隆的错误)。
2.我们实现接口后,要将接口中方法clone重写,我们直接输入clone,Idea会给我们提供。此时我们并不需要对Idea写好的clone进行修改。
3.上面我在main中调用的clone方法,所以我们需要在main方法上抛出异常(这部分先照做,后面异常的时候再说为啥)。
4.调用完克隆方法后,我们需要将类型转为我们对应的类,因为clone()返回值为Object类型。
为了方便理解,请欣赏下图。
在这里插入图片描述
上面代码中可以看出是一个对象中有另外一个对象,但是浅拷贝就只会拷贝一层,比方说上面部分,并不会再创建一个ban对象,而是将地址直接拷贝过去了,这也正是浅拷贝。

深拷贝

深拷贝则与上面不同代码如下:

class Ban implements Cloneable{
    int num = 19;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Ban{" +
                "num=" + num +
                '}';
    }
}
//深拷贝
class Student implements Cloneable{
    String name;
    int age;
    Ban ban = new Ban();

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        student.ban = (Ban) this.ban.clone();
        return student;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                "," + ban +
                '}';
    }
}
public class JavaSE731 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Student student = new Student("zs",14);
        Student student1 = (Student) student.clone();
        student.ban.num = 99;
        System.out.println(student);
        System.out.println(student1);
    }
}

根据上面代码我们可以看出深拷贝的时候我们对Student的克隆方法进行了修改,并且将Ban类也实现了Cloneable的接口,表示可以进行克隆,并且重写了clone方法。
在这里插入图片描述

接口和抽象类区别

核心区别在于抽象类允许存在普通成员方法和成员变量,但是接口只允许存在抽象方法和常量。
在这里插入图片描述

Object类

Object类是最高的类,所有类的父类,任何对象都可以用Object接收。同时Object提供了很多方法。比方说toString,equals,hascode方法。当然提供的方法可能我们并不适用,这就需要我们重写这个方法,比方说提供的equals方法,对于引用类型而言,比较的就是地址。这就需要我们根据需要去更改。String类就重写了这个方法,方便字符串之间进行内容的比较。

内部类

内部类包括:实例内部类,静态内部类,局部内部类,匿名内部类

实例内部类

没有被static修饰的成员内部类

public class JavaSE731 {
    class Student {
        
    }
}
  1. 在实例内部类中可以访问外部类中的任意访问权限的成员
  2. 在内部类中访问的时候,如果外部类和内部类中有相同名称的成员,则会优先访问内部类自己的
  3. 在内部类中访问的时候,如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字
  4. 要想访问实例类中的成员,必须先实例化内部类,实例化的语法如下:
OutClass.InnerClass innerClass1 = new OutClass().new InnerClass();
  1. 实例内部类的非静态方法中包含了外部类的引用。
  2. 实例内部类有两个引用:this表示内部类自己的,OuterClass.this表示外部类的
  3. 创建内部类对象时,必须先创建外部类对象。
  4. 实例内部类也受访问修饰符的限定。

静态内部类

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

public class JavaSE731 {
    static class Student {

    }
}
  1. 在静态内部类中只可以访问外部类的静态成员。
  2. 创建内部类对象时不需要创建外部类
  3. 静态内部类对象的创建:
OutClass.InnerClass innerClass = new OutClass.InnerClass();

局部内部类

定义在外部类的方法内部或者{}内部的类叫做局部内部类。这个类只可以在定义位置使用。(很少使用)

public class JavaSE731 {
    public void func() {
        class A {
            
        }
    }
}
  1. 局部内部类不可以被public,static修饰
  2. 只可以在方法内部使用

匿名内部类

创建匿名内部类缩减了我们子类继承父类,再重写父类方法,再创建子类对象的过程,直接一步到位了。

父类 对象 = new 父类(){   重写父类中的方法   }class Father {
    public void test() {
        System.out.println("父类");
    }
}
public class JavaSE731 {
    public static void main(String[] args) {
        Father father = new Father(){
            @Override
            public void test() {
                super.test();
            }
        };
    }
}

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

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

相关文章

JavaScript (七)——JavaScript 对象和函数

目录 JavaScript 对象 真实生活中的对象&#xff0c;属性和方法 JavaScript 对象 对象定义 对象属性 访问对象属性 对象方法 JavaScript 函数 JavaScript 函数语法 调用带参数的函数 带有返回值的函数 局部 JavaScript 变量 全局 JavaScript 变量 JavaScript 变量…

“遥遥领先”的观察者模式

前提 观察者模式是我们在开发时经常会用到的模式&#xff0c;最近在维护公司项目时看见了前辈的代码用到了观察者模式。就想来和大家讲解观察者模式 观察者模式 生搬硬套概念肯定会让我们新手很难理解&#xff0c;刚好最近华为手机出新机了&#xff0c;一机难抢&#xff0c;…

内存问题检测

内存检测方式 gcc/g 内存检测方式如下&#xff0c;添加一些编译标签&#xff1a; -fsanitizeleak 检测内存泄漏。例如添加标签&#xff1a;-fsanitizeleak -g -O0-fsanitizeaddress 检测内存越界。例如添加标签&#xff1a;-fsanitizeaddress -g -O2&#xff0c;优化级别开…

ThreadLocal详解及ThreadLocal源码分析

提示&#xff1a;ThreadLocal详解、ThreadLocal与synchronized的区别、ThreadLocal的优势、ThreadLocal的内部结构、ThreadLocalMap源码分析、ThreadLocal导致内存泄漏的原因、要避免内存泄漏可以用哪些方式、ThreadLocal怎么解决Hash冲突问题、避免共享的设计模式、ThreadLoca…

Android DexOpt七种触发流程解析【原创硬核】

Android 13 DexOpt七种触发流程解析 众所周知&#xff0c;DexOpt是安卓应用性能优化非常重要的手段&#xff0c;相当于将应用对虚拟机的多层调用直接转化成了arm机器码。Dex优化过和没优化过&#xff0c;效果千差万别。本文深入解析android系统DexOpt机制的触发流程。 1 DexOpt…

如何学习自动化测试工具!

要学习和掌握自动化测试工具的使用方法&#xff0c;可以按照以下步骤进行&#xff1a; 一、明确学习目标 首先&#xff0c;需要明确你想要学习哪种自动化测试工具。自动化测试工具种类繁多&#xff0c;包括但不限于Selenium、Appium、JMeter、Postman、Robot Framework等&…

安全编程的代码示例

一、python代码示例 一个安全编程的示例是对输入进行严格的验证和过滤。比如&#xff0c;当用户在网页上输入用户名和密码时&#xff0c;应该对这些输入进行验证&#xff0c;防止恶意用户输入恶意代码或进行 SQL 注入等攻击。下面是一个简单的示例代码&#xff1a; import…

OpenFeign微服务调用组件

一、跨服务、跨进程调用方式 1)Httpclient 使用Httpclient我们首先需要引入依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </depend…

Meta/东京电子/FPT软件等共同贡献,Aitomatic发布首个半导体行业开源大模型,「锁死」企业技术自主权

2024 年初&#xff0c;研究机构 Market.us 发布报告预测&#xff0c;全球半导体市场规模将大幅增长&#xff0c;预计 2024 年可达到 6,731 亿美元&#xff0c;到 2032 年预计将增长至 1.3 万亿美元。 毫无疑问&#xff0c;这个万亿级市场与充满想象空间的 AI 密不可分。技术层…

【根号分治】 通知

通知 分析&#xff1a; 这道题根号分治看起来就没有前面几题那么明显了 emm当然也可能是我境界还没到 我们考虑如果暴力修改&#xff0c;复杂度是 O ( n m ) O(nm) O(nm)&#xff0c;其实m为这个点的度数 考虑根号分治的思想&#xff0c;我们令 m M m\sqrt M mM ​ 并命度数大…

申瓯通信设备有限公司在线录音管理系统(复现过程)

漏洞简介 申瓯通信设备有限公司在线录音管理系统 index.php接口处存在任意文件读取漏洞&#xff0c;恶意攻击者可能利用该漏洞读取服务器上的敏感文件&#xff0c;例如客户记录、财务数据或源代码&#xff0c;导致数据泄露 一.复现过程 fofa搜索语句:title"在线录音管…

idea显示properties文件中文乱码的解决方法

1.如下 File-》Settings-》File Encodings,修改如下图中绿框标注的内容 2.点击Apply-->OK 3.修改完成后显示

ROS八股

目录 一、ros1和ros2的区别是什么&#xff1f; 二、rostopic 和 rosserver的区别是什么&#xff1f; 三、讲一下ros的navigation框架 一、ros1和ros2的区别是什么&#xff1f; ROS 1和ROS 2是两个主要版本的机器人操作系统&#xff0c;它们在多个方面存在显著差异&#xff…

【Stable Diffusion】(基础篇七)—— lora

lora 本系列博客笔记主要参考B站nenly同学的视频教程&#xff0c;传送门&#xff1a;B站第一套系统的AI绘画课&#xff01;零基础学会Stable Diffusion&#xff0c;这绝对是你看过的最容易上手的AI绘画教程 | SD WebUI 保姆级攻略_哔哩哔哩_bilibili 除了大模型和VAE之外&…

MySQL:集合运算符

集合运算符 MySQL中的 集合运算符&#xff08;Set operators&#xff09;主要用于结合两个或多个SELECT语句的结果集&#xff0c;这些结果集应该具有相同的列数和数据类型&#xff0c;以便能够进行比较或合并。 需要注意的是&#xff0c;MySQL本身并没有直接称为“Set operat…

Flask目录结构路由重定向简单实例讲解——轻量级的 Python Web 框架

假设一个flask目录结构如下&#xff1a; my_flask_app/ │ ├── app.py ├── routes/ │ ├── __init__.py │ ├── ZhejiangProvince/ │ │ ├── __init__.py │ │ ├── la.py │ │ └── el.py │ ├── GuangdongProvince/ │ │ ├…

常见服务限流方法

一、令牌桶算法&#xff08;Token Bucket&#xff09; 原理其实很简单&#xff0c;就是设置同一时刻服务器能处理请求的最大数量&#xff0c;如果超过这个数据&#xff0c;则需要等待&#xff0c;或者不处理请求。相当于设置最大并发量&#xff0c;但是细节是&#xff0c;还设…

解决nginx端口转发后,获取不到真实IP问题

文章目录 1&#xff0c;设置nginx端口转发1.2&#xff0c;无法获取客户端真实IP 2&#xff0c;nginx配置文件增加配置&#xff0c;保留客户端信息2.2&#xff0c;可以看到真实IP信息 1&#xff0c;设置nginx端口转发 location /AWAPI/ {proxy_pass http://172.28.43.19:9607; …

组件化开发

1.组件化开发 组件化&#xff1a;一个页面可以拆分成一个个组件&#xff0c;每个组件有着自己独立的结构[html]、样式[css]、行为 [js]。好处&#xff1a;便于维护&#xff0c;利于复用 → 提升开发效率。组件分类&#xff1a;普通组件、根组件。比如&#xff1a;下面这个页面…