Java中的内部类(如果想知道Java中有关内部类的知识点,那么只看这一篇就足够了!)

简介: Java中的内部类(如果想知道Java中有关内部类的知识点,那么只看这一篇就足够了!)

1.内部类的分类及作用

       在前言中我们已经大致的了解了Java中的内部类,但是在开始学习各种内部类之前,先让我们了解一下有哪些内部类及各个内部类的作用,根据其定义位置和特性,内部类可以分为以下几种主要类型:

       (1)成员内部类(Member Inner Class)

       ——定义位置: 成员内部类定义在一个类的内部,作为该类的成员,与类的其他成员(字段、方法等)处于同一层次。

       ——作用: 成员内部类可以访问外部类的所有成员(包括私有成员),并且可以被外部类的方法调用。它通常用于与外部类有密切关系的场景,如实现某种数据结构的迭代器或者实现某种特定逻辑的辅助类。

       (2)静态内部类(Static Nested Class)

       ——定义位置: 静态内部类使用 static 关键字修饰,与外部类的实例无关,通常定义在外部类的内部作为静态成员。

       ——作用: 静态内部类可以直接通过外部类的类名访问,不需要依赖外部类的实例。它通常用于组织和封装与外部类紧密相关的辅助功能,例如工具类或者单例模式的实现。

       (3)局部内部类(Local Inner Class)

       ——定义位置: 局部内部类定义在方法内部,作为方法的局部变量。

       ——作用: 局部内部类的作用域仅限于所在方法内部,通常用于封装一些复杂的逻辑或者需要单次使用的类定义。它可以访问方法的参数和局部变量,但是这些变量必须声明为 final 或者是实际上的 final(即不可再被修改)。

       (4)匿名内部类(Anonymous Inner Class)

       ——定义位置: 匿名内部类没有显式的类名,在创建对象的同时直接实现类的定义。

       ——作用: 匿名内部类通常用于创建只需一次使用的类的实例,例如实现接口或抽象类的匿名实现。它简化了代码的编写,使得代码更加紧凑和易于理解。

内部类的作用总结:

  • 提高封装性和组织性: 内部类可以访问外部类的私有成员,有助于将相关的功能封装在一起,提高代码的模块化和可维护性。
  • 实现复杂设计模式: 内部类在实现一些复杂的设计模式或者数据结构时特别有用,如迭代器模式、工厂模式等。
  • 实现回调函数和事件处理: 匿名内部类常用于实现回调函数和事件处理,使得代码更加灵活和可扩展。
  • 提供更好的代码结构和可读性: 合理使用内部类可以使得代码结构更加清晰和易于理解,尤其是在处理复杂逻辑或者嵌套关系较多的情况下。

       通过上边对于每个内部类的大致讲解,我相信读者对于内部类已经有了一些初步的理解,但是光是看上面这些生硬冰冷的文字,我相信读者可能还是不能很好的理解Java中的内部类,那么接下来让我们对上面的各个内部类进行一一讲解。

      —— 为了方便读者理解,我们每个内部类都会采用先介绍其定义的方式,然后介绍如何创建其内部类的对象,最后使用一个综合的案例加深理解的流程讲解每个内部类。

2.实例内部类

       在Java中,实例内部类(也称为非静态内部类)是定义在另一个类(外部类)内部的类,并且这个内部类会隐式地持有一个对外部类实例的引用。

(1)实例内部类的大致定义形式:

//外部类
public class OuterClass {
    //外部类成员变量
    private int outerField;
 
    //外部类成员方法
    public void outerMethod() {
        System.out.println("Outer method");
    }
 
    //内部类
    public class InstanceInnerClass {
        //内部类成员变量
        private int innerField;
 
        //内部类成员方法
        public void innerMethod() {
            
        }
    }
}

       以上就是实例内部类的大致定义形式,也就是说如果我们需要一个实例内部类的话,我们就会像上述那样定义一个外部类,然后定义一个其内部类。

(2)实例内部类对象的创建

       根据上边的代码,我们现在在测试类中创建其内部类的实例:

  public class TestInnerClass {  
      public static void main(String[] args) {  
 
          // 创建外部类实例  
          OuterClass outer = new OuterClass();  
 
          // 通过外部类实例创建内部类实例  
          OuterClass.InstanceInnerClass inner = outer.new InstanceInnerClass();  
      }  
  }

       我们会发现,如果想要创建实例内部类,那么我们就必须先创建外部类的实例对象,在创建内部类的实例对象。

注意事项:

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

(3)综合案例

       现在让我们通过一个简单的例子来演示Java中实例内部类的使用。假设我们有一个外部类 Car 表示汽车,汽车有品牌和颜色属性,并且每辆汽车可以有一个内部类 Engine 表示其引擎。

// 外部类 Car
public class Car {
    private String brand;
    private String color;
 
    // 构造方法
    public Car(String brand, String color) {
        this.brand = brand;
        this.color = color;
    }
 
    // 外部类的方法
    public void displayInfo() {
        System.out.println("Car brand: " + brand);
        System.out.println("Car color: " + color);
    }
 
    // 内部类 Engine
    public class Engine {
        private int horsepower;
 
        // 构造方法
        public Engine(int horsepower) {
            this.horsepower = horsepower;
        }
 
        // 内部类的方法
        public void start() {
            System.out.println("Engine started! Horsepower: " + horsepower);
        }
    }
}

在这个例子中:

  • Car 类是外部类,它有两个私有属性 brand 和 color,以及一个构造方法用于初始化这些属性。
  • Car 类中有一个方法 displayInfo(),用于显示汽车的品牌和颜色。
  • Car 类内部定义了一个实例内部类 Engine,表示汽车的引擎。Engine 类有一个私有属性 horsepower 表示马力,并有一个构造方法初始化这个属性。
  • Engine 类中有一个方法 start(),用于启动引擎并显示其马力。

下面是如何在 Main 类中使用 Car 类及其内部类 Engine 的示例:

// 主类 Main
public class Main {
    public static void main(String[] args) {
        // 创建外部类的对象
        Car myCar = new Car("Toyota", "Red");
 
        // 调用外部类的方法
        myCar.displayInfo();
 
        // 创建内部类的对象
        Car.Engine engine = myCar.new Engine(150);
 
        // 调用内部类的方法
        engine.start();
    }
}

在 Main 类的 main 方法中:

  • 首先创建了外部类 Car 的对象 myCar,并传入品牌 "Toyota" 和颜色 "Red"。
  • 调用外部类的方法 displayInfo(),显示汽车的品牌和颜色。
  • 创建了内部类 Engine 的对象 engine,使用语法 myCar.new Engine(150),表示该引擎有150马力。
  • 调用内部类 Engine 的方法 start(),启动引擎并显示其马力。

这样我们就大致的了解完了Java中的实例内部类了。

3.静态内部类

       静态内部类(Static Inner Class)在Java中是指定义在另一个类内部并使用 static 修饰的类。

(1)静态内部类的大致定义形式:

public class OuterClass {
    // 外部类的成员变量和方法
    private static int outerStaticField;
    private int outerInstanceField;
 
    public static void outerStaticMethod() {
        // 外部类的静态方法
    }
 
    // 静态内部类
    public static class StaticInnerClass {
        // 内部类的成员变量和方法
        private int innerField;
 
        public void innerMethod() {
            
        }
    }
}

       以上就是静态内部类的大致定义形式,和实例内部类的大致相同,只不过在定义静态内部类时,加上了static关键词。

(2)静态内部类对象的创建

       根据上边的代码,我们现在在测试类中创建其内部类的实例:

    public static void main(String[] args) {
        // 创建静态内部类的实例
        StaticInnerClass innerObject = new StaticInnerClass();
 
    }
}

       我们会发现,相较于实例内部类而言,静态内部类不需要依赖外部类的实例而可以被实例化和使用。

注意事项:

       1.在静态内部类中只能访问外部类中的静态成员

       2.创建静态内部类对象时,不需要先创建外部类对象

(3)综合案例

       让我们通过一个简单的例子来演示Java中静态内部类的使用。假设我们有一个外部类 Outer 表示外部容器,里面包含一个静态内部类 Inner,用来表示容器内部的元素。

// 外部类 Outer
public class Outer {
    private static String outerField = "Outer's static field";
 
    // 外部类的静态方法
    public static void outerStaticMethod() {
        System.out.println("Outer's static method");
    }
 
    // 静态内部类 Inner
    public static class Inner {
        private String innerField;
 
        // 内部类的构造方法
        public Inner(String innerField) {
            this.innerField = innerField;
        }
 
        // 内部类的方法
        public void display() {
            System.out.println("Inner's method: " + innerField);
            System.out.println("Accessing outer's static field: " + outerField);
            outerStaticMethod();
        }
    }
 
    public static void main(String[] args) {
        // 创建静态内部类的实例
        Inner innerObject = new Inner("Inner's field");
 
        // 调用内部类的方法
        innerObject.display();
    }
}

在这个例子中:

  • Outer 是外部类,它包含了一个静态成员变量 outerField 和一个静态方法 outerStaticMethod()。
  • Inner 是静态内部类,使用 static 关键字修饰,可以直接通过外部类的类名访问,即 Outer.Inner。
  • Inner 类有一个私有成员变量 innerField 和一个公共方法 display(),在 display() 方法中可以访问外部类的静态成员变量和静态方法。

在 main 方法中:

  • Outer 是外部类,它包含了一个静态成员变量 outerField 和一个静态方法 outerStaticMethod()。
  • Inner 是静态内部类,使用 static 关键字修饰,可以直接通过外部类的类名访问,即 Outer.Inner。
  • Inner 类有一个私有成员变量 innerField 和一个公共方法 display(),在 display() 方法中可以访问外部类的静态成员变量和静态方法。

这样我们就大致的了解完了Java中的静态内部类了。

4.局部内部类

       局部内部类(Local Inner Class)是定义在方法内部的类,它只在方法内部可见和有效。局部内部类具有以下特点:

  • 只能在方法内部声明,作用范围仅限于所属方法内部。
  • 可以访问所在方法的局部变量,但是这些变量必须声明为 final 或者是事实上的 final 变量(即不能再被赋值的变量)。
  • 可以访问所在类的所有成员,包括私有成员,并且可以访问外部类的所有成员。
  • 不能包含静态成员(包括静态方法、静态变量、静态初始化块)。

(1)局部内部类的大致定义形式:

public class OuterClass {
    private int outerField = 10;
 
    public void outerMethod() {
        final int localVar = 20; // 局部变量,必须为 final 或事实上的 final
 
        // 局部内部类 LocalInnerClass
        class LocalInnerClass {
            public void innerMethod() {
                System.out.println("Accessing local variable: " + localVar);
                System.out.println("Accessing outer field: " + outerField);
                outerMethod(); // 可以访问外部类的方法
            }
        }
    }
}

       以上就是局部内部类的大致定义形式,我们会发现其只能在方法内部声明,作用范围仅限于所属方法内部。并且该内部类在日常生活中基本不会定义与使用。

(2)局部内部类对象的创建

       根据上边的代码,我们现在创建其内部类的实例:

public class OuterClass {
    private int outerField = 10;
 
    public void outerMethod() {
        final int localVar = 20; // 局部变量,必须为 final 或事实上的 final
 
        // 局部内部类 LocalInnerClass
        class LocalInnerClass {
            public void innerMethod() {
                System.out.println("Accessing local variable: " + localVar);
                System.out.println("Accessing outer field: " + outerField);
            }
        }
 
        // 创建局部内部类的实例
        LocalInnerClass innerObject = new LocalInnerClass();
        innerObject.innerMethod();
    }
 
    public static void main(String[] args) {
        OuterClass outerObject = new OuterClass();
        outerObject.outerMethod();
    }
}

       从上边的代码中我们会发现,局部内部类的实例化代码通常直接在包含它的方法内部进行,因为局部内部类的作用范围仅限于所在方法内部。

注意事项:

       1. 局部内部类只能在所定义的方法体内部使用

       2. 不能被public、static等修饰符修饰

       3. 编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字.class

       4. 几乎不会使用

(3)综合案例

       以下是一个简单的例子,演示了如何在Java中使用局部内部类。假设我们有一个外部类 Calculator 表示计算器,其中有一个方法用来计算两个整数的和,同时使用局部内部类来实现一个简单的日志记录功能。

public class Calculator {
    public int add(int a, int b) {
        // 局部内部类 LogRecorder,用于记录日志
        class LogRecorder {
            public void logAddition(int num1, int num2, int result) {
                System.out.println("Adding " + num1 + " and " + num2);
                System.out.println("Result: " + result);
            }
        }
 
        // 执行加法运算
        int result = a + b;
 
        // 创建局部内部类 LogRecorder 的实例
        LogRecorder logger = new LogRecorder();
        // 记录日志
        logger.logAddition(a, b, result);
 
        // 返回加法结果
        return result;
    }
 
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        int sum = calculator.add(5, 3);
        System.out.println("Sum: " + sum);
    }
}

在这个例子中:

  • Calculator 是外部类,包含了一个方法 add(int a, int b) 用于计算两个整数的和。
  • 在 add(int a, int b) 方法内部定义了一个局部内部类 LogRecorder,用于记录加法运算的日志。
  • LogRecorder 类有一个方法 logAddition(int num1, int num2, int result),在这个方法中输出了加法操作的参数和结果。
  • 在 add(int a, int b) 方法中,首先执行加法运算得到结果 result,然后创建了 LogRecorder 类的实例 logger,并调用其方法记录加法的操作日志。
  • main 方法中创建了 Calculator 的实例,并调用 add(int a, int b) 方法进行加法计算,最后输出了计算结果。

这样我们就大致的了解完了Java中的局部内部类了。

5.匿名内部类

       匿名内部类是一种没有显式定义类名的局部内部类,在使用时直接创建它的实例。它通常用于简化代码,特别是在创建实现某个接口或者继承某个类的对象时非常方便。

特点和用法:

  • 没有显式类名: 匿名内部类没有类名,它是在创建对象时定义类的实现或者继承,然后立即实例化。
  • 用途:
  • 实现接口: 可以通过匿名内部类直接实现接口并创建接口的实例对象。
  • 继承类: 可以通过匿名内部类直接继承一个类并实例化子类对象。
  • 语法: 匿名内部类的语法是在创建对象时使用 new 关键字后,跟上一个类或者接口名,并使用一对大括号 {} 包括内部类的具体实现。

(1)匿名内部类的大致定义形式:

interface Greeting {
    void greet();
}
 
public class Main {
    public static void main(String[] args) {
        // 使用匿名内部类创建接口的实例
        Greeting greeting = new Greeting() {
            @Override
            public void greet() {
                System.out.println("Hello, world!");
            }
        };
 
        // 调用接口方法
        greeting.greet();
    }
}

以上就是匿名内部类的大致定义形式,匿名内部类的使用通常是在需要创建某个接口的实例对象或者继承某个类并实现其方法的场景下非常有用。

(2)局部内部类对象的创建

       对于匿名内部类,我们通常不会对其进行实例化,匿名内部类的实例化代码通常是在需要的地方直接使用,并且通常用于一次性的场景。

(3)综合案例

       以下是一个简单的例子,演示了在Java中如何使用匿名内部类。假设我们有一个接口 Animal 表示动物,其中定义了一个抽象方法 makeSound(),我们可以使用匿名内部类来创建 Animal 接口的实例对象并实现其方法。

// 定义一个接口
interface Animal {
    void makeSound();
}
 
public class Main {
    public static void main(String[] args) {
        // 使用匿名内部类创建接口的实例
        Animal dog = new Animal() {
            @Override
            public void makeSound() {
                System.out.println("Dog: Woof!");
            }
        };
 
        // 调用接口方法
        dog.makeSound();
 
        // 使用匿名内部类创建接口的另一个实例
        Animal cat = new Animal() {
            @Override
            public void makeSound() {
                System.out.println("Cat: Meow!");
            }
        };
 
        // 调用接口方法
        cat.makeSound();
    }
}

在这个例子中:

  • Animal 是一个接口,定义了一个抽象方法 makeSound()。
  • 在 main 方法中,通过使用匿名内部类创建了两个 Animal 接口的实例对象:dog 和 cat。
  • 每一个匿名内部类都实现了 makeSound() 方法,分别输出 "Dog: Woof!" 和 "Cat: Meow!"。
  • 调用每个实例对象的 makeSound() 方法来输出相应的声音。

这样我们就大致的了解完了Java中的匿名内部类了。

       这样我们就将Java中所有的内部类学习完了,通过上边的学习,我们知道在Java中,内部类是嵌套在其他类(外部类)中的类,它可以访问其外部类的所有成员,包括私有成员。并且内部类提供了一种逻辑上组织类的方式,可以实现更加复杂和灵活的设计模式。


相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
6月前
|
Java 数据库连接 数据库
Java 相关知识点总结含基础语法进阶技巧及面试重点知识
本文全面总结了Java核心知识点,涵盖基础语法、面向对象、集合框架、并发编程、网络编程及主流框架如Spring生态、MyBatis等,结合JVM原理与性能优化技巧,并通过一个学生信息管理系统的实战案例,帮助你快速掌握Java开发技能,适合Java学习与面试准备。
312 2
Java 相关知识点总结含基础语法进阶技巧及面试重点知识
|
6月前
|
存储 Java 程序员
Java 基础知识点全面梳理包含核心要点及难点解析 Java 基础知识点
本文档系统梳理了Java基础知识点,涵盖核心特性、语法基础、面向对象编程、数组字符串、集合框架、异常处理及应用实例,帮助初学者全面掌握Java入门知识,提升编程实践能力。附示例代码下载链接。
261 1
|
6月前
|
Java 编译器 数据安全/隐私保护
Java 大学期末考试真题与答案 含知识点总结 重难点归纳及题库汇总 Java 期末备考资料
本文汇总了Java大学期末考试相关资料,包含真题与答案、知识点总结、重难点归纳及题库,涵盖Java基础、面向对象编程、异常处理、IO流等内容,并提供完整代码示例与技术方案,助你高效复习备考。
712 3
|
7月前
|
存储 安全 Java
2025 年最新 40 个 Java 基础核心知识点全面梳理一文掌握 Java 基础关键概念
本文系统梳理了Java编程的40个核心知识点,涵盖基础语法、面向对象、集合框架、异常处理、多线程、IO流、反射机制等关键领域。重点包括:JVM运行原理、基本数据类型、封装/继承/多态三大特性、集合类对比(ArrayList vs LinkedList、HashMap vs TreeMap)、异常分类及处理方式、线程创建与同步机制、IO流体系结构以及反射的应用场景。这些基础知识是Java开发的根基,掌握后能为后续框架学习和项目开发奠定坚实基础。文中还提供了代码资源获取方式,方便读者进一步实践学习。
2157 2
|
6月前
|
存储 缓存 安全
Java基础 - 知识点
Java基础知识点涵盖语言特性、面向对象与基本数据类型、缓存池机制、String类特性、参数传递、类型转换、继承、抽象类与接口区别、重写与重载、Object通用方法及关键字使用等核心内容,是掌握Java编程的重要基石。
120 0
|
7月前
|
并行计算 Java API
Java 入门循环结构基础知识点详解
摘要:本文介绍了Java现代循环技术的进阶应用,包括Stream API、响应式编程和模式匹配,展示了如何用Stream API替代传统循环进行声明式集合处理(如过滤、映射和并行计算),以及响应式编程在异步非阻塞场景下的优势。文章还通过电商订单处理系统的案例演示了这些技术的综合应用,并提供了性能优化建议,如合理使用并行处理和避免循环内对象创建。这些现代特性使Java代码更简洁、高效,更适合高并发和I/O密集型场景。
101 1
|
7月前
|
缓存 算法 NoSQL
校招 Java 面试高频常见知识点深度解析与实战案例详细分享
《2025校招Java面试核心指南》总结了Java技术栈的最新考点,涵盖基础语法、并发编程和云原生技术三大维度: 现代Java特性:重点解析Java 17密封类、Record类型及响应式Stream API,通过电商案例演示函数式数据处理 并发革命:对比传统线程池与Java 21虚拟线程,详解Reactor模式在秒杀系统中的应用及背压机制 云原生实践:提供Spring Boot容器化部署方案,分析Spring WebFlux响应式编程和Redis Cluster缓存策略。
201 0
|
6月前
|
缓存 安全 前端开发
Java 核心知识点与实战应用解析
我梳理的这些内容涵盖了 Java 众多核心知识点。包括 final 关键字的作用(修饰类、方法、变量的特性);重载与重写的区别;反射机制的定义、优缺点及项目中的应用(如结合自定义注解处理数据、框架底层实现)。 还涉及 String、StringBuffer、StringBuilder 的差异;常见集合类及线程安全类,ArrayList 与 LinkedList 的区别;HashMap 的实现原理、put 流程、扩容机制,以及 ConcurrentHashMap 的底层实现。 线程相关知识中,创建线程的四种方式,Runnable 与 Callable 的区别,加锁方式(synchronize
130 0
|
7月前
|
存储 设计模式 Java
Java 期末考试不挂科必背基础知识点复习笔记整理
这是一份全面的Java基础知识点复习笔记,涵盖核心特性、数据类型、流程控制、数组、异常处理、JVM原理、多线程、设计模式及Java 8+新特性等内容。结合买飞机票、验证码生成和评委打分等应用实例,助你掌握考试重点,轻松应对Java期末考试,避免挂科!附带代码资源,供深入学习使用。链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)
387 0