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嵌套类的理解,尤其是这些细微的差别,个人感觉更需要在实际开发中去体会。

参考资料: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值