内部类
文章目录
基本介绍
一个类的内部又完整地嵌套了另一个类结构。被嵌套的类称谓 内部类(inner class)
,嵌套其他类的类称为 外部类(outer class)
。
- 特点:可以直接访问私有属性
基本语法
class Outer{ //外部类
class Inner{ //内部类
}
}
class Other{ //外部其他类
}
内部类的分类
- 定义在外部类局部位置上(比如:方法内):
局部内部类
(有类名)匿名内部类
(没有类名)
- 定义在外部类的成员位置上:
成员内部类
(没用static
修饰)静态内部类
(使用static
修饰)
一、局部内部类
-
局部内部类
是定义在外部类的局部位置,比如方法中,并且有类名 -
语法
class Outer{ public void m(){ //局部内部类 class Inner{} } }
特点
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为地位是局部变量。局部变量不能使用修饰符。但可以使用
final
修饰,因为局部变量也可以使用final
- 作用域:仅仅在定义它的方法或代码块中
- 局部内部类—访问—>外部类的成员 直接访问
- 外部类—访问—>局部内部类 创建对象,再访问(注意:必须在作用域中)
- 外部其它类—不能访问—>局部内部类(因为 局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(
外部类名.this.成员
)去访问
实现
public class Outer { //外部类
private int n1 = 10;
public void m2(){
System.out.println("f()被调用...");
}
public void m(){
/*
2. 局部内部类不能添加访问修饰符
但是可以使用final
*/
final class Inner{ //局部内部类
private int n1 = 20;
public void f(){
/*
7. 在重名情况下,调用外部类的私有属性
*/
System.out.println("n1=" + n1 +" 外部类的私有属性n1=" + this.n1);
/*
1. 调用外部类的私有属性
4. 局部内部类---直接访问--->外部类成员
*/
m2();
}
}
/*
5. 外部类---访问--->局部内部类
先创建对象,再访问
*/
Inner inner = new Inner();
inner.f();
}
}
执行
public class Main {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m();
}
}
结果
n1=20 外部类的私有属性n1=20
f()被调用...
二、匿名内部类
-
匿名内部类
是定义在外部类的局部位置,比如说方法中,并且没有类名 -
语法
class Outer{ public void h(){ IA ia = new IA(){ }; } }
特点
匿名内部类
既是一个类的定义,同时它本身也是一个对象- 它也有
局部内部类
的特点
使用原因
想要使用IA接口、父类、抽象类,并创建对象
IA接口
public interface IA {
public void cry();
}
1.传统方法实现接口
让局部内部类
实现IA接口
public class Outer { //外部类
public void m(){
/*局部内部类实现IA接口*/
class Inner implements IA{ //局部内部类
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
//创建对象
Inner inner = new Inner();
inner.cry();
}
}
执行
public class Main {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m();
}
}
结果
老虎叫唤...
2.匿名内部类实现接口
当内部类
只使用一次时,可以使用匿名内部类
来简化
public class Outer { //外部类
public void m(){
/*匿名内部类实现IA接口*/
IA tiger = new IA(){ //匿名内部类
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
};
//直接使用tiger,不用创建对象
//tiger.getClass 可以查看匿名内部类
System.out.println("tiger的运行规则:"+tiger.getClass());
tiger.cry();
tiger.cry();
}
}
执行
public class Main {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m();
}
}
结果
tiger的运行规则:class student.内部类.匿名内部类.demo.Outer$1
老虎叫唤...
老虎叫唤...
其中Outer$1就是底层自动分配的类名
3.匿名内部类继承父类
父类
public class Father { //父类
Father(String name){ //构造器
System.out.println("接收到了name:"+name);
}
public void test(){} //方法
}
匿名内部类
public class Outer { //外部类
public void m(){
Father father = new Father("Tom"){ //匿名内部类
@Override
public void test() {
super.test();
System.out.println("匿名内部类重写了test()方法");
}
};
father.test();
}
}
执行
public class Main {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m();
}
}
结果
接收到了name:Tom
匿名内部类重写了test()方法
父类构造器
收到了匿名内部类
返回的参数
4.匿名内部类继承抽象类
抽象类
abstract class Animals { //抽象类
abstract void eat();
}
匿名内部类
public class Outer {
public void m(){
Animals dog = new Animals() {
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
dog.eat();
}
}
执行
public class Main {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m();
}
}
结果
小狗吃骨头...
5.匿名内部类做实参
接口
public interface IL {
void show();
}
Picture类实现接口IL
//类---实现--->接口
public class Picture implements IL{
@Override
public void show() {
System.out.println("这是一幅世界名画...");
}
}
执行
public class Main {
public static void main(String[] args) {
//传统方法
f1(new Picture());
//当做实参传递,直接简洁
f1(new IL(){
@Override
public void show() {
System.out.println("这是一幅世界名画~~~");
}
});
}
//静态方法,参数是接口类型
public static void f1(IL il){
il.show();
}
}
结果
这是一幅世界名画...
这是一幅世界名画~~~
6.来做一道例题
题目
有一个手机铃声接口Bell,里面有一个ring方法
有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型
测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
再传入另一个匿名内部类(对象),打印:小伙伴们上课了
首先建立一个Bell
接口
interface Bell {
//ring方法,会被其他类实现
public void ring();
}
再建立一个手机类Cellphone
class Cellphone {
//参数是接口类型
public void alarmclock(Bell bell){
bell.ring();
}
}
最后通过Print
类将它们打印出来
public class Print {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
//匿名内部类做实参
cellphone.alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
//匿名内部类做实参
cellphone.alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴们上课了");
}
});
}
}
结果
懒猪起床了
小伙伴们上课了
三、成员内部类
-
成员内部类
是定义在外部类的成员位置,并且没有static修饰 -
语法
class Outer{ private int n1 = 10; public void m1(){} class Inner{} }
特点
-
可以直接访问外部类的所有成员,包含私有的
class Outer{ private int n1 = 10; class Inner{ System.out.println("外部类的私有属性n1=" + n1); } }
-
可以添加任意修饰符(public、protected、默认、private),因为它的地位就是一个成员
class Outer{ public class Inner{} }
-
作用域和其他外部类一样
-
成员内部类—访问—>外部类的成员 直接访问
class Outer{ public void h(){ } class Inner{ h(); } }
-
外部类—访问—>成员内部类 创建对象,再访问
class Outer{ class Inner{ public void h(){ } } Inner inner = new Inner(); inner.h(); }
-
外部其他类—访问—>成员内部类
class Outer{ class Inner{ public void h(){ } } public Inner getInner(){ return new Inner(); } }
public class Main{ public static void main(String[] args){ //第一种方法 //outer.new Inner()相当于把new Inner当成outer的成员 Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); //第二种方法 //第二种方法 在外部类中编写一个方法,可以返回Inner对象 Outer.Inner inner1 = Outer.getInner(); } }
-
如果外部类和成员内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(
外部类名.this.成员
)去访问class Outer{ private int n1 =10; class Inner{ private int n1 = 20; public void h(){ System.out.println("n1="+n1+" 外部类的n1="+Outer.this.n1); } } }
说明
public class Outer {
private int n1 = 10;
public String name= "张三";
private void hi(){
System.out.println("h1方法被调用...");
}
/*
2. 可以添加任意修饰符
*/
public class Inner{
private double sal = 99.8;
private int n1 = 66; //重名
public void say(){
/*
7. 使用(外部类名.this.成员)访问重名属性
*/
System.out.println("n1=" + n1 + " 外部类的私有属性n1=" + Outer.this.n1 + " this.n1=" + this.n1);
/*
1. 可以直接访问外部类的所有成员,包括私有的
4. 成员内部类---访问--->外部类的成员 ==直接访问==
*/
hi();
}
}
//方法,返回一个Inner
public Inner getInner(){
return new Inner();
}
public void t(){
/*
6. 外部类---访问--->成员内部类 ==创建对象,再访问==
*/
Inner inner = new Inner();
inner.say();
System.out.println(inner.sal);
}
}
执行
public class Main {
public static void main(String[] args) {
//创建外部类对象,并引用
Outer outer = new Outer();
outer.t();
/*
第一种方法
6. 外部其他类使用成员内部类
outer.new Inner()相当于把new Inner当成outer的成员
这只是一种语法,不必纠结
*/
Outer.Inner inner = outer.new Inner();
inner.say();
/*
第二种方法 在外部类中编写一个方法,可以返回Inner对象
*/
Outer.Inner inner1 = outer.getInner();
inner1.say();
}
}
四、静态内部类
-
静态内部类
是定义在外部类的成员位置,并且有static修饰 -
语法
class Outer{ static class Inner{} }
特点
-
可以直接访问外部类的所有
静态成员
,包含私有的,但不能直接访问非静态成员public class Outer { static private int n1 = 100; static class Inner{ public void h(){ System.out.println(n1); } } }
-
可以添加任意修饰符(public、protected、默认、private),因为它的地位就是一个成员
-
作用域:同其他的成员,为整个类体
-
静态内部类—访问—>外部类(比如:静态属性) 直接访问
-
外部类—访问—>静态内部类 创建对象,再访问
-
外部其他类—访问—>静态内部类
public class Outer { static class Inner{ public void say(){ System.out.println("say()被调用..."); } } public Inner getInner(){ return new Inner(); } }
public class Main { public static void main(String[] args) { //方式一 // 因为是静态内部类,可以通过类名直接访问 Outer.Inner inner = new Outer.Inner(); inner.say(); //方式二 //编写一个方法,可以返回静态内部类的对象实例 Outer outer = new Outer(); Outer.Inner inner1 = outer.getInner(); inner1.say(); } }
-
如果外部类和静态内部类的成员重名时,静态内部类访问时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
public class Outer { private static int n = 10; static class Inner{ private int n = 20; public void m(){ System.out.println(n+" 外部类的n="+Outer.n); } } }
public class Main { public static void main(String[] args) { Outer.Inner inner = new Outer.Inner(); inner.m(); } }
结果
20 外部类的n=10