java中的内部类【详细】

About Me

欢迎各位读者访问,大家一起学习。

优秀是一种习惯♡♡♡

做更好的自己!

本人见识有限,写到博客难免有错误或疏忽的地方,还望各位大佬多多指点,在此表示感激不尽。♡♡♡


一:了解内部类

内部类:就是一个类中定义一个类,也就是在A类的内部定义一个B类,B类就称为内部类。如同一个人是由大脑,肢体,器官等组合而成,而内部类就相当于某个器官之一,例如心脏,心脏有属性和方法(血液 、跳动)所以就得用一个类来表示,而心脏又在人体当中,所以内部类在外部类中。

image-20211115194734360

二:内部类分类

1. 成员内部类

成员内部类是是最普通的内部类,定义位于一个类的内部。

1.1 格式:

外部类名.内部类名 对象名 = new 外部类对象().new 内部类对象();

外部类名:是为什么标明生成的内部类对象在哪个外部类当中。

/**
 * @author Tornado
 * @date 2021/11/14 21:24
 */
public class Test {
    public static void main(String[] args) {
        //创建内部类对象
        Out.In oi = new Out().new In();
        oi.method();

    }
}

//外部类
class Out {
    private int age = 10;

    //内部类
    class In {
        //定义一个method()方法
        public void method() {
            //内部类可以访问外部类的成员变量,私有的也可以。
            System.out.println(age);
        }
    }
}

1.2 思考?

  • 上面这个内部类严重破坏了良好的代码结构,为什么还要使用内部类呢?
使用内部类这种技术,可以隐藏细节和内部结构,封装性更好,内部类可以随意访问外部类的成员变量,外部类的私有成员变量,内部类也可以访问。而不用生成外部类对象,这也就是内部类的优点。就如同心脏可以直接访问身体的血液,而不用医生抽血。

1.3 变量如何访问?

/**
 * @author Tornado
 * @date 2021/11/14 21:24
 */
public class Test {
    public static void main(String[] args) {
        //创建内部类对象
        Out.In oi = new Out().new In();
        //调用method()方法
        oi.method();
    }
}

//外部类
class Out {
    private int age = 30;

    //内部类
    class In {
        private int age = 20;

        //定义一个method()方法
        public void method() {
            int age = 10;
            System.out.println("局部变量:" + age);
            System.out.println("内部类变量:" + this.age);
            System.out.println("外部类变量:" + Out.this.age);
        }
    }
}
  • 运行结果

内部类在没有同名的局部变量和成员变量的情况下,内部类会直接访问外部类的成员变量。

局部变量:10
内部类变量:20
外部类变量:30

2. 局部内部类

局部内部类就是在一个外部类的方法中写内部类。也就是把内部类写到了外部类的成员方法中。它和成员内部类的区别就在于访问仅限于方法内或该作用域内。注意:局部内部类中就像是一个方法中定义了一个局部变量一样,是不能有public ,private ,static,protected权限修饰符的。

/**
 * @author Tornado
 * @date 2021/11/14 21:24
 */
public class Test {
    public static void main(String[] args) {
        //创建外部类对象
        Out out = new Out();
        //调用成员方法method()
        out.method();
    }
}

//外部类
class Out {
    private int age = 30;

    public void method() {
        //局部内部类不能写权限修饰符修饰类
        class In {
            private int age = 20;

            //定义一个method()方法
            public void method() {
                System.out.println("内部类的方法");
            }
        }
        //创建局部内部类对象
        In in = new In();
        //调用method()方法
        in.method(); //内部类方法
    }
}

2.1 思考?

如何将局部内部类的对象抛到外界使用?

/**
 * @author Tornado
 * @date 2021/11/15 18:48
 */
public class Test {
    public static void main(String[] args) {
        //如何把Inner扔到这里用

    }
}
class Outer{
    //成员方法
    public void show(){
        class Inner{
            public void method(){
                System.out.println("内部类的method方法");
            }
        }
        Inner inner = new Inner();
        inner.method();
    }
}

根据上面程序可以看出成员内部类不能直接使用Inner对象,而是要通过外部类调用成员方法show()才可以用,那有什么办法可以在外界使用Inner对象呢???看下面这个程序

/**
 * @author Tornado
 * @date 2021/11/15 18:48
 */
public class Test {
    public static void main(String[] args) {
        //如何把Inner扔到这里用
        //创建外部类Outer对象
        Outer outer = new Outer();
        //调用show()方法,返回的值就是Inner对象
        Face inner = outer.show();
        System.out.println(inner);//com.ljf666.test15.Outer$1Inner@36d64342
        inner.method();//内部类的method方法
    }
}
class Outer{
    //成员方法【返回值:Face】
    public Face show(){
        //内部类实现接口
        class Inner implements Face{
            //重写接口中的method()方法
            public void method(){
                System.out.println("内部类的method方法");
            }
        }
        //创建Inner对象
        Inner inner = new Inner();
        //返回inner
        return inner;
    }
}
//定义一个接口Face
interface Face{
    //定义一个抽象方法method()
    void method();
}

既然局部内部类无法直接使用内部类对象,我们可以通过外界定义一个接口,并让内部类实现这个接口,然后将外部类的成员方法变为带有返回值的,返回值为inner对象,然后内部return返回inner对象,外界就可以通过调用方法而调用到inner对象。即可在外界调用到method()方法。

3. 静态内部类

静态内部类也是在一个类的内部定义了一个类,只不过是在类的前面加上了static关键字,静态内部类是不需要外部类的,和类的静态成员变量有点类似,静态内部类不能使用外部类中的非static修饰的成员。

/**
 * @author Tornado
 * @date 2021/11/15 19:18
 */
public class Test {
    public static void main(String[] args) {
        //创建静态内部类的对象
        Outer.Inner oi = new Outer.Inner();
        //调用内部类中的方法
        oi.methodInner();   //静态内部类的方法10
    }
}
class Outer{
    //定义一个成员方法
    public void method(){
        System.out.println("外部类的成员方法");
    }
    //定义一个静态成员变量
    static int a = 10;
    //定义一个静态内部类
    static class Inner{
        public void methodInner(){
            //method(); 编译报错,静态的无法使用非静态的。
            System.out.println("静态内部类的方法"+a);
        }
    }
}

4. 匿名内部类

4.1:本质

匿名内部类本质上是一个特殊的局部内部类,在一个接口,将继承\实现,方法重写,创建对象,放到了一步进行。匿名内部类是用的最多的

4.2:格式

new 类名 \ 接口名(){
	重写方法
}

4.3:实例

4.3.1:格式一
/**
 * @author Tornado
 * @date 2021/11/15 0:49
 */
public class Test01 {
    public static void main(String[] args) {
        //使用匿名内部类的方式创建对象
        A a = new A() {
            @Override
            public void method() {
                System.out.println("这是使用匿名内部类的方式实现的!!!");
            }
        };
        //调用method()方法
        a.method();
    }
}
//定义一个接口A
interface A {
    //定义一个方法method()
    void method();
}
4.3.2:格式二
/**
 * @author Tornado
 * @date 2021/11/15 0:49
 */
public class Test01 {
    public static void main(String[] args) {
        //使用匿名内部类【格式二】
        new A() {
            @Override
            public void method() {
                System.out.println("这是使用匿名内部类的方式实现的!!!");
            }
            //调用method()方法
        }.method();

    }
}

//定义一个接口A
interface A {
    //定义一个方法method()
    void method();
}

4.4: 开发中的使用

当一个接口中只有一个抽象方法的时候,就可以使用匿名内部类font>的方式比较合适,因为这样比较方便,少建java文件,少些class类。但是当一个接口中有多个抽象方法的时候,就不如新建一个java文件,实现这个接口。

/**
 * @author Tornado
 * @date 2021/11/15 10:02
 */
public class TestSwimming {
    public static void main(String[] args) {
        //调用方法并使用匿名内部类的方式传入一个参数列表
        goSwimming(new Swimming() {
            //重写接口中的swim()方法
            @Override
            public void swim() {
                System.out.println("我们一起游泳吧!!!");
            }
        });
    }

    //定义一个static方法goSwimming:【返回值:void  方法名:goSwimming  参数列表:Swimming swmming】
    public static void goSwimming(Swimming swimming) {
        //调用匿名内部类重写后swim()方法
        swimming.swim();
    }
}

//定义一个接口Swimming
interface Swimming {
    //抽象方法swim();
    void swim();
}

三:深入理解内部类

1. 为什么成员内部类可以无条件访问外部类?

成员内部类可以无条件的访问外部类,我们可以从反编译字节码上看。

1.1 代码

public class Test {
    public static void main(String[] args) {
        //创建静态内部类的对象
        Outer.Inner oi = new Outer.Inner();
        //调用内部类中的方法
        oi.methodInner();   //静态内部类的方法10
    }
}
class Outer{
    //定义一;个成员方法
    public void method(){
        System.out.println("外部类的成员方法");
    }
    //定义一个静态成员变量
    static int a = 10;
    //定义一个静态内部类
    static class Inner{
        public void methodInner(){
            //method(); 编译报错,静态的无法使用非静态的。
            System.out.println("静态内部类的方法"+a);
        }
    }
}

1.2 编译后的.class文件

image-20211115193254483

编译器会默认为成员内部类添加一个指向外部类对象的引用

2. 静态内部类有特殊的地方吗?

静态内部类是不依赖外部类的,也就是说可以在不创建外部类的情况下,创建内部类对象。

四:内部类的使用场景

1. 场景和好处

  • 方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
  • 每个内部类都能独立继承一个接口的实现。内部类的存在使得java的多继承机制变的完善。
  • 方便编写事件驱动程序
  • 方便编写线程代码

                                                      不要在最能吃苦的年纪选择了安逸!!!        — Tornado♥

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值