【Java 学习】:内部类详解

news2024/9/24 3:22:47

详谈Java内部类

📃📃本文将通过Java内部类 是什么,为什么被广泛使用,以及又该如何去使用这三个方面来详细讲解其相关知识。

文章目录

1. 内部类是什么

2. 为什么要使用内部类

3. 如何使用内部类

🍉成员内部类

🥑静态内部类

🥝局部内部类

🍋‍🟩匿名内部类

📖总结


1. 内部类是什么

🥬🥬🥬当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。

/**
* 外部类
*/
public class Outer {
	//...
	/**
	* 内部类
	*/
	class Inner {
		//...
	}
}

注:

  • 我们一般将内部类分为四种:成员内部类静态内部类局部(方法内部类)匿名内部类
  • 外部类的定义是相对于内部类而言的

2. 为什么要使用内部类

🍈使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。——《Think in java》

🍈也就是说内部类拥有类的基本特征。(eg:可以继承父类,实现接口)在实际问题中我们会遇到一些接口无法解决或难以解决的问题,此时我们可以使用内部类继承某个具体的或抽象的类,间接解决类无法多继承引起的一系列问题。

注:内部类可以嵌套内部类,但是这极大的破坏了代码的结构,但是这里不推荐使用。

举个例子🌰

/**
 1. OuterClass类继承了 A,实现了IFunctionA
*/
public class OuterClass extends A implements IFunctionA{ 
	/**
	*	Inner类继承了 B,实现了IFunctionB
	*/
	public class InnerClass extends B implements IfunctionB{
	//
	} 
}

除此之外,内部类还可以:

  1. 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
  2. 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
  3. 内部类提供了更好的封装,除了该外围类,其他类都不能访问。
  4. 创建内部类对象的时刻并不依赖于外围类对象的创建。

3. 如何使用内部类

🍉成员内部类

 💢💢也叫作实例内部类,是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:

// 实例内部类
class OuterClass {
    public int data1 = 1;
    public static int data2 = 2;
    private int data3 = 3;

    /*成员方法*/
    public void OuterMethod() {
        System.out.println("外部类的outerMethod方法");
    }

    /*静态方法*/
    public static void OuterStaticMethod() {
        System.out.println("外部类的outerStaticMethod静态方法");
    }

    /*同名方法*/
    public void test() {
        System.out.println("OutClass:: test()");
        InnerClass innerClass = new InnerClass();
    }

    class InnerClass{
        public int data1 = 10;
        public int data4 = 4;
        //public static int data5 = 5; // jdk8 不支持这样用,jdk17 支持
        public static final int data5 = 5;
        private int data6 = 6;

        public void InnerShow() {
            //访问内部类属性
            System.out.println("data4:" + data4);
            //内部类访问外部属性
            System.out.println("data3:" + data3); //私有权限的外部类也可以访问
            //当和外部类冲突时,直接引用属性名,是内部类的成员属性
            System.out.println("data1:" + this.data1); // 默认为this
            //当和外部类属性名重叠时,可通过外部类名.this.属性名
            System.out.println("data1:" + OuterClass.this.data1); //访问外部类成员

            // 访问外部类方法
            OuterMethod();
            OuterStaticMethod();
        }

        public void test(){
            System.out.println("InnerClass:: test()");
        }
    }
    /* 	外部类访问内部类信息 */
    public void OuterShow() {
        InnerClass inner = new InnerClass();
        inner.InnerShow();
    }
}


public class Test {
    /*其他类使用成员内部类*/
    public static void main(String[] args) {
        //创造内部类对象,两种实例化方法
        OuterClass outer = new OuterClass(); //外部类对象
        OuterClass.InnerClass inner1 = outer.new InnerClass();

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

        inner1.test();
        inner1.InnerShow();
    }
}

运行结果如下:

注:成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

总结:【抓住关键字——实例,作为实例成员存在】

  1. 内部类可以是任何的访问修饰符。由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰符。
  2. 内部类的内部不能有静态信息。
  3. 内部类也是类,该继承的继承、该重写的重写、该重载的重载,this和super随便用。
  4. 外部类访问内部类的信息,必须先实例化内部类,然后 . 访问。
  5. 内部类可以直接使用外部类的任何信息,如果属性或者方法发生冲突(重名),使用Outer.this.成员
  6. 其他类访问内部类:成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在外部类的对象。

🥑静态内部类

 💢💢Java中的静态内部类是指在一个类的内部定义的另一个类,并且该内部类被声明为静态(static)的。静态内部类与普通内部类的区别在于,静态内部类不依赖于外部类的实例,可以直接通过外部类名访问

// 静态内部类
class Outer{
    public int data1 = 1;
    /*外部类定义的属性(重名)*/
    public static int data2 = 2;
    public static int data3 = 3;

    static {
        System.out.println("外部类静态块");
    }

    /*成员方法*/
    public void outerMothod() {
        System.out.println("外部类的成员方法");
    }

    /*静态方法*/
    public static void outerStaticMethod() {
        System.out.println("外部类的静态方法");
    }

    public void test(){
        System.out.println("Out:: test()");
    }

    static class Inner{
        public int data4 = 4;
        public static int data5 = 5;
        public static int data3 = 33; //与外部类同名

        public void InnerShow(){
            // 访问内部类成员属性
            System.out.println("内部类data4:"+data4);
            //访问外部类成员属性
            //不重名访问 非静态成员属性
            //System.out.println(data1); //无法直接访问外部非静态成员
            System.out.println("data1:" + new Outer().data1); // 间接访问

            //不重名直接访问 静态成员属性
            System.out.println("外部类data2:" + data2);
            System.out.println("内部的data3:"+ data3);
            System.out.println("外部的data3:"+ Outer.data3);

        }

        public static void InnerStaticShow() {
            //调用时会先加载Outer类,类加载的时候执行静态代码块
            outerStaticMethod();
        }
    }
    /*外部类的内部如何和内部类打交道*/
    public static void callInner() {
        System.out.println(Inner.data3);
        //System.out.println(Inner.data4); //内部类的非静态成员属性无法直接访问
        System.out.println(new Inner().data4);
        
        Inner.InnerStaticShow();
        new Inner().InnerShow();  //调用内部类非静态成员方法
    }
}

public class Test {
    /* 其他类访问静态内部类 */
    public static void main(String[] args) {
        //访问静态内部类的静态方法,Inner类被加载(类加载的时候执行静态代码块),此时外部类未被加载,独立存在,不依赖于外部类。
        Outer.Inner.InnerStaticShow();

        // 静态内部类实例化,不用(),相比于实例内部类优点:不需要外部类的引用
        Outer.Inner in = new Outer.Inner();
        in.InnerShow();
    }
}

总结:【抓住关键字——static,作为静态成员存在】

  1. 静态内部类可以包含任意的信息,可以被任意访问权限修饰符修饰。
  2. 静态内部类的方法只能访问外部类的static关联的成员。
  3. 静态内部类可以独立存在,不依赖于其他外围类。
  4. 其他类访问内部类的静态信息,直接 Outer.Inner.static成员信息 就可以了。
  5. 其他类实例化内部类 Outer.Inner instance = new Outer.Inner();,然后 instance. 成员信息(属性、方法)即可。

🥝局部内部类

💢💢 Java局部内部类是指在一个方法或代码块内部定义的内部类。与成员内部类不同,局部内部类只能在定义它的方法或代码块内部使用,无法在外部访问。

public class Out {
    /*属性和方法*/
    private int outVariable = 1;
    /*外部类定义的属性*/
    private int commonVariable = 2;
    /*静态的信息 */
    private static int outStaticVariable = 3;

    /*成员外部方法*/
    public void outerMethod() {
        System.out.println("我是外部类的outerMethod方法");
    }
    /*静态外部方法*/
    public static void outerStaticMethod() {
        System.out.println("我是外部类的outerStaticMethod静态方法");
    }
    /*成员方法,内部定义局部内部类*/
    public void outerCreatMethod(int value) {
        //public int a = 1; // 不行,局部内部类不能有访问权限修饰符
        //static int a = 1; // 也不能有static 修饰
        final int a = 1;
        int a1 = 1; // 默认为final
        /*女性*/
        boolean sex = false;
        //sex = true; // 有且仅有赋值一次

        /*局部内部类,类前不能有访问修饰符*/
        class In {
            private int inVariable = 10;
            private int commonVariable = 20;
            /*局部内部类方法*/
            public void InnerShow() {
                System.out.println("innerVariable:" + inVariable);
                //局部变量
                System.out.println("是否男性:" + sex);
                System.out.println("参数value:" + value);
                //调用外部类的信息
                System.out.println("outerVariable:" + outVariable);
                System.out.println("内部的commonVariable:" + commonVariable);
                System.out.println("外部的commonVariable:" + Out.this.commonVariable);
                System.out.println("outerStaticVariable:" + outStaticVariable);
                outerMethod();
                outerStaticMethod();
            }
        }
        //局部内部类只能在方法内使用
        In in = new In();
        in.InnerShow();
    }

    /* 开始程序 */
    public static void main(String[] args) {
        Out out = new Out();
        out.outerCreatMethod(100);
    }
}

总结:【抓住关键——作用域,作为方法的局部成员存在】

  1. 局部内部类不能有访问权限修饰符,无法创建静态信息。                                                局部内部类就像是方法里面的一个局部变量一样,是不能有访问权限修饰符和static修饰符的。
  2. 只能在方法内部使用。
  3. 可以直接访问方法内的局部变量和参数。【存在限制,需要 final 或有效的final修饰的】,但是不能更改。 
    ①直接被final修饰的变量。
    ②已被赋值且始终未改变的变量(有且仅有赋值一次),引用指向不能改变。注:JDK8以前(不包括8)只能访问被final修饰的变量。
  4. 编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字.class

注:当局部内部类的变量修改时,就会产生如下错误:

Variable ‘xxx’ is accessed from within inner class, needs to be final or effectively final

传入局部内部类所在方法的参数同理,如果一直不变则可使用,反之则会报错。

局部内部类使用的很少,了解即可.

🍋‍🟩匿名内部类

 💢💢 Java匿名内部类是一种特殊的内部类,它没有类名,直接在创建对象时定义并实现。通常用于创建只需要使用一次的类对象,可以简化代码,提高代码的可读性和可维护性。

  • 原本我们需要创建子类或实现类,去继承父类或实现接口,才能重写其中的方法。但是有时候我们这样做了,然而子类和实现类却只使用了一次(定义了一个对象)。这个时候我们就可以使用匿名内部类,不用去写子类和实现类,起到简化代码的作用。
  • 这样做,把子类继承父类,重写父类中的方法,创建子类对象,合成了一步完成,减少了其中创建子类的过程。或者实现类实现接口,重写接口中的方法,创建实现类对象,合成了一步完成,减少了其中创建实现类的过程。

🥬匿名内部类是不能有名字的类,他们不能被引用,只能在创建是用 new 语句来声明他们。

// 匿名内部类
interface IA{
    void test(); //接口的方法不能有具体实现
}

public class Test {
    public static void main(String[] args) {
        // 匿名内部类对象,下面两种方法都可以
        /*new IA(){
            @Override
            public void test() {
                System.out.println("重写了接口的方法");
            }
        };*/

        IA a = new IA(){
            @Override
            public void test() {
                System.out.println("重写了接口的方法");
            }
        };
        a.test();
    }
}

总结:【匿名内部类通常继承一个类或实现一个接口】

  1. 匿名内部类没有访问权限修饰符。
  2. 匿名内部类要实现父类或接口的所有抽象方法,其他方法可以根据自己的情况进行重写。
  3. 匿名内部类不应当添加自己的成员,因为匿名类没有类名无法向下转型,父类型的引用无法访问。
  4. 匿名内部类访问方法参数时也有和局部内部类同样的限制。
  5. 匿名内部类没有构造方法。
  6. 匿名类是表达式形式定义的,所以末尾以分号;来结束。


📖总结

具体来说,内部类信息(属性、方法)可以和外部类重名;内部类是具有类的基本特征的独立实体;可以利用访问修饰符隐藏内部类的实施细节,提供了更好的封装;静态内部类使用时可直接使用,不需先创造外部类。

💞 💞 💞那么本篇到此就结束,希望我的这篇博客可以给你提供有益的参考和启示,感谢大家支持!!!祝大家天天开心

 

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

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

相关文章

排列组合常用方法一:捆绑法

别问我排列组合是什么,自己看去 看完排列组合的计算方法,有些萌新就会问了,哎?有些题可不像单纯的排列组合哦,题目可能会提出各种奇怪的要求,真是五花八门耶......别急,接下来介绍一个方法&…

【进阶】面向对象之继承(二)

文章目录 一丶子类到底能继承父类中的哪些内容二丶继承中:成员变量的访问特点三丶练习代码呈现 四丶总结 一丶子类到底能继承父类中的哪些内容 构造方法是否可以被继承? 不可以 成员变量是否可以被继承? 可以 成员方法是否可以被继承? 可以,只有虚方法可以被继承 二丶继…

内核头文件, makfile 传参

1 内核头文件,主要指的是, 在板卡上的系统上直接 ,编译驱动模块,而不是在虚拟机的内核源码中 去编译内核模块。 ------------------------------------------------------------------------------------------------------------…

将x减到零的最小操作数问题

欢迎跳转我的主页:羑悻的小杀马特-CSDN博客 目录 一题目简述: 二题目思路: 三解答代码: 一题目简述: leetcode题目链接:. - 力扣(LeetCode) 二题目思路: 首先这道题…

如何在国内下载llama模型

由于项目需求要下载llama模型,本来觉得这是个很简单的事情,直接去huggingface上下载就行,但是没想到遇到了重重问题,于是写下这篇博客记录一下,希望对别人也有帮助! 刚开始搜到的教程是官方给出的&#xf…

C++笔记---string类(简单地使用)

1. string类介绍 string类是C标准库中给出的一种类类型,其目的是为了代替C语言中的字符串。 C语言中,字符串是以\0结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是…

基于vue框架的车辆交易管理系统n5xwr(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:用户,汽车品牌,汽车信息,汽车标签,特价汽车 开题报告内容 基于Vue框架的车辆交易管理系统开题报告 一、研究背景与意义 随着汽车市场的蓬勃发展和消费者购车需求的日益增长,车辆交易活动变得愈发频繁和复杂。传统的车辆交…

工业主板在轨道交通中的应用特点

工业主板在轨道交通中的应用特点主要体现在以下几个方面: 一、强大的处理能力 高性能处理器:工业主板通常搭载高性能的处理器,如飞腾D2000八核CPU等,这些处理器能够高效处理轨道交通系统中的大量数据,确保系统运行的…

Python实战: 写入 Excel 的多个 Sheet

更多内容 个人网站:孔乙己大叔 一、引言 在处理大型数据集或需要向非技术用户展示分析结果时,Excel 是一种广泛使用的工具。然而,手动创建包含多个 Sheet 的 Excel 文件既耗时又容易出错。幸运的是,Python 提供了自动化这一过程的…

51单片机仿真单只共阳级数码管循环显示0-9

51单片机仿真单只共阳级数码管循环显示0-9 单片机AT89C51控制7段共阳数码管的实验报告 一、实验目的 本实验旨在通过使用AT89C51单片机和7段共阳数码管,学习如何编写控制程序以及实现数码管的动态显示。通过此实验,加深对单片机基本原理和实际应用的理…

进程间通信方式(共享内存、信号灯集、消息队列)

共享内存 特点 1)共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。 2)为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程 将其映射到自己的…

1.第二阶段x86游戏实战2-前言

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 本次会有100章左右,会从0基础开始,内容有找游戏中的数据、分析游戏中的数据&…

C++ | Leetcode C++题解之第389题找不同

题目: 题解: class Solution { public:char findTheDifference(string s, string t) {int ret 0;for (char ch: s) {ret ^ ch;}for (char ch: t) {ret ^ ch;}return ret;} };

REAL-FAKE: EFFECTIVE TRAINING DATA SYNTHESISTHROUGH DISTRIBUTION MATCHING 论文学习

这篇文章主要讲的是生成数据在模型训练中的作用,对于接下来要研究的生成多模态数据具有重要的作用。 文章摘要首先讲生成数据很重要,但在训练高级的模型的时候效果不好。论文主要研究的是这背后的原理并且证明了生成数据的作用。 介绍部分,…

在社交物联网中使用MQTT协议和Hardy Wall算法实现有效的多播通信

这篇论文的标题是《EFFECTIVE MULTICAST COMMUNICATION USING MQTT PROTOCOL AND HARDY WALL ALGORITHM IN SIOT》,作者是 S.Jayasri 和 Dr. R.Parameswari,发表在《International Journal of Applied Engineering & Technology》2023年9月的第5卷第…

kubeadm方式升级k8s集群

一、注意事项 升级前最好备份所有组件及数据,例如etcd 不要跨两个大版本进行升级,可能会存在版本bug,如: 1.19.4–>1.20.4 可以 1.19.4–>1.21.4 不可以 跨多个版本的可以逐个版本进行升级。 二、查看当前版本 [rootk8s…

Solidity初体验

一、概念知识 什么是智能合约? 智能合约是仅在满足特定条件时才在区块链上部署和执行的功能,无需任何第三方参与。 由于智能合约本质上是不可变的和分布式的,因此它们在编写和部署后无法修改或更新。此外,分布式的意义在于任何…

上证50ETF期权交易策略有哪些?期权交易时要注意什么?

今天带你了解上证50ETF期权交易策略有哪些?期权交易时要注意什么?上证50ETF期权是一种以华夏50etf基金为标的物的金融衍生品,它允许投资者通过买卖期权合约来对冲风险或进行投机。 期权趋势型策略 趋势型的策略就是我们通常说的追涨杀跌&am…

git代码托管仓库02(分支与冲突)

分支 所有版本控制系统都以某种形式支持分支。使用分支意味着可以把自己的工作从开发主线上分离来进行重大的bug修改,开发新的功能,以免影响主线开发 该master就是分支 查看分支:git branch 添加分支: git branch 分支名 可以看…

C++笔记17•数据结构:二叉搜索树(K模型/KV模型实现)•

二叉搜索树 1.二叉搜索树 1. 二叉搜索树的查找 a 、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。 b 、最多查找高度次,走到到空,还没找到,这个值不存在。2. 二叉搜索树的插入 插入的具…