内部类

🐓内部类

可以将一个类定义在另一个类或方法中,这样的类称为内部类

将类定义在另一个类中成员的位置

public class Inner {
    // 定义在类内部
    class Demo{
        public void say(){
            System.out.println("hello!");
        }
    }
}

成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)

成员内部类依赖于外部类, 要创建内部类的对象, 先要创建外部类的对象

public class Inner {
    private static final String name ="张三";
    public static void say(){
        System.out.println("我是外部类方法!");
    }

    class Demo{
        public void go(){
            // 调用外部类方法及变量
            System.out.println(name);
            Inner.say();
        }
    }
}

/*
    测试
*/
@Test
public void test1(){
    // 先创建外部类实例
    Inner.Demo demo = new Inner().new Demo();
    demo.go();
}

外部类访问内部类时,必须要先实例化内部类的对象

public class Inner {

    public void go(){
        // 实例化内部类
        new Demo().say();
    }

    class Demo{
        private final String name = "李四";
        public void say(){
            System.out.println("我是内部类方法!");
        }
    }
}

成员内部类可以拥有如成员方法般的多种修饰符

public class Inner {
    // public
    public class Demo{}
    // private
    private class Demo2{}
    // protected
    protected class Demo3{}
    // default
    class Demo4{}
}

当外部类和内部类拥有同名的成员变量和方法时,会发生隐藏现象,默认调用内部类的成员

使用外部类.this.变量 和 外部类.this.方法,指定使用外部类变量及方法

public class Inner {
    private String name = "张三";
    public void say(){
        System.out.println("外部类方法!");
    }

    class Demo{
        private String name = "李四";
        public void say(){
            System.out.println("内部类方法!");
        }
        public void go(){
            System.out.println(Inner.this.name);
            Inner.this.say();
        }
    }
}

将内定义在另一个类的方法中

public class Inner {
    public void method() {
        class Demo {
            public void say() {
                System.out.println("hello");
            }
        }
        // 在方法内部调用内部类
        new Demo().say();
    }
}

/*
    测试
*/
@Test
public void test1(){
    Inner inner = new Inner();
    inner.method();
}

局部内部类的访问权限仅限于方法内或者该作用域内

局部内部类和局部变量一样,不能有public, private, protected以及static修饰符

使用内部类能够在实现父类或者接口方法的同时, 产生一个对象

// 接口
public interface Demo{
    void say();
}

/*
    测试
*/

// 产生对象直接调用
@Test
public void test1(){
    Demo demo = new Demo() {
        @Override
        public void say() {
            System.out.println("匿名内部类!");
        }
    };
    demo.say();
}

匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

public class Inner {
    // 需要接口类型的参数
    public void go(Demo demo){
        demo.say();
    }
}

interface Demo{
    void say();
}

/*
    测试
*/
@Test
public void test1(){
    Inner inner = new Inner();
    // 匿名内部类
    inner.go(new Demo() {
        @Override
        public void say() {
            System.out.println("匿名内部类!");
        }
    });
}

和成员内部类的区别是, 静态内部类不依赖于外部类, 但是静态内部类不能调用外部类的非static成员变量或方法

public class Inner{
    private static final String name = "张三";
    // 无法调用非static方法
    private Integer age = 22;
    public static void say(){
        System.out.println("外部类方法!");
    }

    static class Demo{
        public void say(){
            System.out.println(name);
            Inner.say();
        }
    }
}

/*
    测试
*/
@Test
public void test1(){
    // 无依赖于外部类
    Inner.Demo demo = new Inner.Demo();
    demo.say();
}
  • 为什么成员内部类可以无条件访问外部类?
编译器会默认为成员内部类添加一个指向外部类对象的引用
虽然成员内部类的构造函数是空参的,但编译器仍会默认添加一个参数,类型是内部类指向外部类对象的引用类型,从而达到将引用传入的效果
  • JDK8之前, 使用局部内部类和匿名内部类访问的变量只能是final类型 为什么使用final修饰
会出现外部方法已经结束,而局部内部类还没有结束的情况,如果局部内部类需要外部方法的传参,而方法已经结束了,就会出现错误
所以编译器采用复制的方法,在编译期间变量字面值确定的情况下,在匿名内部类或局部方法的常量池中添加一个内容相同的字面量或直接键相应的字节码嵌入到执行字节码中,这样就可以和方法中局部变量分隔开
但是,如果修改方法中的局部变量,又该怎么办呢,所有要求局部内部类访问的变量只能是final类型,使字面量无法修改
  • 为什么使用内部类
1. 每个类都能独立继承一个父类,不管外部类是否继承了父类,使用多继承的解决方案变得完整
2. 方便将存在一定逻辑的类组织在一起,又实现对外的隐藏
3. 方便编写事件驱动
4. 方便编写线程代码
5. 简化代码,利于维护

Original: https://www.cnblogs.com/suwuji/p/16555779.html
Author: 苏无及
Title: 内部类

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/612798/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • MySQL 分区表,为什么分区键必须是主键的一部分?

    随着业务的不断发展,数据库中的数据量会越来越大,相应地,单表中的数据量也会越来越大,达到临界值时,单表的查询性能会下降。 [En] With the continuous deve…

    数据库 2023年5月24日
    078
  • Linux Shell 自动交互功能

    需求背景: 近日,在安装某软件过程,发现在安装过程需要输入一些信息才能继续下一步操作,在机器数量较少情况下,我们可以单台登录上去完成安装操作,但当机器数量超过一定时,如果再手动登录…

    数据库 2023年6月14日
    082
  • Maven项目添加外来jar包

    本例: 是为了读取Excel文件并把数据录入数据库,从数据库读写数据 写入Excel文件 用到的jar包:mysql—-poi Original: https://ww…

    数据库 2023年6月9日
    071
  • mysql @rownum := @rownum+1 方式获取行号

    MySQL: mysql中没有获取行号的函数,因此需要通过一些自定义语句来进行获取。通常做法是,通过定义用户变量@rownum来保存表中的数据。通过赋值语句@rownum:=@ro…

    数据库 2023年6月16日
    073
  • 0812Java核心技术卷(1)随笔

    自增运算符与自减运算符 这些运算符改变了变量的值,所以它的操作数不能是数值。例如4++就是一条非法语句不建议在其他表达式内部使用++,因为这样会降低代码可读性,产生bug Orig…

    数据库 2023年6月14日
    091
  • logstash在windows系统下的安装与使用

    前言:Logstash 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到 Elasticsearch。 ES官网:https://www.ela…

    数据库 2023年6月14日
    094
  • 配置中心的设计-nacos vs apollo

    和 apollo 一样,nacos 也是一款配置中心,同样可以实现配置的集中管理、分环境管理、即时生效等等。不过,nacos 还具备了服务发现的功能。 分析 apollo 时,我们…

    数据库 2023年6月6日
    096
  • 2. 函数

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    数据库 2023年6月16日
    084
  • 重写Feign编码器

    有个spring cloud 架构的项目需要调用php小组的api接口,但php提供的接口入参大部分是下划线命名,而Java这边的实体类是按照驼峰编写,如果使用Fegin调用会导致…

    数据库 2023年6月6日
    079
  • sql查询结果的排序问题

    在sql语句中的查询语句,不同的写入顺序会导致查询的结果不一样 比如我要查询一个联合表中的同学,如果查询的顺序不一样的话,那么结果就会不同 上图为数据的关系图 下面我们要查询张三老…

    数据库 2023年6月11日
    079
  • google浏览器个人常用快捷键

    分享一下个人常用快捷键。 说明:字母排序规则遵循字母表(a->z) 快捷键 介绍 ctrl+0 恢复页面到100% ctrl+数字(1~9) 切换至序号对应的标签页 ctrl…

    数据库 2023年6月14日
    070
  • MyBatis(二)-CURD (ResultMap 一对一,一对多)

    1、insert 标签 1.1 获取SqlSessionFactory 对象的通用方法 方便后面分测试; //获取SqlSessionFactory 对象的通用方法 public …

    数据库 2023年6月16日
    067
  • jar工具常用命令

    参考链接:https://www.ibm.com/developerworks/cn/java/j-jar/index.html Original: https://www.cnb…

    数据库 2023年6月9日
    066
  • sqlserver 分列

    sql server 数据库中某张表(Person)的数据信息是: Address 1 平山花园-4单元-12幢-203 2 香山花园-3单元-22幢-304 现在有需求是,将地址…

    数据库 2023年6月11日
    071
  • VS code 每次退出都要重新下载解决方案

    VS code 每次退出都要重新下载解决方案 打开文件-首选项-设置 在搜索栏输入Extensions: Auto Update 然后把所有打钩的取消 ,退出vs code 的时候…

    数据库 2023年6月16日
    089
  • Java面试题(六)–Redis

    1 Redis基础篇 1、简单介绍一下Redis优点和缺点? 优点: 1、本质上是一个 Key-Value 类型的内存数据库,很像memcached 2、整个数据库统统加载在内存当…

    数据库 2023年6月16日
    082
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球