java神奇的内部类
java神技の内部类
java内部类,顾名思义所谓内部类即为定义在其他类中的类。然而看似简单的解释,却实现了很强大的功能,当然也让人理解起来不是那么的容易,针对内部类的很多条条框框让人很难理解,不夸张的说甚至会造成混乱,为了消除这一混乱只需将内部类看做外部类的一个“属性”或者一个“方法”。(我在学习内部类时就是这么考虑的)如果你用这种方式来思考内部类,你会发现你可以很容易理解何为内部类。所以在下面的内容中我也是按照这一思想来描述何为内部类的(以下内容皆为愚见,如有纰漏望请告知,在此将不胜感激)。
首先:java内部类的种类:成员内部类、静态内部类、方法内部类、匿名内部类(来自Thinking in Java),按照顺序将每一种内部类进行一小段的描述。
1、成员内部类
就好比在一个类中定义一个成员变量一样,只不过在使用此变量是需要“创建一下这个变量”而已,就像上面描述的那样“只需将内部类看做外部类的一个属性或一个方法”。其定义方式如下:
//代码
//外部类
class OuterClass
{
//内部类
class InnerClass
{
public void method_01()
{
System.out.println("method_01");
}
}
public InnerClass getInner()
{
//外部类非static 方法创建内部类方式
return new InnerClass();
}
public static void main(String[] args)
{
//外部类static方法创建内部类
OuterClass outer = new OuterClass();
InnerClass inner = outer.new OuterClass();
}
}
从上面简短的例子中,我们可以看到内部类是如何定义的,方式很简单,跟定义其他类没什么两样,只不过是将此类定义到了其他类的内部。
这样我们就定义了一个类名称为InnerClass 的内部类,接着就是如何使用、创建内部类的问题了。创建内部类主要有两种情况,也可以说按照创建内部类的位置(or scope)而产生的两种实例化对象方式:其一为在外部类内非static方法内创建内部类方式;其二为在外部类内的static方法中(或外部类以外的环境下)创建内部类方式。如何理解者为什么要分两种方式来创建内部?要理解其原因还需要上面的思想(将内部类看做外部类的一个“属性”或者一个“方法”),当以第一种方式创建内部类时,内部类作为外部类的一个组成部分,可以说是一个属性或一个方法时,内部类非静态方法调用时直接调用就可以了。然而要是用第二种方式实例化内部类时,首先考虑如果在一个类中的静态方法如何访问类中的非静态成员变量的问题,这个问题中,首先我们必须在静态方法中实例化一个该类的对象,之后用该对象的引用去调用非静态成员,同样的道理,既然将内部类看成为外部类的一个成员,那么在静态方法中我们只能够先实例化外部类 对象之后通过外部类的引用 来new 我们的内部类了(如代码所示),由此也说明在拥有外部类对象之前是不可能创建内部类的(静态内部类除外)
接下来是内部类的访问权限问题,如果在一个类中定义一个方法(非抽象的),那么是否在此方法内可以调用任何该类中的属性和方法(不论private还是public)呢? 答案是肯定的。这个在java基础中的权限控制中已经明确说了在此就不多加赘述了。根据先前的思想,所以内部类内同样可以访问外部类的所有方法(非抽象)及成员。其访问方式如下:
//代码---我们需要改良一下我们的内部类
//内部类
class OuterClass
{
private String name = "outer property";
//内部类
class InnerClass
{
public void method_01()
{
System.out.println("method_01" + name); //可以直接的调用外部类中的属性
}
}
public InnerClass getInner()
{
//外部类非static 方法创建内部类方式
return new InnerClass();
}
public static void main(String[] args)
{
//外部类static方法创建内部类
OuterClass outer = new OuterClass();
InnerClass inner = outer.new OuterClass();
}
}
当然我们也可以通过在内部类中定义一个和外部类同名的属性,这样就可以覆盖外部类中的属性访问了。这个时候如果我们还需要访问外部类的同名属性时,只需通过OuterClass.this.propertyName就可以了。通过上述例子说明内部类拥有其外部类的所有元素的访问权(java中的迭代器设计模式也是通过此思想来进行设计的)。在这里略加介绍一下java中的迭代器模式,其主要思想是让内部类实现迭代器接口 Iterator,并将内部类设置成private,其目的是将具体实现进行封装及隐藏,之后再外部类中提供一个可以获取内部类实例的方法iterator();程序用户通过此方法获取一个可以无条件访问外部类所有元素的内部类实例,之后通过堆内部类的设计就实现了对外部类的访问。这样,private内部类给类的设计者也提供了一种途径,通过此种方式可以完全阻止任何依赖于类型的编码,并且完全隐藏了实现的细节(完全符合java开发与设计的理念)。
2、静态内部类
在上面讲述成员内部类时略微的介绍了一个下静态内部类,其实很明了,就是将内部类定义成static,也称嵌套类。可以这样理解,普通的内部类对象隐式的保存了一个引用,指向创建他的外围对象,然而嵌套类则意味着:(1)要创建嵌套类对象,并不需要其外围类的对象;(2)不能从嵌套类的对象中方为非静态的外围类对象(源自Thinking in java )。其实很容易理解,可以将静态内部类看成外部类的一个静态方法,这样上面提到的两个问题就都能很多好的理解了。
3、方法内部类
方法内部类就是在方法中定义的类(这句话似乎说的是废话一样),方法内部类将此类型的内部类的创建局限在了该方法内,可以将其理解为定义在该方法内的一个局部变量,只不过该局部变量在使用时需要被实例化一下而已,这样的内部类有区域的限制(can not be out of scope),当然也提供了一个很好的封装,如果只是单一的提供某种功能,且此功能不想让其他区域访问,那么采用方法内部类是一种不错的选择。
4、匿名内部类
匿名内部类俗称没有名字的内部类(又称随父命名的类),匿名内部类的定义与实例化过程基本上是同时发生的(谬论),当然是先定义后实例化,只不过在显示上给人以错觉,因为其实例化的代码与定义的代码在同一处,所以任何匿名内部类的代码只能实例化一个对象,定义过程如下:
interface InnerClass02
{
}
class OuterClass{
public InnerClass02 getIner(){
return new InnerClass02(){
//实现基类或接口的方法
};
}
}
这里面InnerClass02为匿名内部类的接口或父类,引起没有子类的名字,所以称为匿名内部类,这样的内部类与正规的继承相比有些受限,因为匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备,而且要是实现接口,也只能够实现一个接口(鱼与熊掌啊)。
总结:
1、从多层嵌套类中访问外部类的成员
一个内部类被嵌套了多少层并不重要——他能透明的访问所有他所嵌入的外围类的所有成员。
class OuterClass{
private String outerProperty ;
class InnerClassA{
private String innerPorpertyA;
class InnerClassB{
public void print(){
System.out.println(outerProperty);
System.out.println(innerPorpertyA);
}
}
}
public static void main(String args[])
{
OuterClass outer = new OuterClass();
OuterClass.InnerClassA innerA = outer.new InnerClassA();
OuterClass.InnerClassA.InnerClassB innerb = innerA.new InnerClassB();
innerb.print();
}
}
在访问内部类时只需 OuterClass.InnerClassA.InnerClassB 的结构方式即可,即多层次内部类嵌套式,由外部类穿件内部类方式:逐级new的方式创建。
2、为什么需要内部类
至此,我们已经看到了许多描述内部类的语法和语义,但是并不能回答“为什么需要内部类”这个问题,那么SUN公司为什么会如此费心的增加这项基本的语言特性呢?其原因也是内部类最吸引人的是:每个内部类都能独立继承自一个(接口的)实现,所以无论外部类是否已经继承类某个(接口的)实现,对于内部类都是没有影响的(Thinking in Java)。其实质上是说内部类的出现很好的解决了java中不能多继承的问题。
阅读(1735) | 评论(0) | 转发(0) |