Java中的内部类了解一下

本文深入解析Java内部类的四种类型:成员内部类、局部(方法)内部类、静态内部类和匿名内部类。探讨每种内部类的特点、使用场景及限制,通过代码示例展示如何在实际编程中应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 什么是内部类?

        Java 类中不仅可以定义变量和方法,还可以定义类,在类内部定义的类就被称为内部类。根据定义的方式不同,可以将内部类分为四种:

  • 成员内部类
  • 局部(方法)内部类
  • 静态内部类
  • 匿名内部类

2. 为什么要使用内部类?

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

        使用内部类的优势:

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

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

3. 如何使用内部类?

在这里插入图片描述
说明:

  • 非静态内部类不能拥有 静态变量、静态代码块、静态方法(暂无法解释)
  • 静态内部类无需外部类实例即可调用
  • 非静态内部类需要外部类实例调用

3.1 成员内部类

3.1.1 什么是成员内部类?

定义在类内部的非静态类,就是成员内部类。

成员内部类的实例化过程:

  1. 首先生成外部类的实例对象
  2. 然后生成绑定到外部类实例对象的成员内部类实例对象

成员内部类实例对象的生成是依赖于外部类实例对象

【注意】:成员内部类不能定义静态方法和变量(IDEA中直接报错),但可以定义static final/final 的变量(常量)。

        至于成员内部类为什么不能定义静态方法和变量这个问题,我暂无法解释(网上的答案五花八门,暂还没有找到能够说服我的理由的资料),以后有机会的话再来补坑。

3.1.2 如何使用成员内部类?

demo:

public class OuterClass {

    private void doSomething() {
        System.out.println("OuterClass doSomething ...");
    }

    public class InnerClass {

        public void doSomething() {
            OuterClass.this.doSomething();
            System.out.println("InnerClass doSomething ...");
        }
    }

    public static void main(String[] args) {
    	// 在外部类中访问内部类
        InnerClass innerClass = new InnerClass();
        innerClass.doSomething();
    }
}
public class Test {
    public static void main(String[] args) {
    	// 在其他类中访问内部类
        OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
        innerClass.doSomething();
		
		// 这种形式也行
		//OuterClass outerClass = new OuterClass();
        //OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        //innerClass.doSomething();
    }
}

3.1.3 小结

1)、成员内部类可以是任意修饰符(当为private修饰时,不能直接在其他类中实例化)
2)、在其他类(不是外部类)中访问成员内部类时,必须要是这种形式:外部类.成员内部类
3)、成员内部类可以随意的访问外部类的成员变量/方法,且成员变量名/方法名可以同名,但如果这样的话,要想访问外部类的成员变量/方法,必须是这种形式:外部类.this.变量名/方法名

3.2 局部(方法)内部类

3.2.1 什么是局部内部类?

定义在方法中的类,就是局部类。如果一个类只在某个方法中使用,则可以考虑使用局部类。

3.2.2 如何使用局部内部类?

public class OuterClass {

    private void doSomething() {
        System.out.println("OuterClass doSomething ...");
    }

    public void test() {
        int i = 1;

        class InnerClass {
            private void doSomething() {
                OuterClass.this.doSomething();
                System.out.println("i = " + i);
                System.out.println("InnerClass doSomething ...");
            }
        }

        InnerClass innerClass = new InnerClass();
        innerClass.doSomething();
    }


    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        outerClass.test();
    }
}

3.2.3 小结

1)、类前不能有访问修饰符
2)、仅在此方法内使用
3)、无法创造静态信息
4)、可以随意的访问外部类的任何信息
5)、可以直接访问方法内的局部变量和参数(有限制)

3.2.4 局部内部类访问局部变量的限制

变量名从内部类中访问,需要final或有效的final
具体限制如下:

  1. 直接被final修饰的变量
  2. 已被赋值且始终未改变的变量(有且仅有赋值一次),引用指向不能改变。JDK8以前(不包括8)只能访问被final修饰的变量

如:修改变量i的值
在这里插入图片描述

3.3 静态内部类

3.3.1 什么是静态内部类?

定义在类内部的静态类,就是静态内部类。

3.3.2 如何使用静态内部类?

public class OuterClass {
	private static int i = 1;
    private int j = 1;

    public static void doSomething() {
        System.out.println("OuterClass doSomething ...");
    }

    public static class InnerClass {
        private static int i = 100;
        private int j = 100;

        public static void doSomething() {
            OuterClass.doSomething();
            System.out.println("InnerClass doSomething ...");
            System.out.println(OuterClass.i);
        }
        
        public void test()  {
            System.out.println("InnerClass test ...");
        }
    }
}
public class Test {

    public static void main(String[] args) {
        // 1.通过静态内部类名直接访问它的静态方法
        OuterClass.InnerClass.doSomething();

        // 2.实例化静态内部类,并访问它的实例方法
        OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
        innerClass.test();
    }
}

3.3.3 小结

1)、静态内部类中可以包含任意的信息(static/非static)
2)、静态内部类只能直接访问外部类的所有的static的成员变量及方法
3)、用 外部类.内部类 引用=new 外部类.内部类(); 然后利用 引用.成员信息(属性、方法)调用
4)、访问内部类的静态信息,直接外部类.内部类.静态信息就可以了
5)、静态内部类可以独立存在,不依赖于其他外围类

3.4 匿名内部类

3.4.1 什么是匿名内部类?

说简单点:就是没有名字的内部类

        匿名内部类必须要继承一个父类或者实现一个接口,同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。

3.4.3 如何使用匿名内部类?

demo1:

public interface IAnimal {
    void bark();
}
public class OuterClass {

    public IAnimal getInnerInstance(String s) {
        return new IAnimal() {
            @Override
            public void bark() {
                System.out.println(s);
            }
        };
    }

    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        IAnimal iAnimal = outerClass.getInnerInstance("汪汪汪...");
        iAnimal.bark();
    }
}

demo2:把匿名内部类作为方法的参数

public abstract class User {
    private String name;

    public abstract int run();

    public String getName() {
        return name;
    }
}
public class OuterClass {

    public void test(User user) {
        System.out.println(user.getName() + "能够一口气跑 " + user.run() + "米");
    }

    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();

        outerClass.test(new User() {
            @Override
            public int run() {
                return 500;
            }

            @Override
            public String getName() {
                return "zzc";
            }
        });
    }
}

        调用test()方法时,要传入一个User对象。但是由于User是一个接口,无法创建对象,所以要实现该接口。因此此处采用匿名内部类的方式进行,并实现接口中全部的抽象方法。

【参考资料】
浅谈Java内部类(超详细代码示例)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值