【Java 学习】:内部类详解

详谈Java内部类

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

文章目录

[1. 内部类是什么](#1. 内部类是什么)

[2. 为什么要使用内部类](#2. 为什么要使用内部类)

[3. 如何使用内部类](#3. 如何使用内部类)

🍉成员内部类

🥑静态内部类

🥝局部内部类

🍋‍🟩匿名内部类

📖总结


1. 内部类是什么

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

cpp 复制代码
/**
* 外部类
*/
public class Outer {
	//...
	/**
	* 内部类
	*/
	class Inner {
		//...
	}
}

注:

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

2. 为什么要使用内部类

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

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

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

举个例子🌰

cpp 复制代码
/**
 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. 如何使用内部类

🍉成员内部类

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

cpp 复制代码
// 实例内部类
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)的。静态内部类与普通内部类的区别在于,静态内部类不依赖于外部类的实例,可以直接通过外部类名访问

cpp 复制代码
// 静态内部类
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局部内部类是指在一个方法或代码块内部定义的内部类。与成员内部类不同,局部内部类只能在定义它的方法或代码块内部使用,无法在外部访问。

cpp 复制代码
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 语句来声明他们。

cpp 复制代码
// 匿名内部类
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. 匿名类是表达式形式定义的,所以末尾以分号;来结束。

📖总结

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

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

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习