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学习脚印 :日志文件的使用
- java学习脚印:xml中空白文本结点(whitespace TextNode)处理及验证方法
- java学习脚印: JTree序列化(Swing组件运用敏捷版)
- JAVA学习脚印4: 对象与类的概念
- JAVA学习脚印11: java GUI 发展简史
- java学习脚印:深入java绘图机制
- java学习脚印:集合(Collection)之算法
- java学习脚印:Class类与反射机制
- java学习脚印 : 错误列表 Errorlist
- java学习脚印:深入java绘图机制
- java学习脚印:java工具早使用——Maven与Junit
- JAVA学习脚印 :日志文件的使用
- Java学习之路:脚踏实地,一步一个脚印
- JAVA学习脚印10:解惑java 中UTF-16与char
- Java基础知识学习笔记——嵌套类(Nested Classes)
- java基础学习总结—— java外部类与内部类的关系
- JAVA学习脚印 1:开篇——初识java语言及开发环境
- JAVA学习脚印5: 继承特性及特殊类
- java学习脚印: 泛型(Generic)认识之一
- java学习脚印:几种迭代方式