内部类简介(包括在Swing中的实例应用)

  • Post author:
  • Post category:其他


各种介绍语法的程序书上经常出现内部类InnerClass,尽管语法上并不复杂,但如果没有实际例子供参考的话,在概念上比较难以理解,也难以体会到内部类的精妙之处。

希望这篇博文能帮助你更好地理解内部类 ^_^

一个非常常见的例子:你要在JavaSwing里加一个按钮,点击按钮触发事件。

你知道要触发按钮的事件ActionEvent,就得实现ActionListener接口。通过addActionListener(this)来监听。在事件发生时调用ActionListener接口里的actionPerformed方法。

示意代码:(在页面上加一个按钮,点击按钮显示Hello)

import javax.swing.*;
import java.awt.event.*;

public class SimpleGui implements ActionListener {	//需要ActionListener接口
	JButton button;
	public static void main (String[] args) {
		SimpleGui gui = new SimpleGui();
		gui.go();
	}

	public void go() {
		... 
		button = new JButton("Click me");	//new一个Swing的按钮
		button.addActionListener(this);		//按钮绑定事件
		... 
	}

	//实现ActionListener接口内的actionPerformed方法,点击按钮会显示Hello
	public void actionPerformed(ActionEvent event) {
		button.setText("Hello");
	}
}

上面这段代码可以达到目的,但显然不会有人这样去做。因为如果页面上需要多个按钮呢?你无法为接口里的actionPerformed方法提供多个实现。

比如,页面上有两个按钮,点击一个按钮显示hello,点击另一个按钮显示world:

public class SimpleGui implements ActionListener {
	JButton button1;    //两个按钮
	JButton button2;
	...
        public static void main (String[] args) {
		SimpleGui gui = new SimpleGui();
		gui.go();
	}

	public void go() {
		... 
		button1 = new JButton("Click me");  //new一个Swing的按钮
		button.addActionListener(this);
		button2 = new JButton("Click me2"); //再new一个Swing的按钮
		button2.addActionListener(this);
		... 
	}
	
	public void actionPerformed(ActionEvent event) {
		//how???你无法为一个方法提供多个实现
	}
}

或许你会这样来实现actionPerformed方法,以达到点击一个按钮显示hello,点击另一个按钮显示world的目的:

public void actionPerformed(ActionEvent event) {
	if (event.getSource() == button1) {
		button1.setText("Hello");
	} else if (event.getSource() == button2) {
		button2.setText("world");
	}
}

但这样看起来太面向过程了,显得很屌丝,与你高富帅的气质形象极度不符。你真正需要的是内部类。

顾名思义,定义在一个类内部的类,就是内部类。它外层的类就是外部类。

内部类可以使用外部类的所有方法和变量,就算是外部类的private方法和变量也可以用。但内部类的方法和成员不能被外部类直接使用(即使内部类的public成员也无法被外部类直接访问),只能通过内部类对象来访问:

class MyOuterClass {
	private int x;

	class MyInnerClass {		//定义在一个类内部的类,称为内部类
		void go() { x = 42; }	//没问题,外部类的private变量也能被内部类访问
	}
}

定义完内部类,这样来创建内部类对象:

class MyOuter {
	private int x;
	MyInner inner = new MyInner();	//创建内部类实例,内部类实例一定会绑在外部类实例上

	public void doStuff() { 
		//go();			//Error编译出错,外部类无法直接访问内部类内部的成员,哪怕是public也不行
		inner.go();		//通过内部类对象才能调用内部类里的方法
	}

	class MyInner {			//内部类定义处
		void go() { x = 42; }
	}
}

还有种创建内部类对象的方法,不太常见,但你可以了解下:

MyOuter outerObj = new MyOuter();
MyOuter.MyInner innerObj = outerObj.new MyInner();

原理是一样的,内部类的对象一定会绑在外部类对象上。创建外部类对象,用该外部类对象创建内部类对象。

例子代码改成:

public class SimpleGui {
	JButton button1;
	JButton button2;
	...
	public static void main (String[] args) {
		SimpleGui gui = new SimpleGui();
		gui.go();
	}

	public void go() {
		...
		JButton button1 = new JButton("Click me");
		button1.addActionListener(new buttonListener1());
		JButton button2 = new JButton("Click me2");
		button2.addActionListener(new buttonListener2());
		...
	}

	class buttonListener1 implements ActionListener {		//内部类1
		public void actionPerformed(ActionEvent event) {
			button1.setText("Hello");
		}
	}

	class buttonListener2 implements ActionListener {		//内部类2
		public void actionPerformed(ActionEvent event) {
			button2.setText("world");
		}
	}
}

上面都是自解释代码,应该能帮助你理解内部类的精妙:

内部类提供了在同一个类中对同一个方法,提供多种实现

PS:

上面这样将内部类作为外部类的成员来定义(即定义内部类和外部类自身的成员变量和 方法处以同一级别),被称为成员内部类。

除此之外还有局部内部类,匿名内部类,静态内部类。

局部内部类:定义在类的方法或任意作用域中

interface OutInterface { ... }

class OuterClass {
	public OutInterface doit() {
		class InnerClass implements OutInterface {	//顾名思义,定义在外部类方法或任意作用域中的就是局部内部类
			...
		}
		return new InnerClass();
	}

	public static void main(String args[]) {
		OuterClass out = new OuterClass();
		out.doit();	
	}
}

该局部内部类是doit方法的一部分,非OuterClass的一部分,因此doit方法外部无法访问该内部类。但内部类可以访问外部类成员(private成员)这一特性仍旧不变。

匿名内部类:没有类名的内部类

interface OutInterface { … }

class OuterClass {
	public OutInterface doit(){
		return new OutInterface(){	//顾名思义,无类名的称为匿名内部类(因为无类名,所以只能用默认构造函数)
			...
		};
	}

	public static void main(String args[]) {
		OuterClass out = new OuterClass();
		out.doit();	
	}
}

静态内部类:内部类前加上static就是静态内部类。

静态内部类中可以声明static成员,而非静态内部类中不可声明static成员。且静态内部类不可以使用外部类的非静态成员。且不需要外部对象来创建静态内部类对象:

public class OuterClass {
	int x=0;
	static class Inner{		//静态内部类
		void doitInner(){
			//x = 5;	//编译Error,不能在静态内部类中访问外部类的非静态成员
		}
		public static void main(String args[]){ … }   //可将外部类main函数,写入静态内部类
	}
}

上面这样将外部类的static main函数,放入静态内部类后,编译将生成OuterClass.class和OuterClass$Inner.class。

执行java OuterClass$Inner就可以运行程序。这样当完成测试后,需要将.class文件打包时,只要删除OuterClass$Inner.class即可。


总结

无论什么内部类(成员,局部,匿名,静态)本质上仍旧是个类,具有普通类的一切特性。

但毕竟是定义在一个普通类的内部,生成访问权限受到一定限制(如只能通过外部类对象访问内部类),不能在程序中直接new一个内部类对象。内部类能访问外部类的一切成员(静态内部类有一定限制),但外部类无法直接访问内部类的成员,只能通过内部类对象来访问。

如果上面的说法比较难记,可以将外部类想象成丈夫,内部类想象成妻子。对妻子来说,你(丈夫)的就是我的,但我的仍旧是我的。外人无法直接拜访妻子,必须通过丈夫引见才能拜访到妻子。

内部类最强大之处在于:

能在同一个类中对同一个方法,提供多种实现



版权声明:本文为hongse_zxl原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。