内部类
基本介绍
一个类的内部嵌套了另一个类结构,被嵌套的类称之为内部类
最大特点:可以直接访问私有属性;可体现类之间的包含关系
语法
class Outer{//外部类
class Inner{//内部类
}
}
class Other{//外部其他类
}
种类
定义在外部类的局部上(如方法体内):
- 局部内部类
- 匿名内部类(无类名,重点🚩🚩🚩)
定义在外部类的成员上(如属性位置):
- 成员内部类(无static修饰)
- 静态内部类(有static修饰)
局部内部类
语法
class Outer{
private void met(){//在方法体内
class Inner{}//局部内部类
}
}
细节与注意
-
一般定义在局部位置,通常在方法体(有类名)
-
可以直接访问外部类所有成员,包括私有成员
-
不能加修饰符,但是可以使用
final
修饰 -
作用域:仅仅在定义该内部类的方法里或者代码块中
-
访问:
- 局部内部类---》访问---》外部类成员【直接访问】;
- 外部类---》访问---》内部类成员【在作用域内创建对象,再访问】
- 外部其他类-----不可访问------局部内部类【地位与局部变量一样】
-
外部类与局部内部类有重名成员时:访问遵循就近原则;若想访问外部类同名成员。可使用:
外部类名.this.成员(属性、方法)
package com.java_learn.oop_advanced.inner_;
public class LocalInner {
public static void main(String[] args) {
/**
* 局部内部类使用
*/
LocalOuter localOuter = new LocalOuter();
localOuter.m2();
}
}
class LocalOuter{
private int o_n=10;
private void m1(){
System.out.println("这里是外部类LocalOuter的m1方法");
}
public void m2(){
System.out.println("这里是外部类LocalOuter的m2方法");
class LocalInner{//局部内部类不能使用修饰符,可以使用final
private int i_n=20;
private int o_n=100;//与外部类重名属性,调用遵循就近原则;
// 若想访问外部类的o_n,可使用 外部类名.this.属性名 访问
private void i_m(){
System.out.println("这里是内部类LocalInner的i_m方法");
}
private void showi_n(){
System.out.println("外部类属性o_n:"+o_n);//🚩可以直接访问外部类
System.out.println("外部类属性o_n:"+LocalOuter.this.o_n);//🚩使用外部类名.this.属性名访问同名属性
}
}
LocalInner localInner = new LocalInner();//外部类访问内部类成员,需要实例化
localInner.showi_n();
}
}
匿名内部类🚩🚩🚩
语法
class Outer{
private void met(){//在方法体内
new 类/接口(参数列表){}//匿名内部类
};//注意有分号
}
细节与注意(🚩重点理解底层实现)
- 一般定义在局部位置,通常在方法体(没有类名);⚡同时还是一个对象
- 可以直接访问外部类所有成员,包括私有成员
- 不能加修饰符
- 作用域:仅仅在定义该内部类的方法里或者代码块中
- 外部其他类-----不可访问------局部内部类【地位与局部变量一样】
- 外部类与局部内部类有重名成员时:访问遵循就近原则;若想访问外部类同名成员。可使用:
外部类名.this.成员(属性、方法)
- 底层:以外部类名$1 来命名匿名内部类
- jdk创建了匿名类后,立即new了一个外部类名$1的实例,赋给引用变量
- 匿名内部类执行一次赋给引用变量后不可再使用,该类实例的对象可用
- 运行类型:匿名内部类的底层分配类名:
外部类$匿名类序号
package com.java_learn.oop_advanced.inner_;
public class AnonymousInner {
public static void main(String[] args) {
/**
* 匿名内部类使用
*/
A_Outer a_outer = new A_Outer();
a_outer.A_met();//匿名内部类实现
}
}
class A_Outer {
//🚩需求:有多个类实现IA接口,⚡但是每个类只使用一次
//传统方法:创建多个类,实现show方法;这里创建了类Cat
//问题:代码可用性不高,繁琐
public void t_met() {
Cat cat = new Cat();
cat.show();
}
//匿名内部类实现:简化开发
public void A_met() {
/*⚡⚡⚡
cat 的编译类型:IA
cat 的运行类型:匿名内部类
*****解析运行类型******
匿名内部类底层:
class XXXX implements IA{//此XXXX即为系统分配类名,只有调用getClass方法可看;即为》》(外部类$1)
public void show() {
System.out.println("匿名内部类实现了show方法");
}
}
*/
//基于接口 的匿名内部类
IA cat = new IA() {
public void show() {
System.out.println("匿名内部类实现了show方法");
}
};
cat.show();
System.out.println("匿名内部类的类名:"+cat.getClass());
//基于类 的匿名内部类
/*⚡⚡⚡
底层实现:
class xxx extends Bud{}; xxx为系统分配类名---》A_Outer$2
运行类型:A_Outer$2
*/
Bud bud = new Bud(){
//因为底层实现继承,这里可不重写,继承父类b_met方法
};
bud.b_met();
System.out.println("基于类实现的匿名内部类名:"+bud.getClass());
}
}
class Bud{
public void b_met(){
System.out.println("这是Bud类的b_met方法");
}
}
interface IA {
void show();
}
//传统实现方法创建Cat
class Cat implements IA {
@Override
public void show() {
System.out.println("这里小猫实现了show方法");
}
}
- 匿名内部类做参数⚡⚡⚡
package com.java_learn.oop_advanced.inner_;
public class Exercise {
public static void main(String[] args) {
met(
new Nu() {
@Override
public void show() {
System.out.println("这里通过匿名内部类作参数");
}
}
);
}
public static void met(Nu n){
n.show();
}
}
interface Nu{
default void show(){
System.out.println("这里是接口的方法");
};
}
实践
package com.java_learn.oop_advanced.inner_;
public class Exercise01 {
public static void main(String[] args) {
Cellphone.alarmclock(
new Bell() {
@Override
public void ring() {
System.out.println("起床了");
}
}
);
}
}
interface Bell{
void ring();
}
class Cellphone{
public static void alarmclock( Bell b){
b.ring();
}
}
成员内部类
语法
class Outer{
private int a=12;
class Inner{
//与成员地位一致
}
}
细节与注意
- 可添加任意修饰符(地位和属性一样)
- 内部类---》访问---》外部类成员【直接访问】
- 外部类----》访问---》成员内部类【在外部类方法创建对象,再调用】
- 外部其他类---》访问---》成员内部类
package com.java_learn.oop_advanced.inner_;
public class MemberInner {
public static void main(String[] args) {
/**
* 成员内部类
*/
M_Outer m_outer = new M_Outer();
m_outer.show();
//外部其他类访问成员内部类
//方法1
M_Outer.M_Inner m_inner = m_outer.new M_Inner();
m_inner.M_met();
// 方法2:创建一个方法返回成员内部类的对象
m_outer.innerInstance().M_met();
}
}
class M_Outer{
private int age=12;
class M_Inner{
private int a=21;
public void M_met(){
System.out.println("这里是成员内部类的方法");
}
}
public void show(){//在外部类方法中实例化再调用
M_Inner m_inner = new M_Inner();
m_inner.M_met();
}
public M_Inner innerInstance(){
return new M_Inner();
}
}
静态内部类
语法
class Outer{
private int a=12;
static class Inner{
}
}
细节与注意
- 可以访问外部类所有静态成员,包括私有;但是不能直接访问非静态成员
- 可以有任意修饰符
- 外部类与局部内部类有重名成员时:访问遵循就近原则;若想访问外部类同名成员。可使用:
外部类名.成员(属性、方法)
(注意没有this。因为此时为静态内部类)
package com.java_learn.oop_advanced.inner_;
public class StaticInner {
public static void main(String[] args) {
S_Outer s_outer = new S_Outer();
//方法1
s_outer.innerInstance().S_met();
//方法2
S_Outer.S_Inner s_inner = new S_Outer.S_Inner();
s_inner.S_met();
}
}
class S_Outer{
private static int a=10;
private int b=20;
static class S_Inner{
private int a=30;
public void S_met(){
System.out.println("这是静态内部类的方法");
}
}
public S_Inner innerInstance(){
return new S_Inner();
}
}