为什么要使用内部类?
我们知道一个类可以继承多个接口,但是不能继承多个类,而使用内部类可以实现多重继承
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。(摘自《Think in java》)
成员内部类
成员内部类即定义在另一个类的内部的类
1、内部类可以任意访问外部类的成员(内部类1 不可以直接访问 内部类2 的成员)
2、外部类访问内部类成员需要先创建内部类对象
3、成员内部类依赖于外部类,所以要先创建外部类才可以创建成员内部类,详见 Main()
4、建议在外部类中提供访问内部类成员的接口
1 package innerclass; 2 3 public class Main { 4 public static void main(String[] args) { 5 // 成员内部类依赖外部类存在,要实例化内部类,必须存在外部类对象 6 // 方法1: 7 OuterClass outer = new OuterClass(); 8 OuterClass.InnerClass inner1 = outer.new InnerClass(); 9 // 方法2: 10 OuterClass.InnerClass inner2 = outer.getInnerClass(); 11 12 // 通过外部类提供的接口访问内部内方法 13 outer.getInnerFun(); 14 } 15 } 16 17 class OuterClass { 18 private int id = 1; 19 String name = "外部类"; 20 21 private InnerClass inner = null; 22 23 public void fun() { 24 //外部类访问内部类成员,必须创建内部类对象,通过指向对象的引用来访问 25 InnerClass inCls = new InnerClass(); 26 System.out.println(inCls.name); 27 inCls.innerFun(); 28 } 29 30 // 用于对外访问内部类 31 public InnerClass getInnerClass() { 32 if (inner == null) { 33 inner = new InnerClass(); 34 } 35 return inner; 36 } 37 38 // 建议在外部类中提供对外访问内部内成员的方法 39 public void getInnerFun() { 40 new InnerClass().innerFun(); 41 } 42 43 class InnerClass { 44 private String name = "内部类"; 45 46 private void innerFun() { 47 // 成员重名时,外部的将被屏蔽 48 System.out.println(name); 49 // 访问外部类重名属性 50 System.out.println(OuterClass.this.name); 51 System.out.println("id = " + id); 52 } 53 } 54 }View Code
静态内部类
在定义内部类时添加 static 关键字。
1、静态内部类不依赖与外部类可直接创建
2、静态内部类不可以访问外部类的非 static 成员(因为在不创建外部类的情况下可以创建静态内部类,如果可以访问外部类的非static成员则产生冲突)
1 public class Main { 2 public static void main(String[] args) { 3 OuterClass.InnerClass inner = new OuterClass.InnerClass(); 4 inner.fun(); 5 } 6 } 7 8 class OuterClass { 9 private static String name = "OuterClass"; 10 11 static class InnerClass { 12 void fun() { 13 System.out.println(name + ".InnerClass.fun()"); 14 } 15 } 16 }View Code
局部内部类
局部内部类的访问仅限于方法内或者该作用域内
1 class Cls { 2 String ClsName = "Cls"; 3 4 public void fun(String str) { 5 String funName = "fun"; 6 class InnerCls { 7 void innerFun() { 8 ClsName = "c"; 9 System.out.println(ClsName); 10 11 // funName = "f"; 12 // str = "s"; 13 // 以上为final对象不可直接修改 14 System.out.println(funName); 15 System.out.println(str); 16 } 17 } 18 new InnerCls().innerFun(); 19 } 20 }View Code
从内部类(局部内部类或匿名内部类)引用的本地变量必须是final变量或实际上的 final 变量
因为局部变量的生命周期与局部内部类的对象的生命周期的可能不一致性,从而导致变量值可能的不一致
(JDK1.8之后会隐式加上 final,只有在修改上述变量时才会报错)
匿名内部类
上图代码摘自百度百科,这既不匿名,也看不出内部,为什么叫匿名内部类?
使用场景
1、只用到类的一个实例
2、类在定义后马上用到
3、类非常小(SUN推荐是在4行代码以下)
4、给类命名并不会导致你的代码更容易被理解
特点
1、匿名内部类不能有构造方法
2、匿名内部类不能定义任何静态成员、静态方法
3、匿名内部类不能是public,protected,private,static
4、只能创建匿名内部类的一个实例
5、一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类
6、因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效
匿名内部类写法:
1 package innerclass; 2 3 public class Main { 4 public static void main(String[] args) { 5 new IFS() { 6 @Override 7 public void IFun() { 8 System.out.println("接口式匿名内部类"); 9 } 10 }.IFun(); 11 12 new Cls1() { 13 @Override 14 void CFun1() { 15 System.out.println("继承式匿名内部类"); 16 } 17 }.CFun1(); 18 19 //方法的参数为接口或类 20 new Cls2().CFun2(new IFS() { 21 @Override 22 public void IFun() { 23 System.out.println("参数式匿名内部类"); 24 } 25 }); 26 27 } 28 } 29 30 interface IFS { 31 public void IFun(); 32 } 33 class Cls1 { 34 void CFun1() { 35 } 36 } 37 class Cls2 { 38 //参数可以是接口、抽象类、普通类 39 void CFun2(IFS ifs) { 40 ifs.IFun(); 41 } 42 }View Code
参考资料
https://www.cnblogs.com/chenssy/p/3388487.html ——chenssy
https://www.cnblogs.com/dolphin0520/p/3811445.html ——Matrix海子
https://www.cnblogs.com/wfq9330/p/8760031.html ——爱养花的码农
https://baike.baidu.com/item/java%E5%86%85%E9%83%A8%E7%B1%BB/2292692?fr=aladdin#4 ——百度百科
public static void main(String[] args) { OuterClass.InnerClass inner = new OuterClass.InnerClass(); inner.fun(); }}
class OuterClass { private static String name = "OuterClass";
static class InnerClass { void fun() { System.out.println(name + ".InnerClass.fun()"); } }}