您的位置:首页 > 编程语言 > Java开发

JAVA学习脚印9:外部类与嵌套类

2013-09-14 10:37 507 查看

JAVA学习脚印9:外部类与嵌套类

本节要点

为什么使用嵌套类?

外部类与嵌套类的定义、嵌套类的分类?

嵌套类的特性有哪些?

内部类的分类及每种内部类的特性有哪些?

外部类与嵌套类是java语言中一个稍显繁琐的知识点,但确实又带来很多便利之处。
嵌套类可以从逻辑上只对一个类有用的类嵌入在这个外部类的里面,从而把这两个类放在一起;同时嵌套类提高了封装性,嵌套类可以在访问外部类的成员的的同时对外部不可见;另外嵌套类可以增强可读性,便于代码的维护。因此java语言使用这一特性来优化编程。

1.外部类(enclosingclass)与嵌套类(nestedclasses)的定义

java语言中允许这样定义类:

classOuterClass {
...
staticclass StaticNestedClass {
...
}
classInnerClass {
...
}
}


上述OuterClass被称为外部类,而StaticNestedClass和InnerClass称为嵌套类。嵌套类是外部类的成员,因此可以声明可以为private,public,protected,或者packageprivate。嵌套类有两种,静态和非静态的。声明为静态的嵌套类即为静态嵌套类StaticNestedClass,非静态的嵌套类称为内部类如InnerClass。

2.静态嵌套类

静态嵌套类是和外部类相关联的,它不可以直接访问外部类的成员变量和方法,只能通过对象引用来访问。静态嵌套类可以通过外部类的名字来访问,例如:
OuterClass.StaticNestedClass
要创建静态嵌套类,使用语法格式使用为:
OuterClass.StaticNestedClassnestedObject = new OuterClass.StaticNestedClass();
例如: java.awt.geom.Rectangle2D抽象类内部定义了两个静态嵌套类Float和Double用于构造不同数据类型的三角形。

publicabstract class Rectangle2D extends RectangularShape {

publicstatic class Float extends Rectangle2D implements Serializable {
...
}
publicstatic class Double extends Rectangle2D implements Serializable {
...
}
}


3.内部类

内部类一般声明在一个类中,与类中的方法成为并列的块,也可以声明在类的方法体中。
在方法体中声明的内部类,即为局部类;在方法体中声明的没有名称的内部类,即为匿名内部类。

1)内部类一般特性

特性之一:内部类必须与外部类实例关联,且可以直接访问外部类实例的方法和域
内部类和外部类的一个实例关联,内部类的实例只能在外部类的实例存在时才能存在,它可以直接访问该对象的方法和域,即使它们被声明为private。内部类通过OuterClass.this来访问外部类的成员。
创建内部类对象的语法格式如下:
OuterClass.InnerClassinnerObject = outerObject.new InnerClass();

特性之二:内部类不能定义自己的任何静态成员
内部类和外部类的实例相关,因此不能定义自己的静态成员。因为静态成员在类加载类时即被确定,而此时是还未创建外部类的实例,因此内部类不可以有静态成员。
下面是使用内部类的一个典型例子:

package com.learningjava;
/**
* a program to demonstrate using innerclass.

* from :http://docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html

*/
public class DataStructure {

public static void main(String s[]) {

// fill the array with integervalues and print out only

// values of even indices

DataStructure ds = newDataStructure();

ds.printEven();

}

// create an array

private final static int SIZE = 15;

private int[] arrayOfInts = newint[SIZE];

public DataStructure() {

// fill the array withascending integer values

for (int i = 0; i < SIZE;i++) {

arrayOfInts[i] = i;

}

}

public void printEven() {

// print out values of evenindices of the array

InnerEvenIterator iterator =this.new InnerEvenIterator();

while (iterator.hasNext()) {

System.out.println(iterator.getNext() + " ");

}

}

// inner class implements theIterator pattern

private class InnerEvenIterator {

// start stepping through thearray from the beginning

private int next = 0;

public boolean hasNext() {

// check if a currentelement is the last in the array

return (next <= SIZE -1);

}

public int getNext() {

// record a value of aneven index of the array

int retValue =arrayOfInts[next];

//get the next even element

next += 2;

return retValue;

}

}

}


2)局部类特性

特性之一:局部类可以访问局部变量,但是目前版本要求局部类只能访问声明为final的局部变量,也许在javase 8版本中会得到改进。同时局部类也不能定义或者声明任何静态成员。
代码1:局部类只能访问局部常量

publicclass LocalClassTest {

publicstatic void main(String[] args) {

LocalClassTesttest = new LocalClassTest();

test.sayGoodbyeTo("Tom");

}

publicvoid sayGoodbyeTo(final String name) {

classEnglishGoodbye {

publicvoid sayGoodbye() {

System.out.println( "Byebye"+","+name);

}
}

EnglishGoodbyemyEnglishGoodbye = new EnglishGoodbye();

myEnglishGoodbye.sayGoodbye();

}

}


这里局部变量name声明为finalString name则可以在局部类中访问,否则提示错误信息如下:
Cannotrefer to a non-final variable name inside an inner class defined in adifferent method

特性之二:在静态方法中声明的局部类,只能访问外部类的静态成员。

特性之三:局部类可以访问包围它的块的实例成员,它不是静态的;因此,在局部类里面不能包含大部分种类的静态声明,但是局部类可以声明静态常量域。接口与生俱来即为静态的,因此在块中不能声明接口。

代码2:代码块中不能定义接口,接口与生俱来即为static.

public void greetInEnglish() {
interface HelloThere {
public void greet();
}
class EnglishHelloThere implements HelloThere {
public void greet() {
System.out.println("Hello " + name);
}
}
HelloThere myGreeting = new EnglishHelloThere();
myGreeting.greet();
}


将不能通过编译,因为greetInEnglish()方法中不允许声明接口HelloThere;

代码3:局部类不允许声明静态方法

public void sayGoodbyeInEnglish() {
class EnglishGoodbye {
public static void sayGoodbye() {
System.out.println("Bye bye");
}
}
EnglishGoodbye.sayGoodbye();
}


将不能通过编译,因为局部类不允许声明静态方法,开发环境提示错误信息如下:
Themethod sayGoodbye cannot be declared static; static methods can onlybe declared in a static or top level type 。

代码4:局部类允许声明静态常量域可以通过编译,因为farewell被声明为静态常量。

publicclass LocalClassTest {

publicstatic void main(String[] args) {

LocalClassTesttest = new LocalClassTest();

test.sayGoodbyeInEnglish();//printBye bye

}

publicvoid sayGoodbyeInEnglish() {

classEnglishGoodbye {

publicstatic final String farewell = "Bye bye";//ok

publicvoid sayGoodbye() {

System.out.println(farewell);

}

}

EnglishGoodbyemyEnglishGoodbye = new EnglishGoodbye();

myEnglishGoodbye.sayGoodbye();

}

}


3)匿名内部类特性

匿名内部类可以使你的代码更简洁,它允许你在声明一个类的同时实例化该类。它与局部类的差别在于它是没有名字的类,局部类有类的声明而匿名内部类则是一个表达式。如果你一个局部类你仅使用一次,那么就可以使用匿名内部类。匿名内部类有如下特性:

特性之一:匿名内部类可以访问外部类的成员,也可以访问声明为常量的局部变量。

特性之二:在匿名内部类里面同样不能声明静态初始化代码段和接口,但可以持有静态常量域。

特性之三:在匿名内部类在里面在可以在声明在域、额外的方法、局部类;但是不可以定义构造器。

下面是使用匿名内部类用于处理GUI事件的典型例子:

packagecom.learningjava;

importjava.awt.*;

importjava.awt.event.*;

importjavax.swing.*;

/**

*a program to demonstrate using anonymous class

*@author wangdq

*2013-09-14

*/

publicclass AnonymousClassTest {

publicstatic void main(String[] args) {

TestFrameframe = new TestFrame();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setVisible(true);

}

}

/**

*a frame with a button to change the background color of the panel

*/

classTestFrame extends JFrame {

publicTestFrame() {

this.setTitle("AnonymousClassTest");

this.setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);

panel= new JPanel();

JButtonbutton = new JButton("Change background color");

//declarea annonymous class and instantiate it

button.addActionListener(newActionListener(){

@Override

publicvoid actionPerformed(ActionEvent e) {

intred = (int) (Math.random()*255) ;

intgreen = (int) (Math.random()*255) ;

intblue = (int) (Math.random()*255) ;

ColorbgColor = new Color (red,green,blue);

panel.setBackground(bgColor);

}

});

this.add(panel,BorderLayout.CENTER);

panel.add(button);

}

privateJPanel panel;

privatefinal int DEFAULT_WIDTH = 300;

privatefinal int DEFAULT_HEIGHT = 300;

privatestatic final long serialVersionUID = 1L;

}


在这个例子中,button.addActionListener()方法需要一个实现了ActionListener接口(ActionListener接口声明为:publicinterface ActionListener extendsEventListener)的类的一个实例,我们使用匿名内部类使用来使用完成了使用此项功能。这段代码等价于:

step1:先声明一个类

classButtonListener implements ActionListener {

publicButtonListener(JPanel panel) {

this.panel= panel;

}

@Override

publicvoid actionPerformed(ActionEvent e) {

//TODO Auto-generated method stub

intred = (int) (Math.random()*255) ;

intgreen = (int) (Math.random()*255) ;

intblue = (int) (Math.random()*255) ;

ColorbgColor = new Color (red,green,blue);

panel.setBackground(bgColor);

}

privateJPanel panel;

}


step2:再创建一个实例并传递给addActionListener方法。

button.addActionListener(newButtonListener(panel));


由此可见匿名内部类简化了代码,使用很方便。

java嵌套类的理解,尤其是这些细微的差别,个人感觉更需要在实际开发中去体会。

参考资料: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 内部类