内部类:定义在另一个类中的类。
当描述事物时,事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容.
使用内部类的原因:
- 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据
- 内部类可以对同一个包中的其他类隐藏
- 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较方便
实例6-6:InnerClassTest.java
package innerClass;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class innerClassTest
{ /**
* @param args
*/
public static void main(String[] args)
{ // TODO 自动生成的方法存根
TalkingClock clock = new TalkingClock(1000,true);
clock.start();
JOptionPane.showMessageDialog(null, "Quit the program???");
System.exit(0);
}
}
class TalkingClock
{
private int interval;
private boolean be;
public TalkingClock(int interval, boolean b)
{
this.interval = interval;
this.be = b;
}
public void start()
{
ActionListener listener = new TimerPrinter();
Timer t = new Timer(interval, listener);
t.start();
}
public class TimerPrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
Date now = new Date();
System.out.println("At the tone , the time is : " + now);
if(be) Toolkit.getDefaultToolkit().beep();
}
}
}
1、使用内部类访问对象状态
- 内部类可以直接访问外部类中的成员,包括私有的。之所以可以直接访问外部类中的成员,其实是因为内部类中持有了一个外部类的引用,其格式为:外部类名.this
// 其中的 be 是外部类 TalkingClock 的成员变量
if(be) Toolkit.getDefaultToolkit().beep(); // 等价于下句
if(TalkingClock.this.be) Toolkit.getDefaultToolkit().beep();
- 外部类要访问内部类,必须先创建内部类对象
clock.start();// clock对象调用方法start,在start中创建内部类对象
2、局部内部类
实例6-6中, TimePrinter 这个类名字只在start方法中创建对象时使用一次,这时可以在一个方法中定义局部类,简化代码。
public void start()
{
class TimerPrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
...
}
}
...
}
注意:
- 局部类不能用 public 或 private 访问说明符进行声明
- 它的作用域被限定在声明这个局部类的块中
- 局部类可以对外部世界完全隐藏,即使 TalkingClock 类中的其他成员也不能访问它,除了 start 方法,没有任何方法知道 TimePrinter 类的存在
3、内部类方法访问局部变量
有说是局部类访问的局部变量必须被声明为final,但下面写的程序又没有出现问题。(难道是版本不同的原因???)
class Outer
{
int x = 3;
void method(int z)
{
int y = 4;
class Inner
{
int x = 1;
void function()
{
System.out.println(Outer.this.x);// 打印3
System.out.println(y);// 打印4
System.out.println(this.x);// 或者 System.out.println(x);打印1
System.out.println(z);// 打印6
}
}
new Inner().function();// 创建内部类并调用方法
}
}
class InnerClassDemo3
{
public static void main(String[] args)
{
new Outer().method(6);
}
}
4、匿名内部类
- 若只创建某内部类的一个对象时,就不必命名,也就是内部类的简写格式。
- 定义的匿名内部类必须是继承一个类或者实现接口
- 格式:new 父类或者接口() {定义子类的内容}
abstract AbsDemo
{
abstract void show();
}
class Outer
{
int x = 3;
/*class Inner extends AbsDemo// ①
{
void show(){} // ②
}*/
public void function()
{
//new Inner().show();// ③创建对象并④调用方法
// 将①-④步放在一起完成
new AbsDemo()
{
void show(){}
void teyou(){}// 特有的方法
}.show();
// 或
AbsDemo s = new AbsDemo()
{
void show(){}
void teyou(){} //特有的方法
};
s.show();
s.teyou();// 编译失败,因为父类AnsDemo中没有该方法
}
}
5、静态内部类
- 当内部类在成员位置上,就可以被成员修饰符所修饰;
比如
private:将内部类在外部类中进行封装
static:内部类就具备static的特性
①、当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限;
②、在外部其他类中,如何直接访问static内部类的非静态成员?
new Outer.Inner().function();
③、在外部其他类中,如何直接访问static内部类的静态成员?
Outer.Inner.function();
注意:
- 当内部类中定义了静态成员,该内部类必须是静态static的
- 当外部类中静态方法访问内部类时,内部类也必须是静态的
class Outer
{
private static int x = 3;
static class Inner
{
static void function()// 情况②时未被static修饰;情况③时,被static修饰
{
System.out.println("Inner: " + x);// 打印num初始值
}
}
}
class InnerClassDemo2
{
public static void main(String[] args)
{
// ①,当内部类Inner及其方法function都未被static修饰时,可如下调用
// new Outer().new Inner().function();
// ②
// new Outer.Inner().function();
// ③
Outer.Inner.function();
}
}
当内部类定义在外部类的成员位置上,而且非私有时,可以在外部其他类中可以直接建立内部类对象;
格式:
外部类名.内部类名 变量名 = 外部类对象.内部类对象
Outer.Inner in = new Outer().new Inner();