【从0开始学习Java | 第12篇】内部类
文章目录
- 基本介绍📖
- 快速入门
- 内部类的分类🧾
- 局部内部类🥝
- 说明⚠️
- 为什么局部变量不能添加访问修饰符?🤔
- 演示(注释非常重要)
- 匿名内部类(最重要)🐦🔥
- 说明(跟局部内部类类似)⚠️
- 实例(注释非常重要)
- 匿名内部类应用实践(当做实参传递,简洁高效)🍂
- 案例1
- 案例2
- 成员内部类🥝
- 说明⚠️
- 示例
- 静态内部类🥝
- 说明⚠️
- 示例
基本介绍📖
一个类的内部又完整的嵌套了另一个类结构,被嵌套的类称为内部类(inner class),嵌套了其他类的类称为外部类(outer class),使我们类的五大成员【属性、方法、构造器、代码块、内部类】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
快速入门
public class Learn{//外部其他类public static void main(String[] args){}
}class Outer{//外部类private int n1 =100; //属性public Outer(int n1) {//构造器this.n1 = n1;}public void m1(){//方法System.out.println("ma()");}{System.out.println("代码块....");}class Inner{ //内部类,在Outer类的内部}
}
内部类的分类🧾
定义在外部类的局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点)
定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
局部内部类🥝
说明⚠️
- 局部内部类是定义在外部类的局部位置,比如在方法中,并且有类名(本质仍然是一个类)
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量不能使用访问修饰符,但是可以使用final修饰,因为局部变量也可以使用final
- 作用域:仅仅在定义它的方法或代码块中
- 局部内部类 - - -访问- - ->外部类的成员【访问方式:直接访问】
- 外部类 - - - 访问 - - ->局部内部类的成员
访问方式:创建对象,再访问(注意:必须在作用域内) - 外部其他类 - - - 不能访问 - - - >局部内部类(因为局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)去访问
为什么局部变量不能添加访问修饰符?🤔
原因:局部内部类的作用域被严格限制在其所在的代码块(如方法体)内部,就像方法中的局部变量一样。它的可见性仅局限于当前代码块,外部类的其他方法或外部类之外的代码都无法直接访问它。而访问修饰符的核心作用是控制跨作用域的访问权限(例如外部类访问内部类成员、子类继承时的可见性等)。对于局部内部类而言,由于其作用域已经被限定在局部代码块中,跨作用域访问本身就不存在,因此访问修饰符失去了实际意义
演示(注释非常重要)
public class Learn{//外部其他类public static void main(String[] args){new Outer().m1();}
}class Outer{//外部类private int n1 =100; //属性private void m2() {//私有方法System.out.println("m2()");}public void m1(){//方法//1.局部内部类是定义在外部类中的局部位置,通常在方法里面//3.不能添加访问修饰符,但是可以使用final修饰//4.作用域:仅仅在定义它的方法或代码块中final class Inner{ //局部内部类(本质仍然是一个类)private int n1=800;//2.可以直接访问外部类中的所有成员,包括私有的public void f1(){//6. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,// 如果想访问外部类的成员,则可以使用(外部类.this.成员)去访问System.out.println("n1="+n1+" 外部类的n1="+Outer.this.n1);m2();}}//5.外部类在方法中,可以创建Inner对象,然后调用方法即可Inner inner = new Inner();inner.f1();}
}
运行结果:
n1=800 外部类的n1=100
m2()
匿名内部类(最重要)🐦🔥
说明(跟局部内部类类似)⚠️
- 匿名内部类是定义在外部类的局部位置,如方法中,并且没有类名
- 匿名内部类的语法既有定义类的特征,也有创建对象的特征,因为匿名内部类既是一个类的定义,同时它本身也是一个对象
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它是一个局部变量
- 作用域:仅仅在定义它的方法或代码块中
- 匿名内部类 - - - 访问 - - - > 外部类成员【直接访问】
- 外部其他类 - - - 不能访问 - - - >匿名内部类(局部变量)
- 如果外部类和匿名内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)去访问
基本语法
new 类或接口(参数列表){类体
};
实例(注释非常重要)
public class AnonymousInnerClass {public static void main(String[] args){Outer04 outer04 = new Outer04();outer04.method();}
}interface IA {public void cry();
}class Outer04 {private int n1 = 10;public void method() {//基于接口的匿名内部类//1.需求:想使用接口IA,并创建对象//2.传统方式:写一个类,实现该接口,并创建该对象
// IA tiger = new Tiger();
// tiger.cry();//而需求是Tiger类是只使用一次,后面不再使用//4.可以使用匿名内部类来简化开发//6.tiger的编译类型是? IA//7.tiger的运行类型是?就是匿名内部类 ××× => Outer04$1/*
* 我们看底层: 会分配类名 Outer04$1
* class ××× implement IA{
* public voi cry() {
* System.out.println("老虎叫唤");
* }
* }
*
* */// 8. jdk在底层创建匿名内部类 Outer04$1,立即就创建了Outer04$1实例,// 并把地址返回给tiger// 9.匿名内部类使用一次,就不能再使用(不是对象tiger)IA tiger = new IA(){public void cry(){System.out.println("老虎叫唤");}};tiger.cry();tiger.cry();System.out.println(tiger.getClass());//演示基于类的匿名内部类//分析//1. father编译类型 => Father//2. father运行类型 => Outer04$2//3. 底层会创建匿名内部类/** class Outer04$2 extends Father{* public void test(){System.out.println("匿名内部类重写了test方法");}* }* */Father father = new Father("jack"){public void test(){System.out.println("匿名内部类重写了test方法");}};father.test();System.out.println("father对象的运行类型="+father.getClass());//基于抽象类的匿名内部类Animal animal = new Animal() {public void eat() {System.out.println("小狗吃骨头");}};animal.eat();System.out.println(animal.getClass());//也可以直接调用,不过只能使用一次//匿名内部类本身也是返回一个对象new Animal() {public void eat() {System.out.println("小猫吃猫粮");}}.eat();}}//class Tiger implements IA{
// public void cry(){
// System.out.println("老虎叫换");
// }
//}class Father{public Father(String name){System.out.println("接收到了name="+name);}public void test(){}
}abstract class Animal{public abstract void eat();
}
运行结果:
老虎叫唤
老虎叫唤
class Outer04$1
接收到了name=jack
匿名内部类重写了test方法
father对象的运行类型=class Outer04$2
小狗吃骨头
class Outer04$3
小猫吃猫粮
匿名内部类应用实践(当做实参传递,简洁高效)🍂
案例1
public class Test {public static void main(String[] args){f1(new IB(){public void show(){System.out.println("show()");}});}public static void f1(IB ib){ib.show();}
}interface IB{public void show();
}
案例2
需求:
- 有一个铃声接口Bell,里面有一个ring方法
- 有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型
- 测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
- 再传入另一个匿名内部类(对象),打印:小伙伴上课了
public class Test2 {public static void main(String[] args){Cellphone.alarmclock(new Bell(){public void ring(){System.out.println("懒猪起床了");}});Cellphone.alarmclock(new Bell(){public void ring(){System.out.println("小伙伴上课了");}});}
}interface Bell{public void ring();
}class Cellphone{public static void alarmclock(Bell bell){bell.ring(); //动态绑定}
}
输出:
n1 = 10 name = 张三
n1 = 10 name = 张三
成员内部类🥝
说明⚠️
-
成员内部类是定义在外部类的成员位置,并且没有static修饰(否则就是静态内部类了)
-
可以直接访问外部类的所有成员,包含私有的
-
可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员
-
成员内部类 - - - 访问 - - - > 外部类成员(比如:属性)【访问方式:直接访问】
-
外部类 - - - 访问 - - -> 成员内部类【访问方式:创建对象,再访问】
-
🧐外部其他类 - - - 访问 - - - > 成员内部类
语法:Outer.Inner inner = new Outer.new Inner(); -
如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)去访问
示例
public class Test {public static void main(String[] args){Outer08 outer08 = new Outer08();outer08.t1();Outer08.Inner08 inner08 = new Outer08().new Inner08();inner08.say();}}class Outer08{//外部类private int n1=10;public String name = "张三";//注意:成员内部类,是定义在外部类的成员位置public class Inner08{//成员内部类public void say(){System.out.println("n1 = "+n1+" name = "+name);}}public void t1(){Inner08 inner08 = new Inner08();inner08.say();}
}
静态内部类🥝
说明⚠️
- 静态内部类是定义在外部类的成员位置,并且有static修饰
- 可以直接访问外部类的所有静态成员,但不能访问非静态成员👏
- 可以添加任意访问修饰符,因为它的地位就是一个成员
- 作用域:同其他成员,为整个类体
- 静态内部类 - - - 访问 - - - >外部类(比如:静态属性)【访问方式:直接访问所有静态成员】
- 外部类 - - - 访问 - - - > 静态内部类【访问方式:创建对象,再访问】
- 外部其他类 - - - 访问 - - - > 静态内部类
语法之一:Outer.Inner inner = new Outer.Inner();
inner.say(); - 如果外部类和静态内部类的成员重名时,静态内部类访问时,遵循就近原则,如果想访问外部类的静态成员,则可以使用(外部类.类名)去访问【这里没有this,因为只能访问外部类静态的静态成员】👏
示例
public class Test {public static void main(String[] args){new Outer10().m1();//静态内部类可以通过类名直接访问new Outer10.Inner10().say();}}class Outer10{//外部类private int n1=10;private static String name = "张三";static class Inner10{ //静态内部类public void say(){//只能访问外部类中的静态成员System.out.println(name);}}public void m1(){Inner10 inner10 = new Inner10();inner10.say();}
}
结果:
张三
张三
如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!