Java 基础教程

内部类(Inner Class)

什么是内部类?

在 Java 中,大部分时候,我们把类定义成一个独立的程序单元。但在某些情况下,我们把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类(有的地方也叫嵌套类),包含内部类的类也被称为外部类(有的地方也叫宿主类)。

注意:Java 从 JDK 1.1 开始变引入了内部类支持。

示例:在 Compare 类的内部定义一个 InnerClass 类,此时,InnerClass 被称为内部类,Compare 被称为外部类,代码如下:

public class Compare {
   // 外部类的成员变量
   private boolean ignoreCase = false;

   // 【重点】定义一个内部类
   private class InnerClass {
       public boolean compare(String str1, String str2) {
           // 引用外部类的成员
           if(ignoreCase) {
               return str1.equalsIgnoreCase(str2);
           }
           return str1.equals(str2);
       }
   }

   public static void main(String[] args) {
       Compare compare = new Compare();
       // 【重点】实例化内部类
       InnerClass innerClass = compare.new InnerClass();

       // 调用内部类的方法
       // 不忽略大小写比较
       System.out.println(innerClass.compare("hello", "Hello")); // false

       // 忽略大小写比较
       compare.ignoreCase = true;
       System.out.println(innerClass.compare("hello", "Hello")); // true
   }
}

内部类的作用

Java 的内部类主要有如下作用:

(1)内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该内部类。假设需要创建 Car 类,Car 类需要组合一个 Engine 对象,Engine 类只有在 Car 类里才有效,离开了 Car 类之后没有任何意义。在这种情况下,就可把 Engine 定义成 Car 的内部类,不允许其他类访问 Engine。

(2)内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。

(3)匿名内部类适合用于创建那些仅需要一次使用的类,特别是在事件监听、回调中使用匿名内部类,如使用 java.util.Collections 类的 sort(List<T> list, Comparator<? super T> c) 方法对 List 列表进行排序,第二个参数接收一个类,用来实现排序,通常情况下我们通过匿名内部类来实现,例如:

List<String> list = new ArrayList<>();
list.add("Helen");
list.add("Bill");
list.add("Tom");

Collections.sort(list, /* 我是一个内部类 */ new Comparator<String>() {
   @Override
   public int compare(String o1, String o2) {
       return o1.compareTo(o2);
   }
});

注意:上面代码中不理解的地方后续章节将详细展开,这里重点了解匿名内部类的作用。

内部类分类

Java 中内部类分为成员内部类、静态内部类、方法内部类和匿名内部类。

成员内部类(Member Inner Class)

成员内部类是定义在另一个类内部的普通类。成员内部类可以访问外部类的成员变量和方法,包括私有成员。它还可以使用外部类的引用来访问外部类的实例。

成员内部类语法如下:

// 外部类
public class OuterClass {

   // 定义内部类
   private class InnerClass {
       // 内部类的成员...
       // 内部类的方法...    
   }

}

上面代码中,OuterClass 是外部类,InnerClass 是内部类,内部类创建的语法和外部类一样,也包含修饰符、class 关键字、类名、extends、implements 关键字等。

实例化成员内部类方式如下:

// 方式一:
Compare compare = new Compare();
InnerClass innerClass1 = compare.new InnerClass();

// 方式二:
InnerClass innerClass2 = new Compare().new InnerClass();

注意:成员内部类的访问权限和普通成员一样,private 只能在本类中访问,protected 在子类中能访问,public 所有类均可访问,默认包访问权限则只能在包内访问。

静态内部类(Static Inner Class)

静态内部类是定义在另一个类内部的静态类。静态内部类与外部类的实例无关,可以直接访问外部类的静态成员,但不能访问外部类的非静态成员。

静态内部类语法如下:

// 外部类
public class OuterClass {

   // 定义内部类
   private static class InnerClass {
       // 内部类的成员...
       // 内部类的方法...    
   }

}

实例化静态内部类方式如下:

InnerClass innerClass = new InnerClass();

方法内部类(Method Local Inner Class)

方法内部类是定义在方法内部的类。方法内部类只能在方法内部被访问,它可以访问外部类的成员变量和方法,但只能访问方法中的 final 变量。

方法内部类语法如下:

// 外部类
public class OuterClass {

   public void demo(){
       // 定义内部类
       private static class InnerClass {
           // 内部类的成员...
           // 内部类的方法...    
       }
       
       // 实例化内部类
       InnerClass innerClass = new InnerClass();
   }

   // 外面不允许访问 InnerClass 内部类
}

匿名内部类(Anonymous Inner Class)

匿名内部类是没有名字的内部类,用于创建一个实现某个接口或继承某个类的临时对象。匿名内部类通常用于简化代码,将实现逻辑直接定义在使用的地方,并且可以访问外部类的成员变量和方法。

匿名内部类语法如下:

// 外部类
public class OuterClass {

   // 方法参数接收了一个匿名内部类
   public void demo(new InnerClass(){
   
   }){
       // ...
   }

}

内部类与this

内部类与 this 关键字有一些特殊的关系。当内部类引用外部类的实例时,可以使用 this 关键字来引用外部类的实例。在内部类中,this 关键字表示内部类的实例,而外部类的实例可以使用 “外部类名.this” 来引用。

例如,考虑以下代码:

public class OuterClass {
   private int x = 10;
   
   public class InnerClass {
       private int y = 5;
       
       public void printValues() {
           System.out.println("Outer x: " + OuterClass.this.x);
           System.out.println("Inner y: " + this.y);
       }
   }
   
   public void createInnerClass() {
       InnerClass inner = new InnerClass();
       inner.printValues();
   }
}

在上面的例子中,OuterClass 是外部类,InnerClass 是内部类。在 InnerClass 的 printValues 方法中,我们使用 OuterClass.this.x 来引用外部类的 x 变量,使用 this.y 来引用内部类的 y 变量。

在 createInnerClass 方法中,我们创建了 InnerClass 的实例 inner,并调用它的 printValues 方法。在 printValues 方法中,使用 this 关键字来引用内部类的实例。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号