内部类回顾

阅读说明

如有任何疑问或者错误,可以博文私信作者,或添加微信 YY20203_24 备注 文章错误

抛出问题

常见的面试问法
内部类有哪些?具体适用场景?
内部类导致的泄漏?为什么泄漏?如何解决?
静态内部类的单例编写?匿名内部类中使用到的参数为什么必须是 final ?

自己想到的知识点
一般内部类(仅在当前类内使用的类)、匿名内部类(不需要使用类名或者引用的)、静态内部类(不需要使用外部类的成员及方法的)、局部内部类(一时不知道如何解答使用场景)
外部类持有内部类的引用,导致内存无法释放的泄漏,解决方法是使用静态内部类或者弱引用
单例模式的写法,为什么使用final修饰?
一时能想到的点,肯定不全面或者get不到面试官想要你说出的点,下面我们再来学习一遍

基础介绍

相关概念

成员内部类(一般内部类):定义在类内部的普通类
静态内部类:使用static修饰的内部类
局部内部类:代码块或者方法中创建的类,区别于成员内部类(只在方法或者代码块局部有效,范围区别)
匿名内部类:只创建一个类对象(不需要命名)的内部类

基本使用

public class OutClass {
    private int i = 1;
    private int i2 = 1;
    public static String str = "outclass";

    class InnerClass {
        // 成员内部类
        private int i = 2;

        public void innerMethod() {
            int i = 3;
        }
    }}
       //先创建外部类对象
        OutClass outClass = new OutClass();
        //创建内部类对象
        OutClass.InnerClass in = outClass.new InnerClass();
        //内部类对象调用自己的方法
        in.innerMethod();

细节:
1、成员内部类的创建必须使用外部类的实例进行创建
2、内部类有参数为外部类对象的构造方法,即对应内部类持有外部类的引用(见下图)
image.png
3、成员内部类不能创建静态变量/方法,原因静态变量、静态方法是与类绑定的,无需创建即可使用,而成员内部类必须由外部类实例创建

public class Outclass {

    private String name;
    private int age;

    public static class InnerStaticClass {

        private String name;

        public String getName() {
            return name;
        }

        public int getAge() {
            return new Outclass().age;
        }
    }
}
        Outclass3.InnerStaticClass  innerStaticClass= new Outclass3.InnerStaticClass();
        innerStaticClass.getAge();
        innerStaticClass.getName();

细节:
1、与外部类的使用基本一致
2、变量、方法只能使用对应的静态方法和变量(内部类使用外部类的,外部类使用内部类的)

public class OutClass4 {
    private String className = "OutClass";

    {
        class PartClassOne { // 局部内部类
            private void method() {
                System.out.println("PartClassOne " + className);
            }
        }
        new PartClassOne().method();
    }

    public void testMethod() {
        class PartClassTwo { // 局部类内部类
            private void method() {
                System.out.println("PartClassTwo " + className);
            }
        }
        new PartClassTwo().method();
    }}
        OutClass4 outClass3 = new OutClass4();
        outClass3.testMethod();

细节:
1、无法外部创建
2、和成员内部类一样,局部内部类有参数为外部类对象的构造方法,即对应内部类持有外部类的引用
3、和成员内部类一样,局部内部类不能创建静态变量/方法,有外部引用,无法独立存在
4、可理解为作用域很小的成员内部类

public class OutClass5 {
    private OnClickListener mClickListener;
    private OutClass5 mOutClass5;

    interface OnClickListener {
        void onClick();
    }

    public OutClass5 setClickListener(final OnClickListener clickListener) {
        mClickListener = clickListener;
        return this;
    }

    public OutClass5 setOutClass5(final OutClass5 outClass5) {
        mOutClass5 = outClass5;
        return this;
    }

    public void setClickInfo(final String info, int type) {
        setClickListener(new OnClickListener() {
            @Override
            public void onClick() {
                System.out.println("click " + info);
            }
        });

        setClickListener(new OnClickListener() {
            @Override
            public void onClick() {
                System.out.println("click2 " + info);
            }
        });
    }
}

button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
    }});

细节:
1、和普通类的的构造函数不同,后面多了{},且没有构造参数,构造函数名一般为接口或者父类
2、{}内实现接口或者抽象类的方法
3、匿名内部类有参数为外部类对象的构造方法,即对应内部类持有外部类的引用

使用场景

成员内部类:当做类的成员使用且对其他类隐藏时使用,比如Android某个页面的适配器可以使用成员内部类处理
静态内部类:在基类 A 里持有静态内部类 B 的引用,然后在 A 的子类里创建特定业务的 B 的子类;单例模式
局部内部类:某个方法为代码块临时使用时创建
匿名内部类:Android常见的点击事件

何时使用内部类

  1. 需要用一个类来解决一个复杂的问题,但是又不希望这个类是公共的
  2. 需要实现一个接口,但不需要持有它的引用

特殊语法

1、内部类访问外部类的同名字段时需要使用 外部类名.this 进行操作

深入学习

静态内部类的单例模式写法

public class LocationManager{
    private static class ClassHolder {
        private static final LocationManager instance = new LocationManager();
    }
    public static LocationManager getInstance() {
        return ClassHolder.instance;
    }
}

内部类导致的内存泄漏解决

内部类造成内存泄漏的原因:
静态内部对象持有外部类对象的引用,即非静态内部类对象在某个时刻已经不在被使用,或者说这个内部类对象可以在不影响程序正确运行的情况下被回收,而因为我们对这个内部类的使用不当而使得其无法被 JVM 回收,同时会导致其外部类对象无法被回收
避免策略:
1.能用静态内部类就尽量使用静态内部类
2.对于一些自定义类的对象,慎用 static 关键字修饰(static 修饰的对象越多,对应的 “root” 也就越多,每一次 JVM 能回收的对象就越少)
3.弱引用结合静态内部类解决handler的内存泄漏问题(如下)

    private static class MyHandler extends Handler {
        //弱引用,在垃圾回收时,activity可被回收
        private WeakReference<MainNewActivity> mWeakReference;

        public MyHandler(MainNewActivity activity) {
            mWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
        }
    }

拓展

普通内部类注意点

1、内部类对象可以访问外部类对象中所有访问权限的字段,同时,外部类对象也可以通过内部类的对象引用来访问内部类中定义的所有访问权限的字段
2、private 权限的字段只能被当前类本身访问。然而这里直接访问了对应外部类 / 内部类的 private 权限的字段,原因是啥?
在非静态内部类访问外部类私有成员 / 外部类访问内部类私有成员 的时候,对应的外部类 / 外部类会生成一个静态方法,用来返回对应私有成员的值,而对应外部类对象 / 内部类对象通过调用其内部类 / 外部类提供的静态方法来获取对应的私有成员的值

局部内部类注意点

在外部类的方法中定义的类,其作用的范围是所在的方法内。他不能被 public、private、protected来修饰。它只能访问方法中定义的final类型的局部变量

总结

内容不多,主要是整理出一个思路,方便大家面试和回忆此处的知识点

思绪图

题外话

关注我的工作外生活
公众号搜索 杨方刚的生活录
摸鱼小程序搜索 魔芋办公室

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值