JAVA中的内部类

文章目录

  • 一、实例内部类
    • [1.1 定义](#1.1 定义)
    • [1.2 核心特性](#1.2 核心特性)
    • [1.3 如何创建实例内部类对象?](#1.3 如何创建实例内部类对象?)
    • [1.4 内部类如何访问外部类?](#1.4 内部类如何访问外部类?)
    • [1.5 同名冲突怎么解决?](#1.5 同名冲突怎么解决?)
  • 二、静态内部类
    • [2.1 定义](#2.1 定义)
    • [2.2 核心特点](#2.2 核心特点)
    • [2.3 代码示例](#2.3 代码示例)
    • [2.4 什么时候使用静态内部类?](#2.4 什么时候使用静态内部类?)
  • 三、局部内部类
    • [3.1 定义](#3.1 定义)
    • [3.2 特点](#3.2 特点)
    • [3.3 三种类比较](#3.3 三种类比较)
    • [3.4 补充](#3.4 补充)

一、实例内部类

1.1 定义

直接定义在 类的内部、方法外部 ,并且 没有static修饰 的类,就是实例内部类

java 复制代码
public class Outer {
    //实例内部类
    class Inner {
    }
}

特点一句话:

内部类对象,必须依附一个外部类对象存在。

没有Outer对象,就不可能有Inner对象。

1.2 核心特性

1.内部类持有外部类的引用

实例内部类对象里,会隐式持有一个外部类对象的引用,类似:

java 复制代码
Outer.this

这意味着:

  • 内部类可以直接访问外部类的所有成员,包括private字段和方法
java 复制代码
public class Outer {
    private int outerField = 100;


    //实例内部类
    class Inner {
        private int innerField = 200;

        public void innerMethod() {
            //直接访问外部类私有成员
            System.out.println(outerField);
            //等同于
            System.out.println(Outer.this.outerField);
        }
    }

}

2.外部类不能直接访问内部类成员

外部类想要访问内部类,必须先创建内部类对象

java 复制代码
public class Outer {
    public int date1 = 1;
    //实例内部类
    class Inner {
        public int innerDate = 2;
    }
    
    public void test() {
        //System.out.println(innerDate); //不允许的,需要创建内部类对象
        
        Inner inner = new Inner();
        System.out.println(inner.innerDate);
    }
}

3.不能定义静态成员(static变量/方法)

实例内部类不能有static变量,static方法、static代码块。

因为它依赖外部实例,而static属于类,不依赖实例,两者矛盾

  1. 访问权限

内部类可以用

  • public
  • protected
  • default(包私有)
  • private

private 内部类只能在外部类内部使用。

1.3 如何创建实例内部类对象?

  1. 在外部类内部创建(简单)
java 复制代码
public class Outer {
    void createInner() {
        Inner inner = new Inner();
    }

    class Inner {}
}
  1. 在外部类之外创建(必须先有外部对象)

语法格式:

java 复制代码
Outer outer = new Outer(); //首先得有外部对象
Outer.Inner inner = outer.new Inner(); //然后才用点的方式创建实例内部类对象

完整示例:

java 复制代码
public class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();

        inner.innerMethod();
    }
}

必须先new Outer(),才能new Inner()

这就是"依附"关系

1.4 内部类如何访问外部类?

内部类可以直接访问外部类所有成员,包括 private。

原理:

编译器会自动给内部类加一个 "隐藏字段":

java 复制代码
final Outer this$0;

构造 Inner 时,自动把外部对象传进去。

你写的:

java 复制代码
innerMethod() {
    System.out.println(outerField);
}

编译器实际编译成:

java 复制代码
innerMethod() {
    System.out.println(Outer.this.outerField);
}

1.5 同名冲突怎么解决?

如果内部类和外部类有同名成员:

java 复制代码
class Outer {
    int a = 10;

    class Inner {
        int a = 20;

        void test() {
            System.out.println(a);        // 20(内部类自己)
            System.out.println(this.a);   // 20
            System.out.println(Outer.this.a); // 10(外部类)
        }
    }
}

规则:


二、静态内部类

2.1 定义

静态内部类 = 写在别的类里面的普通类,跟外部类只有"包级"关系,不依附外部对象。

用static修饰的成员内部类,就叫静态内部类。

java 复制代码
public class Outer {
    //静态内部类 
    static class Inner{
    }
}

相比于实例内部类:

  • 实例内部类(非static):必须寄生在外部对象上
  • 静态内部类(static):完全独立,不需要外部对象

2.2 核心特点

1.不持有外部类对象引用

这是和实例内部类最大的区别:

  • 实例内部类 -> 有outer.this
  • 静态内部类 -> 没有外部引用

2.可以直接new,不需要先new外部类

java 复制代码
public class Test {
    public static void main(String[] args) {
        //静态内部类创建方式
        Outer.Inner inner = new Outer.Inner();
    }
}

相比实例内部类:

java 复制代码
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

3.只能访问外部类的静态成员

静态内部类里:

  • 能访问:外部类的static变量,static方法
  • 不能直接访问:外部类的普通成员变量、成员方法
  • 如果想要访问外部类普通成员变量和方法,可以先实例外部类对象,通过外部类对象进行调用
java 复制代码
class Outer {
    private static int a = 10;
    private int b = 20;

    static class Inner {
        void test() {
            System.out.println(a);  // ✅ 可以
            System.out.println(b);  // ❌ 报错!不能访问外部实例成员
        }
    }
}

== 4.可以有自己的静态成员==

实例内部类不能有 static,

但静态内部类可以有 static 变量、static 方法。

java 复制代码
class Outer {
    static class Inner {
        static int x = 100;   // ✅ 允许
        static void test() {} // ✅ 允许
    }
}

2.3 代码示例

java 复制代码
public class Outer {
    private static String outerStatic = "外部静态变量";
    private String outerField = "外部实例变量";

    // 静态内部类
    public static class Inner {
        public void say() {
            // 只能访问外部静态成员
            System.out.println(outerStatic);

            // 下面这句会报错
            // System.out.println(outerField);
        }
    }
}

使用:

java 复制代码
public class Test {
    public static void main(String[] args) {
        // 直接创建
        Outer.Inner inner = new Outer.Inner();
        inner.say();
    }
}

2.4 什么时候使用静态内部类?

最常见的场景:

  1. 某个类只在外部类内部使用,但又不想和外部实例绑定
  2. 作为数据载体(比如 Builder 模式)
java 复制代码
Student.builder()
       .name("张三")
       .age(18)
       .build();

这里的 Builder 几乎都是静态内部类。

  1. 存放常量、工具方法
  2. 不想单独创建一个 .java 文件,但又需要一个独立类

也就是:

静态内部类就是一个 "住在外部类里面" 的独立类,不依赖外部对象,不持有外部引用,用法跟普通类几乎一样,只是名字要带外部类.


三、局部内部类

3.1 定义

定义在方法里,代码块里、构造方法里的类,就叫局部内部类。

它就像方法里的局部变量,只在这个方法内部有效,外面根本看不见、用不了。

java 复制代码
public class Outer {

    public void test() {
        // 👇 这就是局部内部类(写在方法里)
        class LocalInner {
            public void say() {
                System.out.println("我是局部内部类");
            }
        }

        // 只能在方法内部创建对象
        LocalInner inner = new LocalInner();
        inner.say();
    }
	 public void test2() {
        //LocalInner inner = new LocalInner(); //错误,无法识别到这个局部内部类
    }
}

特点:

  • 只在当前方法里有效
  • 外面不能访问,连外部类其他方法都访问不到
  • 像局部变量一样,是 "临时的类"

3.2 特点

1.作用域极小

只在当前方法 / 代码块内部有效。

出了这个大括号 {},就不存在了。

2.不能加访问修饰符

局部内部类不能写 public、private、protected、static

因为它本来就是局部的,修饰它没有意义。

java 复制代码
public void test() {
    // 错误写法
    public class LocalInner {}

    // 正确写法
    class LocalInner {}
}

3.可以访问外部类所有成员

包括 private 的变量和方法。

java 复制代码
public class Outer {
    private int a = 100;

    public void test() {
        class LocalInner {
            public void say() {
                // 可以直接访问外部类私有成员
                System.out.println(a);
            }
        }
    }
}

4.可以访问方法里的局部变量,但必须是 effectively final

JDK 8 以前必须加 final

JDK 8 以后不用写 final,但不能修改,否则报错。

java 复制代码
public void test() {
    int num = 200;  // 相当于 final

    class LocalInner {
        public void say() {
            System.out.println(num);  // 可以访问
            // num = 300;  ❌ 报错!不能修改
        }
    }
}

原因:

局部变量在栈上,方法结束就销毁;

内部类对象在堆上,可能活得更久。

为了安全,Java 强制它不能变。

  1. 局部内部类里可以定义成员
  • 成员变量
  • 成员方法
  • 甚至再写局部类(没人这么干)

但不能写 static 成员(除了 static final 常量)。

java 复制代码
class Outer {
    private int outerA = 10;

    public void method() {
        final int localNum = 20;  // 局部变量

        // 局部内部类
        class LocalInner {
            private int innerA = 30;

            public void test() {
                // 访问外部类成员
                System.out.println(outerA);
                // 访问方法局部变量
                System.out.println(localNum);
                // 访问自己成员
                System.out.println(innerA);
            }
        }

        // 只能在这里创建
        LocalInner inner = new LocalInner();
        inner.test();
    }
}

3.3 三种类比较

3.4 补充

为什么 a = 200; 不能直接写在类里?

java 复制代码
public class Outer {
    private static int a = 10;
    private int b = 20;

    a = 200; // 这里报错!
}

根本原因:

类 = 定义的地方

方法 / 代码块 = 执行代码的地方

赋值语句 a=200 是执行语句,必须放在方法或代码块里,不能裸写在类中。

Java 类体中,只能写 "定义",不能直接写 "执行语句"

类里面合法的内容只有:

  • 成员变量(定义)
  • 方法
  • 构造器
  • 代码块
  • 内部类

不能直接写赋值语句、打印语句这种执行代码!

那怎么修改 a 的值?

有 3 种正确写法,任选一种:

方法 1:在方法里修改(最常用)

java 复制代码
public class Outer {
    private static int a = 10;
    private int b = 20;

    // 写在方法里 ✅
    public void change() {
        a = 200; 
    }
}

方法 2:在静态代码块里修改

java 复制代码
public class Outer {
    private static int a = 10;
    private int b = 20;

    // 静态代码块 ✅
    static {
        a = 200;
    }
}

方法 3:直接定义时赋值

java 复制代码
private static int a = 200;

所以:

  1. 类中不能直接写执行语句(赋值、打印等)
  2. 变量修改必须放在方法或代码块内
  3. static 变量可以在静态代码块 / 静态方法里修改
相关推荐
深蓝轨迹2 小时前
黑马点评--达人探店模块
java·spring boot·redis
always_TT2 小时前
C语言中的布尔值:_Bool与stdbool.h
c语言·开发语言
!停2 小时前
C++入门基础—类和对象3
java·数据库·c++
寂静or沉默2 小时前
Java程序员技术面试:如何清晰描述项目难点?逻辑模板!Java的原因与解决方案最新发布!
java·开发语言·面试
Z.风止2 小时前
Large Model-learning(1)
开发语言·笔记·git·python·学习
Sgf2273 小时前
第15章 网络编程
开发语言·网络·php
东离与糖宝3 小时前
Gradle 9.4+Java26:大型项目构建提速100倍实战配置
java·人工智能
Ares-Wang3 小时前
Python》》FastAPI 异步框架 接口 pymysql【同步】 aiomysql【异步】
开发语言·python·fastapi
想进大厂的小徐3 小时前
maven的子模块和子pom的区别
java·maven