内部类
3445字约11分钟
2025-09-23
内部类
public class InnerClass01 { //外部其它类
}
class A { // 外部类
// 类中的五大成员
// 属性
int a = 10;
// 方法
public void info() {
System.out.println("This is a method.");
}
// 构造器
public A() {
System.out.println("This is a constructor.");
}
// 代码块
{
System.out.println("This is a code block.");
}
// 内部类
class B {
}
}
局部内部类
局部内部类可以访问外部类中的所有成员,包含私有的
class InnerClass {
private String name = "Hello,World!";
private void info() {
System.out.println("私有方法");
}
public void innerClass() {
// 内部类只能在定义它的方法体内或则代码块中使用
class A {
public void info1() {
// 调用外部类中的私有属性
System.out.println(name);
// 调用外部类中的私有方法体
info();
}
}
}
}
局部内部类不能添加访问修饰符,但可以使用 final
修饰
// innerClass方法
public void innerClass() {
// A类
class A {
public void info() {
}
}
// 添加final之后,类B不能被继承
final class B {
public void info() {
}
}
}
外部类访问局部内部类中的成员
- 内部类只能在定义它的方法体内或则代码块中使用
- 外部类要调用内部类,则要在定义内部类的方法体中或则代码块中创建对象
- 然后外部类在调用创建的对象即可实现调用内部类
public class InnerClassDetail {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.innerClass();
}
}
class InnerClass {
private String name = "Hello,World!";
private void info() {
System.out.println("私有方法");
}
public void innerClass() {
// 内部类只能在定义它的方法体内或则代码块中使用
class A {
public void info1() {
// 调用外部类中的私有属性
System.out.println(name);
// 调用外部类中的私有方法体
// 如果调用的外部方法名和本方法名相同
// 那么可以使用下面这种方式调用外部方法
// InnerClass.this.info();
// 或则直接修改本方法或外部方法中的某个方法名
info();
}
}
// 外部类要调用内部类,则要在定义内部类的方法体中或则代码块中创建对象
// 然后外部类在调用创建的对象即可实现调用内部类
A a = new A();
a.info1();
}
}
运行结果
Hello,World!
私有方法
内部类是作用域中的类
- 成员方法的方法体是作用域
- 代码块的方法体是作用域
// 成员方法的方法体是作用域
public void info() {
class index {
}
}
// 代码块的方法体是作用域
{
class index {
}
}
匿名内部类在运行完之后就没有(也就是调用完之后,匿名内部类就不存在了)
匿名内部类(重点)
接口的匿名内部类
匿名内部类是运行在底层的,所以我们看不到
class A { public void index() { new B() { @Override public void info(String name) { System.out.println(name + " a"); } }.info("hello"); } } // 调用类A,其运行结果:hello a class B { public void info(String name) { System.out.println(name + " b"); } }
public class Anonymousinnerclass { public static void main(String[] args) { InnerClass innerClass = new InnerClass(); innerClass.menthod(); // 运行结果:老虎嗷嗷叫~~~ } } class InnerClass { // 外部类 private int a = 10; public void menthod() { /* * 下面的代码中编译类型是 IA * 而运行类型则是 匿名内部类(InnerClass$1) * 匿名内部类是运行在底层的,所以我们看不到 * - 因为接口不能被直接创建,所以系统就会在系统底层创建一个类 * - 匿名内部类就相等于是在底层创建一个内部类 * - 且该内部类还实现了一个接口(该接口就是你new的那个接口) * - 然后在将该类赋值给一个对象,这样方便调用 * 匿名内部类的语法如下: * class InnerClass$1 implements IA { * @Override * public void sound() { * System.out.println("老虎嗷嗷叫~~~"); * } * } * 匿名内部类的类名系统生成的,其类名是 外部类的名称 加上 $1,这后面的数字根据代码从上到下的优先级排列 * 匿名内部类只能被使用一次(注意:是内部类不能被使用,而对象tiger还是可以继续使用的,因为内部类已经传给了tiger) * 因为接口是不能直接创建的,所以需要在后面接上大括号,然后在实现接口里面的所有抽象类 * 这样系统就知道这是一个匿名内部类,就会在底层创建一个类 * 下面只是把匿名内部类赋值给一个对象(IA对象),这样好方便调用 * */ IA tiger = new IA() { @Override public void sound() { System.out.println("老虎嗷嗷叫~~~"); } }; // 因为动态绑定机制,以及就近原则 // 这里会优先调用匿名内部类的方法,而不是其它方法 tiger.sound(); // 向上转型 // IA ia = new Tiger(); // 优先调用子类中的sound方法 // ia.sound(); } } interface IA { void sound(); } //class Tiger implements IA { // @Override // public void sound() { // System.out.println("老虎嗷嗷叫~~~"); // } //}
类的匿名内部类
package com.mao.anonymousinnerclass;
public class AnonymouClass {
public static void main(String[] args) {
VC vc = new VC();
vc.info();
}
}
class VC {
//
public void info() {
/*
* 编译类型是 VC1
* 运行类型是 匿名内部类(VC$2)
* 匿名内部类的类名系统生成的,其类名是 外部类的名称 加上 $1,这后面的数字根据代码从上到下的优先级排列
* - 匿名内部类就相等于是在底层创建一个内部类
* - 且该内部类还继承了一个类(该类就是你new的那个类)
* - 然后在将该类赋值给一个对象,这样方便调用
* 因为不是实现接口,所以方法体里面可以不用写什么代码
* 当然,如果你想,也可以重写你继承的代码(也就是你new的那个对象)
* 注意:即使是匿名内部类,该写的参数还是要写的(形参和实参)
* 该代码的语法为:
* class VC$1 extends VC1() {
*
* }
* */
VC1 vc1 = new VC1("jack") {
};
// 这里之所以输出的是构造器中的内容
// 是因为我们在创建对象的时候会调用该对象的构造器
// 其次info方法中没有输出语句
// 所以就只输出构造器中的语句
// 因此不写 vc1.info(); 也没什么影响,这并不影响构造器中的语句正常输出
vc1.info();
/*
* 创建抽象类的匿名内部类
* 其规则和普通类一样,但是抽象方法中的所有抽象类要全部调用
* 该代码的语法为:
* class VC$2 extends BB() {
* @Override
* public void B1() {
* System.out.println("私有类的匿名内部类");
* }
* }
* */
BB bb = new BB("mack") {
@Override
public void B1() {
System.out.println("私有类的匿名内部类");
}
};
bb.B1();
}
}
// 普通类
class VC1 {
public VC1(String name) {
System.out.println("name:" + name);
}
public void info() {
}
}
// 抽象类
abstract class BB {
public BB(String name) {
}
abstract void B1();
}
匿名内部类的使用细节
匿名内部类的两种调用方法
new IA() { @Override public void sound() { System.out.println("老虎嗷嗷叫~~~"); } }.sound();
IA tiger = new IA() { @Override public void sound() { System.out.println("老虎嗷嗷叫~~~"); } }; tiger.sound();
匿名内部类本身也是一个对象,所以可以直接调用;创建抽象类的匿名内部类,其规则和普通类一样,但是抽象类中的所有抽象方法都要调用(是强制性的),而普通类中的普通方法可以不用调用(不是强制性的)
public void info() { VC1 vc1 = new VC1("jack") { }; vc1.info(); /* * 创建抽象类的匿名内部类 * 其规则和普通类一样,但是抽象类中的所有抽象方法要全部调用 * */ new BB("mack") { public void BB() { System.out.println("私有类的匿名内部类"); } }.BB(); }
class VC1 { public VC1(String name) { System.out.println("name:" + name); } public void info() { } } abstract class BB { public BB(String name) { } abstract void BB(); }
匿名内部类和继承一样,使用调用的对象里的方法时,也是用super来调用
class InnerClass { // 外部类 public void menthod() { CA dog = new CA() { @Override public void CA() { System.out.println("修狗汪汪叫~~~"); // 匿名内部类和继承一样,使用调用的对象里的方法时,也是用super来调用 super.CB(); } }; dog.CA(); } } // 运行结果 // 修狗汪汪叫~~~ // hello class CA { public void CA() { System.out.println("shijie"); } public void CB() { System.out.println("hello"); } }
可以访问外部类的所有成员,包括私有类
class InnerClass { // 外部类 private int a = 10; public void menthod() { IA tiger = new IA() { private int a = 1; @Override public void sound() { int a = 6; // 调用外部类中的私有类 System.out.println(InnerClass.this.a + "老虎嗷嗷叫~~~"); // 调用本类中的私有属性 System.out.println(this.a + "狮子嗷嗷叫~~~"); // 调用本方法中的属性 System.out.println(a + "猫猫喵喵叫~~~"); } }; tiger.sound(); } } interface IA { void sound(); }
匿名内部类不能添加访问修饰符
class InnerClass { // 外部类 private int a = 10; public void menthod() { // 错误实例 // IA tiger = public new IA() { // private int a = 1; // @Override // public void sound() { // int a = 6; // System.out.println(this.a + "老虎嗷嗷叫~~~"); // } // }; } } interface IA { void sound(); }
匿名内部类意味着没有引用指向它, 所以它只能调用一次,如果要使用多次该匿名内部类,可以直接使用一个引用(
tiger
)指向它就可以了,不过这个也就不叫匿名了。public void menthod() { // 将匿名内部类赋值给tiger IA tiger = new IA() { private int a = 1; @Override public void sound() { int a = 6; System.out.println(this.a + "老虎嗷嗷叫~~~"); } }; tiger.sound(); }
外部其它类不能直接访问匿名内部类
public class AnonymouSinnerClass { public static void main(String[] args) { InnerClass innerClass = new InnerClass(); // 调用匿名内部类所对应的方法或则代码块 // 注意:方法和代码块中要写一个调用匿名内部类的方法 // 否则即使你调用了匿名内部类所对应的方法或则代码块也不会输出什么的 innerClass.menthod(); } } class InnerClass { // 外部类 private int a = 10; public void menthod() { IA tiger = new IA() { private int a = 1; @Override public void sound() { int a = 6; System.out.println(this.a + "老虎嗷嗷叫~~~"); } }; // 当调用方法或则代码块时,则会调用匿名内部类中所对应的方法 tiger.sound(); } } interface IA { void sound(); }
当匿名内部类中的属性名和外部类中的属性名一致时,系统默认按就近原则调用属性,如果想使用外部类中的属性时,则可以使用
外部类名.this.属性名
成员内部类
调用成员内部类
public class Index01 {
public static void main(String[] args){
/*
* 访问成员内部类的几种方法
* */
A1 a1 = new A1();
a1.f2();
// A1.B1表示的是A1类中的内部类B1类,因为B1类不是静态类
// 所以需要创建A1类来引用内部类B1,所以 a1.new B1(); 就是用来创建内部类B1的
A1.B1 b1 = a1.new B1();
// 或者在A1类中创建一个返回B1类的方法
A1.B1 b2 = a1.getF3();
}
}
class A1 {
int a = 30;
String name = "zhangsan";
// 成员内部类:定义在外部类中的内部类
// 成员内部类本身也是一种类,所以可以使用任何的访问修饰符
class B1 {
int a = 20;
int b = 1;
public void f1() {
// 成员内部类也可以调用外部类中的所有成员,包括私有的
// 成员内部类同样遵守就近原则
// 当内部类中的属性名和外部类中的属性名重复时,我们要调用外部类中的属性则可以使用 外部类.this.属性名
int a = 10;
// 输出为 num:20 name:zhangsan b:1
System.out.println("num:" + this.a + " name:" + name + " b:" + b);
// 输出为 num:30
System.out.println("num:" + A1.this.a);
}
}
public void f2() {
B1 b1 = new B1();
// 调用成员内部类
b1.f1();
System.out.println(b1.a);
}
public B1 getF3() {
return new B1();
}
}
静态内部类
静态成员内部类调用外部类中的静态属性时,直接输入 外部类名.属性名
,因为调用的是静态属性,所以不需要加this
public class Index02 {
public static void main(String[] args) {
// 通过创建对象来访问,这里并没有创建X1类对象
// 这里之所以不用创建外部类X1,是因为我们调用的内部类是静态内部类
// 调用一个类中的静态成员是不需要创建该类的
X1.Y1 h1 = new X1.Y1();
h1.m1();
// 通过静态方法返回静态类来访问,这样就不用创建外部类的对象了
X1.Y1 h5 = X1.getF5();
h5.m1();
// 通过返回静态类来访问
X1 a1 = new X1(); // 创建X1类
X1.Y1 y2 = a1.getF4();
// 如果静态内部类中的方法也是静态的,那么可以直接调用,不用重新new一个
X1.Y1.m1();
}
}
class X1 {
public int a = 10;
public static String name = "zhangsan";
// 静态成员内部类本身也是一种类,所以可以使用任何的访问修饰符
public static class Y1 {
static String name = "lisi";
public static void m1() {
// 因为该类是一个静态的成员内部类
// 所以只能调用静态的成员方法,非静态的成员方法则无法访问
System.out.println(name);
// 静态成员内部类调用外部类中的静态属性时,直接输入 外部类名.属性名
// 因为静态内部类只能调用静态的成员方法,所以不需要像以前一样加 this
System.out.println(X1.name);
}
}
public Y1 getF4() {
return new Y1();
}
public static Y1 getF5() {
return new Y1();
}
}
总结:
- 内部类有局部内部类、匿名内部类、成员内部类和静态内部类
- 成员内部类和静态内部类本质是一个类