Java中的四种内部类

内部类

类的五大成员

  • 属性
  • 方法
  • 构造器
  • 代码块
  • 内部类

基本介绍:

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类,嵌套其他类的类称为外部类。

基本语法

class Outer{	//外部类
	class Inner{	//内部类
	
	}
}
class Other{	//外部其他类

}

内部类的分类

  1. 定义在外部类局部位置上(比如方法内):
    • 局部内部类(有类名)
    • 匿名内部类(没有类名,重点)
  2. 定义在外部类的成员位置上:
    • 成员内部类(没用static修饰)
    • 静态内部类(使用static修饰)

局部内部类的使用

​ 说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
  3. 作用域:仅仅在定义它的方法或代码中。
  4. 局部内部类访问外部类的成员【访问方式:直接访问】
  5. 外部类访问局部内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】
  6. 外部其他类不能访问局部内部类(因为局部内部类地位是一个局部变量)
  7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。
代码实现
public class LocalInnerClass {
    public static void main(String[] args) {
        Outer01 outer01 = new Outer01();
        outer01.m1();
    }
}

class Outer01{  //外部类
    private int n1 = 100;   //私有成员变量
    private void m2(){  //私有方法
        System.out.println("m2方法被调用。");
    }
    public void m1(){   //外部类的方法
        final class Inner01{    //局部内部类
            private int n1 = 800;   //局部内部类与外部类成员变量重名
            public void f1(){   //局部内部类可以直接访问外部类的所有成员,包含私有的
                System.out.println("局部内部类的n1="+n1+" 外部类的n1="+Outer01.this.n1);  //遵循												//就近原则,Outer01.this相当于Outer01实例化对象
                m2();
            }
        }
        Inner01 i1 = new Inner01();
        i1.f1();
    }
}

匿名内部类的使用

  • 本质是类
  • 内部类
  • 该类没有名字
  • 同时还是一个对象

​ 说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名(它的类名是系统内部自动生成的,用户是 看不到的)。

  1. 基于接口实现匿名内部类:

    public class AnonymousInnerClass {
        public static void main(String[] args) {
            Outer02 outer02 = new Outer02();//创建外部类对象
            outer02.method();
        }
    }
    
    /**
     * 基于接口实现匿名内部类
     * Outer02为外部类
     */
    class Outer02{
        private int n1 = 10;
        public void method(){
            /**
             * 1.如果想实现Animal接口,常规方法是定义一个类实现Animal接口,并创建对象
             *  但如果定义的类只使用一次,后面不再使用,就会造成浪费
             * 2.匿名内部类可以省去定义一个新的类,定义如下所示:
             *  tiger的编译类型:Animal,就是接口类型
             *  tiger的运行类型:就是匿名内部类 Outer02$1
             *  底层会分配一个类名为Outer02$1的类实现接口
             * 3.jdk底层在创建匿名内部类时,立即创建了匿名内部类实例,并且把地址传给了tiger
             */
            /*
                class Outer02$1 implements Animal{
                    @Override
                    public void cry(){
                        System.out.println("老虎叫唤...");
                    }
                }
             */
            Animal tiger = new Animal() {
                @Override
                public void cry() {
                    System.out.println("老虎叫唤...");
                }
            };
            tiger.cry();
            System.out.println("tiger对象的运行类型:"+tiger.getClass());
        }
    }
    
    interface Animal{
        void cry();
    }
    

    2.基于类实现匿名内部类:

    public class AnnoymousInnerClass02 {
        public static void main(String[] args) {
            Outer03 outer03 = new Outer03();
            outer03.method();
        }
    }
    
    class Outer03{
        private int n1 = 10;
        public void method(){
            /**
             * P1的编译类型:Person
             * p1的运行类型:匿名内部类 Outer03$1
             * 传递的参数“Jack”传给了Person的构造器
             * 如果基于抽象类的匿名内部类,匿名内部类要实现抽象类的所有抽象方法
             */
            /*
            底层会创建匿名内部类
            class Outer03$1 extends Person{
                    @Override
                    public void test(){
                        System.out.println("重写了Person类的test方法...");
                    }
                }
             */
            Person p1 = new Person("jack"){
                public void test(){
                    System.out.println("重写了Person类的test方法...");
                }
            };
            p1.test();
            System.out.println("p1的运行类型:"+p1.getClass());
        }
    }
    
    class Person{
        public Person(String name){
            System.out.println("调用了Person类的构造器...");
        }
        public void test(){
    
        }
    }
    
匿名内部类的使用细节
  1. 匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征。

    Person p1 = new Person("jack"){
                public void test(){
                    System.out.println("重写了Person类的test方法...");
                }
            };
            new Person("rose"){
                public void test(){
                    System.out.println("重写了Person类的test方法...");
                }
            }.test();
    
  2. 可以直接访问外部类的所有成员,包含私有的。

  3. 不能添加访问修饰符,因为它的地位就是一个局部变量。

  4. 作用域:仅仅在定义它的方法或代码块中

  5. 外部其他类不能访问匿名内部类(因为匿名内部类地位是一个局部变量)

  6. 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。

匿名内部类的案例

1.有一个铃声接口Bell,里面有个ring方法。

2.有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型

3.测试手机类的脑涨功能,通过匿名内部类(对象)作为参考,打印:懒猪起床了

4.再传入另一个匿名内部类(对象),打印:小伙伴上课了

说明:运用了(1)继承(2)多态(3)动态绑定(4)内部类

代码实现:
public class InnerClassExercise02 {
    public static void main(String[] args) {
        Cellphone cellphone = new Cellphone();
        //匿名内部类作为参数传入alarmclock(Bell bell)方法中
        cellphone.alarmclock(new Bell() {	//定义匿名内部类
            @Override
            public void ring() {
                System.out.println("懒猪起床了...");//重写ring()方法
            }
        });
        cellphone.alarmclock(new Bell() {	//定义匿名内部类
            @Override
            public void ring() {
                System.out.println("小伙伴上课了...");//重写ring()方法
            }
        });
    }
}

interface Bell{
    void ring();
}

class Cellphone{
    public void alarmclock(Bell bell){	//传入一个匿名内部类对象
        bell.ring();
    }
}

成员内部类的使用

​ 说明:成员内部类是定义在外部类的成员位置,并且没有static修饰

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
  3. 作用域和外部类的其他成员一样,为整个类体
  4. 成员内部类访问外部类成员【访问方式:直接访问】
  5. 外部类访问成员内部类【访问方式:创建对象,再访问】
  6. 外部其他类访问成员内部类有两种方法
  7. 如果外部类和内部类的成员重名时(如下代码所示)
public class MemberInnerClass01 {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.n1();
        //外部其他类调用成员内部类
        //1.第一种方法:
        Outer04.Inner04 i5 = outer04.new Inner04();
        i5.m1();
        //2.第二种方法:在外部类定义一个方法返回成员内部类对象
        Outer04.Inner04 i6 = outer04.getInstanceInner04();
        i6.m1();
    }
}
class Outer04{
    private int n1 = 10;
    public String name = "jack";
    class Inner04{
        private int n1 = 99;
        public void m1(){
            System.out.println("调用m1方法...");
            System.out.println("外部类属性 name = "+name);
            //外部类与成员内部类成员名字冲突时:
            System.out.println("外部类 n1 = "+Outer04.this.n1);
            System.out.println("成员内部类 n1 = "+n1);
        }
    }
    public void n1(){
        Inner04 i4 = new Inner04();//创建成员内部类对象
        i4.m1();
    }
    public Inner04 getInstanceInner04(){
        return new Inner04();
    }
}

静态内部类的使用

​ 说明:静态内部类是定义在外部类的成员位置,并且有static修饰

  1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
  2. 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员
  3. 作用域:同其他的成员,为整个类体
  4. 静态内部类访问外部类(比如:静态属性)【访问方式:直接访问所有静态成员】
  5. 外部类访问静态内部类【访问方式:创建对象,再访问】
  6. 如果外部类和静态内部类的成员重名时,静态内部类访问的时候,默认遵循就近原则。如果想访问外部类成员,则可以使用(外部类名.成员)
代码实现:
public class StaticInnerClass01 {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.n1();
        //外部其他类调用静态内部类
        //1.第一种方法:
        Outer05.Inner05 i5 = new Outer05.Inner05();
        //2.第二种方法:在外部类定义一个方法返回静态内部类
        Outer05.Inner05 i6 = Outer05.getInner05();
    }
}

class Outer05{
    private static int n1 = 10;
    public static String name = "jack";
    public static class Inner05{
        private static int n1 = 99;
        public void m1() {
            System.out.println("调用m1()方法...");
            //外部类和静态内部类成员重名
            System.out.println("外部类 n1 = "+Outer05.n1);
            System.out.println("静态内部类 n1 = "+n1);
        }
    }

    public void n1(){
        Inner05 inner05 = new Inner05();
        inner05.m1();
    }
    public static Inner05 getInner05(){
        return new Inner05();
    }
}

综合案例

public class test {
    public static void main(String[] args) {
        //并不是10,因为成员变量的初始值不会改变,并且也不是静态成员变量
        Outer06 outer06 = new Outer06();
        Outer06.Inner06 i6 = outer06.new Inner06();
        System.out.println(i6.n);//5
    }
}

class Outer06{
    public Outer06(){
        Inner06 inner06 = new Inner06();
        inner06.n = 10;
        Inner06 i2 = new Inner06();
        System.out.println(i2.n);//5
    }
    class Inner06{
        public int n = 5;
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值