JAVA学习脚印9:外部类与嵌套类
Posted The fool
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA学习脚印9:外部类与嵌套类相关的知识,希望对你有一定的参考价值。
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嵌套类的理解,尤其是这些细微的差别,个人感觉更需要在实际开发中去体会。
以上是关于JAVA学习脚印9:外部类与嵌套类的主要内容,如果未能解决你的问题,请参考以下文章