一个月学会Java 第14天 内部类

news2024/10/26 11:29:20

Day14 内部类

类有外边的public
class,然后还有一个文件多个的class,但是有没有想过,class可以作为成员也就是类内部的类,甚至作为方法内部的属性也就是类内部的方法的内部出现。除了这两个,
还有直接对着上节课讲的抽象类和接口创建对象的匿名内部类,和成员内部类的静态化,静态内部类

第一章 内部类

我们先来讲一下内部类有几个

  • 局部内部类
  • 成员内部类
  • 静态内部类
  • 匿名内部类

分别都是方法内部的、类内部的、类内部的、和创建对象的时候可以匿名创建一个子类的。

局部内部类

局部内部类,刚刚也讲了,其实就是方法内部的一个类,所以叫做局部,以为他并不是作为一个属性存在,而是有点方法内部的变量的意思。

首先我们先来说说怎么进行声明,就是在一个方法内部直接写class即可,在此之前我们先防止踩雷,先说几点,就正常的写类即可,但是在内部的方法声明里面,无法声明static方法,除非你是jdk16+

在这里插入图片描述

其他的情况就和正常的类一样使用即可,还有就是,因为他是局部的,而且是方法内部的,所以无论是什么等级的访问修饰符其实都是一个作用的,就是延伸也延伸不到外面,都是被困死在这个方法内部的,而且就算使用了private关键字进行的声明,在这个方法里面还是可以照常使用被private声明的方法以及属性的,其余和外部的类是一样的

package innerClass;

public class LocalInnerClass {
    public static void main(String[] args) {
        class A {
            private int i = 100;

            private void p() {
                System.out.println("P() method");
            }

            public A() {
                System.out.println("创建对象");
            }
        }
        A a = new A();
        System.out.println(a.i);
        a.p();
    }
}

在这里插入图片描述

局部内部类的作用就是,比如你在方法中临时要用到这块内容,然后这块内容只有在类中是可以实现的,才会这么去用,在一般的开发状况下是用不着的,但是java还是提供着这个办法先,我们也就可以当做了解,不做过多的深入

成员内部类

成员内部类的位置和只有一个类的时候的内部里面的方法和属性是同一等级的,也就是class内部的class和method和property是一个等级的,所以也说明,我们在同一个类里面方法1是不是可以正常调用方法2,所以我在成员内部类class里面的方法3也是可以调用外部类的方法1,如果有重复的,就和局部变量一样,就近原则。

希望大家还记得我们讲就近原则的时候的情况,是this相关,有属性i和形参i,如果只用i就会就近使用形参i,所以这里同理,如果我们就近上使用了同名方法,但是实际上我要用外边的,我们就需要使用this,但是我们这个时候也在类里面,所以这个this前面就要加上一点东西,就是外部类的名字,成员内部类的东西还是很多的,我们娓娓道来

我们先讲创建和使用

package innerClass;

public class OuterClass {
    public class InnerClass {
        public void p1() {
            p();
        }
    }

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

创建十分的简单,就是这样子即可,就是类里面套了一个类,但是我们使用起来的话就没有那么的方便了,我们先学习一下怎么使用,和使用的原理是怎么样的,然后怎么简略使用。

首先,我们的这个类是内部类,所以说是内部的一个类,然后他又是个普通成员,是非静态的,所以我们想要使用这个类,是不是需要使用对象.类这样子的用法,所以就是我们先要创建一个外部类的对象,然后通过外部类的这个对象进行创建内部类的对象

创建外部的类我们还是非常习惯和擅长的是吧,就使用 OuterClass outerClass = new OuterClass()
即可创建外部的类,但是要创建内部的类的话,需要使用外部的类进行new,所以我们写起来就是这样的,自然是基于上面外部类的对象创建好的基础上进行创建的,

OuterClass.InnerClass innerClass = outerClass.new InnerClass()

是不是非常的长,但是希望大家能够理解这个意思,毕竟我已经讲的很清楚了,想要创建一个非静态类然后又在成员位置的类的对象,首先就需要先创建一个外部类的对象,然后再通过这个对象对内部的类进行对象的创建。

然后我们再来看一个缩减版,就是不需要保存外部对象就可以创建,其实就是匿名内部类的使用

OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();

学的比较好的同学们应该可以看懂,其实就是一模一样的,只不过匿名了一下

package innerClass;

public class OuterClass {
    public class InnerClass {
        public void p1() {
            p();
        }
    }

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

class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();
        innerClass.p1();
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass1 = outerClass.new InnerClass();
        innerClass1.p1();
    }
}

在这里插入图片描述

还是非常的简单的对吧,然后我们现在已经会了怎么创建并使用,就再来深究一下内部的情况,比如我刚刚说的就近原则,还有使用外部类的属性和方法,这里我们已经浅演示了一下,因为我们内部类的p1调用了p方法,然后p方法是从属于外部类的。

我们来看一下内部类的就近原则,和使用外部的怎么进行使用,我们使用 外部类类名.this.方法 就可以实现调用

package innerClass;

public class OuterClass {
    public class InnerClass {
        public void p1() {
            p();
            System.out.println("以上为内部类的p,接下来是外部类的p");
            OuterClass.this.p();
        }

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

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

class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();
        innerClass.p1();
    }
}

在这里插入图片描述

现在大家也都已经会了就近原则和怎么使用被就近原则的方法了,接下来我们来讲讲内部类继承的特性

package innerClass;

public class OuterClass {
    public int i = 100;

    public class InnerClass extends OuterClass {
        public int i = 50;

        public void p1() {
            System.out.println("p1()");
            OuterClass.this.p();
        }

        public void p() {
            p1();
            System.out.println("InnerClass p()");
        }
    }

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

class Test {
    public static void main(String[] args) {
        OuterClass innerClass = new OuterClass().new InnerClass();
        innerClass.p();
        System.out.println(innerClass.i);
    }
}

在这里插入图片描述

实际上,和普通的继承是一样的。

静态内部类

静态的成员内部类,就因为是静态的,所以会出现静态的一些特性。

有但不限于,自身为静态,所以不能调用外部的非静态的属性,
比如外部的属性i就是不能调用的,即使自己也没有i。不能出现OuterClass.this.p();
因为这个是属于调用对象了,所以为非静态,然后外部如果为静态方法的话,那就是使用 OuterClass.p()
进行调用了,然后在创建对象的时候也不一样的,要
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
因为这个类为静态类,所以和其他静态属性和方法一样的,无需创建对象,直接使用 类名.静态类名 即可。

同样,继承的话那也和成员内部类一致,但是还有静态类的特性保持住就是一样了。

package innerClass;

public class OuterClass {
    public static int i = 100;

    public static class InnerClass {
        public static void p1() {
            System.out.println("p1()");
        }

        public void p() {
            System.out.println(i);
            p1();
            System.out.println("InnerClass p()");
        }
    }

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

class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
        innerClass.p();
        OuterClass.InnerClass.p1();
    }
}

在这里插入图片描述

静态内部类在实际的作用中还是比较多的,毕竟创建完静态类其实和创建在外边的普通类是差不多了,只不过这个放在内部更好的看见,因为这样普通的类也是进行一次加载,然后对加载完的这个类进行对象的创建,相当于就是镜像,这个声明就是静态,说明和普通的类是一样的加载过程,不像成员内部类会出现,我换一个对象,那个我的类就得重新加载一遍这种情况

匿名内部类

这个类非常的好用而且非常的经常用,就比如说我们创建不了对象的,抽象类啊、接口啊这些,包括正常的类都是可以衍生出匿名内部类的

一般我们的匿名内部类的声明都是 类名 对象 = new 类名(){ }
然后需要补充的东西写在花括号里面,可以理解为直接创建了一个类,然后继承或者是实现了这个最左边的父指子的这个父,我们分别使用抽象类和接口来给大家演示一下,使用匿名内部类的方式实现功能,然后我们再说一下普通的类可以不可以使用匿名内部类的方式进行创建

package innerClass;

public class AnonymousInnerClass {
    public static void main(String[] args) {
        //从花括号开始就是匿名内部类的创建
        A a = new A() {
            @Override
            public void a() {
                System.out.println("method a()");
            }
        };
        a.a();
        a.p();
    }
}

abstract class A {
    public void p() {
        System.out.println("打印一些东西");
    }

    public abstract void a();
}

在这里插入图片描述

我们再来看看接口,这次我们搞两个方法,这里说一句题外话,就是jdk8的新特性,单个方法的接口,又叫做函数式接口,可以使用java8加入的新特性Lambda表达式来更快的解决,Lambda表达式就是匿名内部类写单个方法的接口的缩写版,也就是函数式接口的匿名内部类的缩写版,我们暂且只是提一嘴

package innerClass;

public class AnonymousInnerClass {
    public static void main(String[] args) {
        TwoMethods twoMethods = new TwoMethods() {
            @Override
            public void one() {
                System.out.println("print one");
            }

            @Override
            public void two() {
                System.out.println("print two");
            }
        };
        twoMethods.one();
        twoMethods.two();
    }
}

interface TwoMethods {
    void one();

    void two();
}

在这里插入图片描述

能理解吧,接下来我再带大家看一个东西,也就是字节码的各种内部类是怎么样的。

自然我们从idea中还是看不到的

在这里插入图片描述

这里放的还是比较保守的,其实就是可视化更好,所以接下来我们直接去文件里面去瞅瞅。

在这里插入图片描述

以肉眼可见,我们的LocalInnerClass中出现了个$1A,这个其实就是成员内部类创建的字节码,然后我们的匿名内部类创建的则是,AnonymousInnerClass$1,我们可以来证明一下

package innerClass;

public class AnonymousInnerClass {
    public static void main(String[] args) {
        TwoMethods twoMethods = new TwoMethods() {
            @Override
            public void one() {
                System.out.println("print one");
            }

            @Override
            public void two() {
                System.out.println("print two");
            }
        };
        twoMethods.one();
        twoMethods.two();
        System.out.println(twoMethods);
        System.out.println(new AnonymousInnerClass());
        System.out.println(twoMethods instanceof AnonymousInnerClass);
        System.out.println(twoMethods instanceof TwoMethods);
    }
}

interface TwoMethods {
    void one();

    void two();
}

在这里插入图片描述

答案告诉我们,他只是名字是和这个AnonymousInnerClass有关,但和这个类实际上是无关的,因为我们在判断实例的时候直接返回了false,下面的true也说明我们直接创建的这个类,实际上就是实现/继承了我们没办法直接创建实例的类,并创建一个对象,但是没有实际的名字给我们看到,所以叫做匿名内部类

包括匿名对象,其实我们不知道这个对象的名字,毕竟我们的 Hello hello = new Hello() 里面的对象就是hello是吧,但是我们直接使用
new Hello() 的话是不是就是不知道他叫什么名字,那是不是就是匿名的。

还有一点,就是不只是只有不能创建对象的抽象类和接口才能使用匿名内部类,其实什么类都可以使用匿名内部类的方式进行创建对象,包括正常的类,接下来就给大家演示一下

package innerClass;

public class AnonymousInnerClass {
    public static void main(String[] args) {
        Dog dog = new Dog() {

        };
        dog.setAge(10);
        dog.setName("Nick");
        System.out.println(dog);
    }
}

class Dog {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Dog() {
    }

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

在这里插入图片描述

结果很明显,并没有任何的问题

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

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

相关文章

GeoScene Pro教程(008):GeoScenePro数据查询和检索

文章目录 1、工具分类2、数据常用工具2.1 加载数据2.2 查询需求2.2.1 按照属性查询查询1:人口大于300万的城市有哪些查询2:自治州有哪些查询3:城市名字中带有“荆”的有哪些补充2.2.2 按照位置查询需求2:导出湖北省境内的铁路数据需求3:武汉市共有多少条铁路2.2.3 空间连接…

48 Redis

48 Redis 前言 Redis(Remote Dictionary Server ),即远程字典服务。是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 redis会周期性的把更新的数据写入磁盘或者把修改操…

RTSP与ONVIF协议的区别及其在EasyCVR视频汇聚平台中的应用

在视频监控和物联网设备领域,RTSP(Real Time Streaming Protocol)和ONVIF(Open Network Video Interface Forum)是两个重要的协议,它们各自在视频流的传输和控制上发挥着不同的作用,并在实际应用…

网络安全之XXE攻击

0x01 什么是 XXE 个人认为,XXE 可以归结为一句话:构造恶意 DTD 介绍 XXE 之前,我先来说一下普通的 XML 注入,这个的利用面比较狭窄,如果有的话应该也是逻辑漏洞。 既然能插入 XML 代码,那我们肯定不能善罢…

基于Nodemcu的手机控制小车

基于Nodemcu的手机控制小车 一、项目说明二、项目材料三、代码与电路设计四、轮子和车体五、电路连接六、使用方法 一、项目说明 嗨,机器人项目制造者们!在这个项目中,我制作了这辆简单但快速的遥控车,它可以通过智能手机控制&am…

gaussdb 主备版本8 SQL参考 学习

SQL参考 1 数据类型 1.1 货币类型 1.1.1 货币类型存储带有固定小数精度的货币金额。 1.2 布尔类型 1.2.1 true:真 1.2.2 false:假 1.2.3 null:未知(unknown) 1.3 日期/时间类型 1.3.1 DATE 输出格式:仅支…

MySQL-06.DDL-表结构操作-创建

一.DDL(表操作) create database db01;use db01;create table tb_user(id int comment ID,唯一标识,username varchar(20) comment 用户名,name varchar(10) comment 姓名,age int comment 年龄,gender char(1) comment 性别 ) comment 用户表; 此时并没有限制ID为…

圈子系统APP小程序H5该如何设置IM?

搭建圈子系统的常见问题,以及圈子论坛系统的功能特点 社交圈子论坛系统的概念 圈子小程序源码 多客圈子系统 圈子是什么软件 跟进圈一个系统的软件 为圈子系统APP小程序H5设置IM(即时通讯),需要遵循一系列步骤来确保通讯功能的稳定、安全和高…

企业架构之从理论指南到实践指导企业数字化转型

理论与实践结合的数字化转型之道 在当今的全球化经济中,企业面临着前所未有的数字化转型压力。数字化转型不仅是技术的更新换代,更是业务、组织、文化和战略的系统性重塑。对于企业来说,如何将理论转换为有效的实践路径,是推动数…

STM32 通用同步/异步收发器

目录 串行通信基础 串行异步通信数据格式 USART介绍 USART的主要特性 USART的功能 USART的通信时序 USART的中断 串行通信基础 在串行通信中,参与通信的两台或多台设备通常共享一条物理通路。发送者依次逐位发送一串数据信号,按一定的约定规则被接…

乐鑫ESP32-S3无线方案,AI大模型中控屏智能升级,提升智能家居用户体验

在这个由数据驱动的时代,人工智能正以其前所未有的速度和规模改变着我们的世界。随着技术的不断进步,AI已经从科幻小说中的概念,转变为我们日常生活中不可或缺的一部分。 特别是在智能家居领域,AI的应用已成为提升生活质量、增强…

linux下编译鸿蒙版curl、openssl

一.环境准备 1.参考说明 NDK开发介绍:https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/napi/ndk-development-overview.md 2.NDK下载 点击介绍页面中的链接可以跳转到相应下载页面: 下载相应版本: 下载完毕后解压到指定目…

Matlab详细学习教程 MATLAB使用教程与知识点总结

Matlab语言教程 章节目录 一、Matlab简介与基础操作 二、变量与数据类型 三、矩阵与数组操作 四、基本数学运算与函数 五、图形绘制与数据可视化 六、控制流与逻辑运算 七、脚本与函数编写 八、数据导入与导出 九、Matlab应用实例分析 一、Matlab简介与基础操作 重点内容知识…

第2章 STM32最小系统介绍

第2章 STM32最小系统介绍 1. STM32最小系统组成 2. STM32启动模式 1.STM32最小系统组成 (1)电源电路 (2)复位电路 (3) 晶振电路 (4)下载电路 可打开开发板原理图查看 2.STM32启动模式 在STM…

Postman最新V11版本关键更新一览

Postman作为接口测试中,被广泛应用的一款主流工具,以其丰富的功能,灵活方便的使用方式,广受欢迎。最新发布的V11版本则在向协作平台转型的过程中一路狂奔,增加大量全新的协作支持。下面我们就一起来看看都有哪些变化吧…

基于Arduino的泡茶机器人

打造你的完美泡茶助手 引言 你是否曾遇到过泡出的茶太淡或太苦?通过这个项目,你可以创建一个设备,为你的茶包提供完美的浸泡时间。只需附上一个茶包并放置你的杯子,设备就会开始工作!它将完美地按照你的喜好浸泡你的…

数通--3

一、动态路由 内部 路由器之间要互联互通,必须遵循相同的协议 企业内部用 IGP,企业之间用BGP RIP(已淘汰,不考) 距离就是长短,矢量就是方向,即路由的出接口 一台路由器 A 配好RIP,…

【Fargo】5:根据网络带宽动态调整发送速率

根据网络带宽动态调整发送速率 原理:这个简单实现的原理是 改变包的发送速率就可以改变发送码率了。例如1秒发1000个1KB 的包,带宽8Mbps,如果带宽是4Mbps,那么1秒发500个就够了。D:\XTRANS\thunderbolt\ayame\zhb-bifrost\player-only\worker\src\fargo\zhb_uv_udp_sender.…

好书分享《大模型应用开发极简入门》

本书为大模型应用开发极简入门手册,为初学者提供了一份清晰、全面的“可用知识”,带领大家快速了解GPT-4和ChatGPT的工作原理及优势,并在此基础上使用流行的Python编程语言构建大模型应用。 通过本书,你不仅可以学会如何构建文本生…

大数据开发基础实训室设备

大数据实验实训一体机 大数据实验教学一体机是一种专为大数据教育设计的软硬件融合产品,其基于华为机架服务器进行了调优设计,从而提供了卓越的性能和稳定性。这一产品将企业级虚拟化管理系统与实验实训教学信息化平台内置于一体,通过软硬件…