本文最后更新于:2021年9月28日 晚上
概览:Java内部类:静态内部类、局部内部类和匿名内部类。
2021/07/25
内部类
就是类的定义位于外部类
之内,它与外部类的属性
、方法
并列。
内部类分别有:
成员内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public class MemberInnerClass {
private int id = 1; private static int sex = 0;
public MemberInnerClass(int id) { this.id = id; }
public void printInfo() { System.out.println("Outer class info: " + id + ", " + sex); }
public static void printSex() { System.out.println("Outer class static info: " + sex); }
class InnerClass1 { private int one = 1; public int two = 2;
public InnerClass1(int one, int two) { this.one = one; this.two = two; }
public void publicFunc() { System.out.println("Inner class public func"); System.out.println("one,two " + one + two); System.out.println("Outer member: " + id); System.out.println("Outer static member: " + sex); printSex(); printInfo(); } }
public void testInnerClass() { InnerClass1 inner = new InnerClass1(1, 2); inner.publicFunc(); } }
public class MemberInnerClassTest {
public static void main(String[] args) { MemberInnerClass outer = new MemberInnerClass(1); MemberInnerClass.InnerClass1 inner1 = outer.new InnerClass1(1, 2);
inner1.publicFunc(); } }
|
特点:
- 成员内部类中不能够书写静态的属性和方法!
- 成员内部类可以访问外部类的属性和方法,包括私有的、静态的!
- 访问静态的直接通过
变量名
或者外部类.变量名
的方式调用。
- 访问普通的成员直接通过
变量名
或者外部类.this.变量名
的方式调用。
- 关于在类外创建内部类对象,需要注意特殊写法,
外部类对象.new 内部类()
。
- 内部类是一个编译时的概念,一旦编译成功,就会称为两个不同的类,例如上述的例子中,最终生成了
MemberInnerClass.class
和MemberInnerClass$InnerClass1.class
。
内部类能够访问外部类的原因在于,在通过外部类对象来访问内部类对象时,外部类对象会将自己的引用传递给内部类,内部类可以通过Outer.this
的方式来调用外部类的属性和方法。
作用:
- 用成员内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private还要小的访问权限。
- 数据安全。如果我们的内部类不想轻易被任何人访问,可以选择使用private修饰内部类,这样我们就无法通过创建对象的途径来访问,想要访问只需要在外部类中定义一个public修饰的方法,间接调用。
静态内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public class StaticInnerClass {
private int id = 1; private static int sex = 0;
public StaticInnerClass(int id) { this.id = id; }
public void printInfo() { System.out.println("Outer class info: " + id + ", " + sex); }
public static void printSex() { System.out.println("Outer class static info: " + sex); }
static class InnerClass{ private int id = 100; private static int sex = 1;
public InnerClass(int id) { this.id = id; }
public static void printSexAndOuter(){ System.out.println("Inner class static info: " + sex); System.out.println("Outer class static info: " + StaticInnerClass.sex); } public void printInfo(){ System.out.println("Inner class: " + id); System.out.println("Inner class: " + sex); System.out.println("Outer class: " + StaticInnerClass.sex); } } }
public class StaticInnerClassTest { public static void main(String[] args) { StaticInnerClass outer = new StaticInnerClass(10); StaticInnerClass.InnerClass inner = new StaticInnerClass.InnerClass(100);
inner.printInfo(); StaticInnerClass.InnerClass.printSexAndOuter(); } }
|
特点:
- 静态内部类可以声明静态的成员和方法。而成员内部类则不可以。
- 和常规相同,static中没有this指针,static方法不能访问普通的成员变量。
- 注意内部类对象声明的写法,和成员内部类不同。
- 编译生成的文件和成员内部类相同。
作用:
- 提供调试作用。我将main方法写在静态内部类中,生成.class文件后,调试代码在静态内部类当中,当我删除静态内部类后,其他人仍然可以使用我的外部类。👍
局部内部类
- 局部内部类是一个在方法的内部声明的类。
- 局部内部类可以访问外部类的成员变量以及方法。
- 局部内部类中如果要访问该内部类所在方法中的局部变量,那么这个局部变量就必须是final修饰的。
- 不过从Java8开始,只要局部变量没有发生过改变,也是不会报错的~
- final修饰变量:变为常量,会在常量池中放着,逆向思维想这个问题,如果不使用final修饰,当局部内部类被实例化后,方法弹栈,局部变量随着跟着消失,这个时候局部内部类对象再想去调用该局部变量,就会报错,因为该局部变量已经没了,当局部变量用final修饰后,就会将其加入常量池中,即使方法弹栈了,该局部变量还在常量池中呆着,局部内部类也就是够调用。所以局部内部类想要调用局部变量时,需要使用final修饰,不使用,编译通不过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class LocalInnerClass {
private int id = 1; private static int sex = 0;
public LocalInnerClass(int id) { this.id = id; }
public void printInfo() { System.out.println("Outer class info: " + id + ", " + sex); }
public static void printSex() { System.out.println("Outer class static info: " + sex); }
public void localFunc() { int id = 10; class InnerClass { public void printInfo() { System.out.println("local inner id: " + id); System.out.println("outer: " + LocalInnerClass.this.id + "," + LocalInnerClass.sex); } }
InnerClass inner = new InnerClass(); inner.printInfo(); } }
public class LocalInnerClassTest { public static void main(String[] args) { LocalInnerClass outer = new LocalInnerClass(1); outer.printInfo();
outer.localFunc(); } }
Outer class info: 1, 0 local inner id:10 outer: 10
|
特点:
- 局部内部类不需要也不能通过外部类对象直接实例化,它只能在其所在方法中实例化自己。
- 局部内部类只能用于那个方法之中,相当于一份局部变量,但是!局部内部类可以访问所在类的属性和方法。
作用:
- 局部内部类只能在所在的方法体作用域中进行实例化,如果有想要所在方法返回这个类,就要通过接口的向上转型操作!在某些情况下,某些业务逻辑需要临时处理,这些业务逻辑只在这里使用又可以封装成一个类的话,而又没必要重新建个文件,所以可以这写一个局部内部类来处理。java代理模式中可能有用到局部内部类,在方法中直接实现接口,返回代理对象,简单而又方便。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| interface Innerface{ public void inner(); }
public class ReturnLocalInnerClass { public Innerface work(){
class InnerClass implements Innerface{
@Override public void inner() { System.out.println("Inner implement innerface"); } } return new InnerClass(); }
}
public class ReturnLocalInnerClassTest { public static void main(String[] args) { ReturnLocalInnerClass outer = new ReturnLocalInnerClass(); Innerface inner = outer.work(); inner.inner(); } }
|
匿名内部类
- 类似于匿名对象,仅当需要时使用一次,作为临时实现的内部类。
- 本质上是一个继承了类或者实现了接口的子类匿名对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class OnceClass{ public void printInfo(String info){ System.out.println("Only once info: " + info); } private void printInfoPrv(String info){ System.out.println("Only once info with private: " + info); } }
public class AnonInnerClass { private String name;
public AnonInnerClass(String name) { this.name = name; }
public void work(){ System.out.println("AnonInnerClass work"); new OnceClass().printInfo(this.name); } }
public class AnonInnerClassTest { public static void main(String[] args) { AnonInnerClass outer = new AnonInnerClass("Bob"); outer.work(); } }
|
特点:
- 匿名内部类需要依托其他类或者接口来创建。如果依托于类,那么就是这个类的子类,如果依托于接口,那就是这个接口的实现类。
- 匿名内部类除了依托的类或接口之外,不能指定继承或者实现其他类或接口,同时也不能被其他类所继承,因为没有名字。
- 匿名内部类的创建只能是使用new关键字,可以
new 类名/接口名字(){ 重写func();}.func()
这样的形式。
作用:
- 如果某些方法仅仅会被调用一次,那么就可以使用匿名内部类进行格式简化。某些方法参数提示是抽象类或者接口作为参数,此时就可以提供一个对象的子类对象。例如
Thread
的构造方法中有一种需要传入Runnable接口参数的方法。
为什么使用内部类
1 实现封装性
通过内部类来进一步封装一个类内部的属性,如果不想要内部类轻易被访问,那么可以通过加private修饰符来达到效果,这样就不能通过实例化内部类对象的方式来访问内容,只能通过外部类提供的接口来访问。
2 实现回调功能
可以编写一个接口,然后实现那个接口,再将接口按照一个对象当作参数的形式传递给另一个方法中,然后通过这个接口实例化的对象来调用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| interface CallBack{ void callBackFunc(); }
public class InnerClassCallBack { public void func(CallBack call){ System.out.println("Callback is running"); call.callBackFunc(); }
public static void main(String[] args) { InnerClassCallBack iccb = new InnerClassCallBack(); iccb.func(new CallBack() { @Override public void callBackFunc() { System.out.println("callbackfunc is running"); } }); } }
|
To Be Continue
参考链接:https://blog.csdn.net/weixin_45039616/article/details/105289452
https://blog.csdn.net/Hacker_ZhiDian/article/details/82193100