我们之前定义的类都是一个类一个文件,而今天我们学习内部类
一个类在另一个类内部,这个类就叫做内部类,如心脏和身体,发动机和汽车的关系
内部类分为2种,成员内部类和匿名内部类
成员内部类
定义格式
修饰符 class 外部类名称{
修饰符 class 内部类名称{
}
}
这里需要注意的是,内用外随便使用,但是外用内需要使用实例对象

我们如上定义了Body类和内部Heart类,我们Body类定义私有变量,内部类是可以访问的

我们编译后可以看见,Body是单独生成类文件,而Heart类文件是关联外部类名的,用$符号连接,所以我们类名只推荐大小写字母数字和下划线,防止使用美元符号冲突
成员内部类的使用
有两种方法,1是间接使用,2直接创建类使用
间接使用

我们给之前的案例修改如上,我们在类内部(或方法内部)创建私有类实例,然后在main接口调用

创建实例使用
实例创建和我们之前的有点区别,这里需要硬性记住
外部类名称.内部类名称 变量名 = new 外部类名称().new 内部类名称();
这里用到了2次new,就是需要2次实例化,包括外部类的实例,也就是我们之前说的外用内需要实例化

如上,我们类没有改变,直接在main方法里定义Heart实例
内部类同名变量访问

如上,我们Outer类内定义了内部类Inner,然后2个类都定义了成员变量num,最后在内部类函数里定义了局部变量num,我们知道局部变量直接使用就可以了,对于内部类的成员变量,直接使用this也OK,但是对于外部类我们不能使用super,因为不是继承的关系,而是要时使用外部类名.this访问

运行结果验证如上
局部内部类
如果一个类定义在另一个外部类方法内部,那只有在这个方法里可以使用,出了方法就不行,不管是其外部类的其他方法,或者更外


如上,我们定义的局部内部类在另一个类方法内部,这里其权限只能使用默认,不能是我们使用的public,我们调用如上
这里继续说下权限问题,结合上节课修饰符
外部类可以使用public/default不写两种,不能是其他
成员内部类可以使用4种权限
局部内部类只能使用default不写这种
对于局部内部类我们要注意的是访问对应方法的局部变量,该局部变量必须是final的,在java8+以后,final可以省略,但是这个局部变量是不可以修改的

如上,我们修改num会报错.
这个原因是方法是存在于栈中,而new出来的对象是在堆中,当方法出栈,对象还存在,如果调用对象的方法,局部变量就无法访问到,这时只有将其设置成final不会变的值,然后就对象就不考虑你出栈销毁,我已经存好了这个值
匿名内部类
讲匿名内部类先回顾下接口


如上,我们编写接口的抽象方法,然后实现了复写这个方法

我们在main方法里调用这个方法,可以实例化实现类,也可以使用我们多态的方法,左父右子,都是可以的,但是不能直接拿接口去实例化,这是错误写法,已经被上图注释
我们匿名内部类的使用就是当我们作为一个接口的实现,只需要实现一次的时候,那就不需要在额外编写实现类,直接在实例时定义
格式 接口名称 变量名 = new 接口名称(){ 里面复写抽象方法};

如上,我们相当于在实例时使用了类的定义,这里需要记住格式,最后分号不要忘了,这样我们使用匿名内部类就不用关心起名,也不用额外创建文件,直接实例时定义就可以了,但是要记住一定是实例一次,否则多次调用,就有你重复写的- -
匿名类的注意事项
1匿名内部类只能实例一次,如果多次实例可以,但是显得代码重复,所以推荐使用xx.java用文件写类

这么写显得很臃肿,这时不推荐使用匿名内部类
2 匿名对象只能调用一次方法,如果想调用多次,只能多次new匿名对象
什么是匿名对象呢,我们知道 接口名 变量名 = new 接口名(){};是匿名内部类写法,虽然匿名,但是有对象名,如上图的a,b,而匿名对象就是没有左侧,只有右侧的,

如上图,我们只能调用一次fun方法,多次调用只能多次new
网友评论