内部类(inner class)的简单介绍
本文主要介绍内部类(inner class)的一些基本应用,将从内部类的分类角度,首先对每一个具体内部类进行介绍。主要包括普通的内部类【common inner class】、局部内部类[local inner class]、嵌套内部类【nested innner class】、匿名内部类【anonymous inner class】、然后比较一下局部内部类[local inner class]和匿名内部类【anonymous inner class ]的区别,进而知道在具体情况下该选择内部类,即到底用local inner class还是anonymous inner class。最后介绍内部类的应用。
一:首先对每一个具体内部类进行介绍
1.普通的内部类【common inner class】
定义:在一个类里面直接定义一个类:
一些详细情况看代码:
1 package com.qls.comonInnerClass; 2 3 public class A { 4 /** 5 * 从B C D E 这四个普通内部类中可以看出类前面的修饰符可以是 6 * private protected default(也就是什么修饰符没有的D) public. 而在局部内部类中修饰类的只能是: 7 * abstract 或final 或者什么修饰符都没有。 8 * 注意的问题如下: 9 * 1.通常情况下:外部类会有一个返回内部类引用的一个方法如getB()这个方法。 10 * 2.如何在内部类中用this指代外部类引用?【答:外部类名.this 参考第19行代码。】 11 * 以及如何创建内部类的一个实例?【答:x.new B() 其中x是外部类的一个实例,B为一个内部类。 12 * 若是直接写new B()会报错。参考第38、39两行代码。】 13 * 上述两个注意点对其他的内部类也适用。 14 * @author 秦林森 15 * 16 */ 17 private class B { 18 public A outer(){ 19 return A.this;//A.this是指代A的一个引用。 20 } 21 } 22 protected class C{ 23 24 } 25 class D{ 26 27 } 28 public class E{ 29 30 } 31 /** 32 * 返回内部类的引用: 33 */ 34 B getB(){ 35 return new B(); 36 } 37 public static void main(String[] args) { 38 A a = new A(); 39 B b = a.new B(); 40 } 41 }
局部内部类【local innner class】
定义:把类定义在方法里面,或者是方法中的某一个区域中。
代码如下:
1 package com.qls.localInnerClass2; 2 /** 3 * 定义:the creation of an entire class within the scope of a method,or Nesting a class within 4 * a scope of a method. 5 * This is called a local inner class. 6 * 注意情况如下: 7 * 1.局部内部类【local inner class】如果想要修饰的话,只有abstract 和final可以, 8 * 其余的如(public protected)等都不可以。 9 * 2.在局部内部类中只能访问包含该内部类的范围(enclosing scope)的final变量。若不是则会报错。 10 * 11 * @author 秦林森 12 * 13 */ 14 public class A { 15 public void ouyangfeng(){ 16 //把类D定义在方法ouyangfeng()的某个区域中。 17 if(3>2){ 18 class D{ 19 20 } 21 } 22 final class B{ 23 24 } 25 } 26 27 public void sixi(final String s){ 28 int e=1; 29 final int c=8; 30 class C{ 31 /** 32 * 在局部内部类或者匿名内部类中只能访问包含该内部类的范围(enclosing scope)的final变量。 33 * 若不是则会报错。 34 * 如int f=e;编译器报错。 35 */ 36 String str=s; 37 int d=c; 38 // int f=e;//编译器报错。 39 } 40 } 41 public static void main(String[] args) { 42 // TODO Auto-generated method stub 43 44 } 45 46 }
匿名内部类:没有名字的内部类。
下面的代码介绍了以下的内容:
1.匿名内部类实现一个接口,
2.匿名内部类实现一个没有默认构造方法的抽象类
3.匿名内部类和局部内部类一样把参数定义成final,完成字段初始化
4.匿名内部类用普通代码块{}完成初始化,弥补了匿名内部类没有构造方法的缺陷。
代码如下:
package com.qls.anonymouseInnerClass; /** * 匿名内部类(anonymous inner class)一般用在return 语句中。 * 注意情况如下: * 匿名内部类由于没有名字,自然而然也就没有构造方法,其他三种内部类都有构造方法。 * 没有构造方法怎么给对象赋值进行初始化呢?【答:用普通的代码块{},在这个代码块里面实行初始化。】 * @author 秦林森 * */ interface B{ void ouyangfeng(); } abstract class C{ private int i; public C(int i) { this.i=i; } public abstract int value(); } public class A { public B getB(){ //new B(){};就是匿名内部类:用默认的构造方法 return new B() { @Override public void ouyangfeng() { // TODO Auto-generated method stub System.out.println("ouyangfeng is chief village of sixi "); } }; } public C getC(final int i){ //匿名内部类用一个带参数的构造方法 return new C(i) { //用普通代码块实现初始化: { //这里写两个输出语句作为演示。 System.out.println("泗溪"); System.out.println("ouyangfeng"); System.out.println(value());//输出value的值 } @Override public int value() { // TODO Auto-generated method stub return i;//从这里可以看出要想引用i,必须把i定义成final。这和局部内部类一样。 } }; } public static void main(String[] args) { // TODO Auto-generated method stub new A().getC(4);//输出泗溪、ouyangfeng、4 } }
嵌套内部类:
1 package com.qls.nestedClass; 2 /** 3 * 如果你不想让内部类的对象和外部类的对象有如何联系的话,你就可以把内部类定义成static 4 * 嵌套内部类(Nested inner class)的定义:类中关键词static修饰的内部类。 5 * 注意情况如下: 6 * 1.在嵌套内部类中不能访问外部类的非静态变量。 7 * 2.创建内部类变量时,你不想通过创建外部类变量才能创建内部类变量时,你可以把这个内部类定义成static 8 * 即嵌套内部类。 9 * 3.在接口interface中定义的内部类默认都是public static 的,所以在接口中的内部类必是嵌套内部类。 10 * @author 秦林森 11 * 12 */ 13 interface D{ 14 void hello(); 15 class Test implements D{ 16 17 @Override 18 public void hello() { 19 // TODO Auto-generated method stub 20 System.out.println("hello"); 21 } 22 public static void main(String[] args) { 23 /** 24 * 由于Test类默认是public static 的,所以创建Test对象时,不需要通过外部类D, 25 * 所以直接new Test()即可创建Test类中的一个对象。 26 * 话又说回来了,如果在接口中的类不是public static 的那么这个内部类也就是普通的内部类 27 * 在创建Test的对象时,也就需要外部类的对象。关键D是接口,你怎么new 呢? 28 * 所以在的类只能是static 的。 29 */ 30 new Test().hello();//输出hello 31 } 32 } 33 } 34 public class A { 35 int a=9; 36 public static class B{ 37 // int b=a;编译报错 38 void f(){ 39 System.out.println("f()"); 40 } 41 } 42 public static void main(String[] args) { 43 /** 44 * 从这里你看到了,可以对B直接new ,访问B中的函数f(). 45 * 但是如果B没有static这个关键字,即B是普通内部类时,必须这样才能访问到f() 46 * new A().new B().f(); 47 */ 48 new B().f(); 49 } 50 }
二:比较一下局部内部类[local inner class]和匿名内部类【anonymous inner class ]的区别
1.匿名内部类没有构造犯法,二局部内部类有构造方法。
2.如果在一个外部类有两个或两个以上的方法,返回的都是某个接口或者抽象类的引用,建议把写一个局部内部类。若写成匿名内部类时,代码会显得特别冗长。反之如果一个时,建议用匿名内部类。
代码如下:
1 package com.qls.anonymouseInnerClass; 2 interface Six{ 3 void six(); 4 } 5 public class Ouyangfeng { 6 private class SixTest implements Six{ 7 8 @Override 9 public void six() { 10 // TODO Auto-generated method stub 11 12 } 13 14 } 15 public Six f(){ 16 return new SixTest(); 17 } 18 public Six g(){ 19 return new SixTest(); 20 } 21 }
三:内部类的应用:
用内部类实现java的多重继承。
1 package com.qls.anonymouseInnerClass; 2 class D{ 3 4 } 5 abstract class E{ 6 7 } 8 class F extends D{ 9 //这是实现多重继承的核心代码。这里是用一个匿名内部类实现 10 E makeE(){ 11 return new E() { 12 }; 13 } 14 } 15 public class MultipleInherit { 16 public static void takesD(D d){ 17 18 } 19 public static void takesE(E d){ 20 21 } 22 public static void main(String[] args) { 23 // TODO Auto-generated method stub 24 F d = new F(); 25 takesD(d); 26 takesE(d.makeE()); 27 } 28 29 }
最后简要介绍一下让一个类继承另一个类中的内部类?以及怎么让一个类中的内部类继承另一个类的内部类呢?
首先是:让一个类继承另一个类中的内部类
代码如下:
1 package com.qls.anonymouseInnerClass; 2 3 import com.qls.anonymouseInnerClass.WithInner.Inner; 4 5 class WithInner{ 6 class Inner{ 7 private int a; 8 public Inner(int a) { 9 this.a=a; 10 } 11 public Inner() { 12 // TODO Auto-generated constructor stub 13 } 14 } 15 } 16 public class InheritInner extends Inner{ 17 public InheritInner(WithInner withInner) { 18 // TODO Auto-generated constructor stub 19 /** 20 * 这句话必须要写。否则编译器会报错。即:外部类的一个对象.super(). 21 * 这里的super(),比奥斯Inner的一个默认构造方法。 22 * 如果Inner中比如有这样一个构造方法:public Inner(int a) 23 * 你现在也可以写成:把withInner.super();改为withInner.super(1);编译器是不会报错的。 24 * 如果没有默认构造方法public Inner() 则这题必须写成:withInner.super(1);的形式。 25 */ 26 27 withInner.super(); 28 } 29 public static void main(String[] args) { 30 // TODO Auto-generated method stub 31 WithInner withInner = new WithInner(); 32 InheritInner inheritInner = new InheritInner(withInner); 33 } 34 35 }
让一个类中的内部类继承另一个类的内部类
代码如下:
1 package com.qls.anonymouseInnerClass; 2 /** 3 * 朱元璋家住凤阳,刘伯温家住青田 4 * @author 秦林森 5 * 6 */ 7 class ZhuYuanZhang{ 8 class FengYang{ 9 private String location; 10 11 public FengYang(String location) { 12 this.location = location; 13 } 14 15 } 16 } 17 class LiuBoWei{ 18 class QingTian extends ZhuYuanZhang.FengYang{ 19 private String location; 20 public QingTian(ZhuYuanZhang zhuYuanZhang, String location) { 21 zhuYuanZhang.super(location);//这句话必须要写。或者会报错, 22 this.location=location; 23 } 24 public void accurate(){ 25 System.out.println("一统江山刘伯温 ,家在"+location); 26 } 27 } 28 } 29 public class Test { 30 31 public static void main(String[] args) { 32 // TODO Auto-generated method stub 33 new LiuBoWei().new QingTian(new ZhuYuanZhang(), "青田").accurate(); 34 } 35 36 }/*Output: 37 一统江山刘伯温 ,家在青田*///:~