内部类就是定义在另一个类中的类,使用内部类的理由主要有以下三点:
1)内部类方法可以访问该类定义在作用域中的数据,包括私有数据。
2)内部类可以对同一个包中的其他类隐藏起来。
3)当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。
内部类根据定义的位置不同,可以分为四种,第一种就是普通的内部类,第二种是局部内部类,第三种是匿名内部类,第四种是静态内部类。
这里只需强调一点即可,就是为了运行使用了其外部实例域的内部类,内部类对象中总有一个隐式引用,它指向了创建它的外部类对象,因此其内部类可以使用其外部类的实例域。
当然,既然有隐式引用,当然可以显式的表达出来了。
对于内部类引用外部类中数据,可以使用以下语法:外部类名.this.数据名
例如下面例子中的:
if(beep)可以显式的写为if(TalkingClock.this.beep)
创建一个内部类对象的时候也可以显式的说明,可以使用以下语法:内部类名 对象名=this.new 内部类名(参数);
例如下面例子中的:
ActionListener listener=new TimePrinter();可以显式的写为ActionListener listener=this.new TimePrinter();
下面是一个完整的例子:
代码:
package InnerClasses;
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 {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock(1000,true);
clock.start();
JOptionPane.showMessageDialog(null,"关闭??");
System.exit(0);
}
}
class TalkingClock{
private int interval;
private boolean beep;
public TalkingClock(int interval,boolean beep) {
this.interval=interval;
this.beep=beep;
}
public void start() {
ActionListener listener=new TimePrinter();
Timer t=new Timer(interval,listener);
t.start();
}
private class TimePrinter implements ActionListener{
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("现在时间是:"+new Date());
if(beep) {
Toolkit.getDefaultToolkit().beep();
}
}
}
}
运行结果:
对于第二种内部类--局部内部类,其实是定义在类方法中的内部类,这种类不能使用访问修饰符,而且这种类的作用域被限制在声明这个局部类的块中。同一般的内部类相比,局部内部类还有一个优势就是可以访问局部变量。
例如上面的代码可以修改为:
代码:
package InnerClasses;
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 {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock(1000,true);
clock.start();
JOptionPane.showMessageDialog(null,"关闭??");
System.exit(0);
}
}
class TalkingClock{
private int interval;
private boolean beep;
public TalkingClock(int interval,boolean beep) {
this.interval=interval;
this.beep=beep;
}
public void start() {
class TimePrinter implements ActionListener{
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("现在时间是:"+new Date());
if(beep) {
Toolkit.getDefaultToolkit().beep();
}
}
}
ActionListener listener=new TimePrinter();
Timer t=new Timer(interval,listener);
t.start();
}
}
输出结果和上一例子一样。
第三种内部类--匿名内部类:
这种内部类更加直接,没有类名。
具体语法为:
类名 对象名=new 类名(构造参数){
内部类方法和数据
}
类名也可以是接口名,如果是接口名,则就像下面这样子了:
接口名 对象名=new 接口名(){
方法和数据
}
下面是一个例子:
package InnerClasses;
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 AnonyInnerClassTest {
public static void main(String[] args) {
TalkingClock2 clock =new TalkingClock2();
clock.start(1000, true);
JOptionPane.showMessageDialog(null, "退出??");
System.exit(0);
}
}
class TalkingClock2{
public void start(int interval,boolean beep) {
ActionListener listener=new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("现在的时间是:"+new Date());
if(beep) {
Toolkit.getDefaultToolkit().beep();
}
}
};
Timer t=new Timer(interval,listener);
t.start();
}
}
运行结果和前两个例子一样。
第四种内部类--静态内部类
静态内部类的目的很简单,就是为了把一个类隐藏在另一个类的内部。这时,可以将内部类声明为static。
静态内部类中不可以引用外部类的非静态变量和方法,而在静态内部类中可以有静态域和静态方法。
下面是一个例子:用于计算一个double型数组的最大值和最小值。
代码:
package InnerClasses;
public class StaticInnerClass {
public static void main(String[] args) {
double[] d=new double[20];
for(int i=0;i<d.length;++i) {
d[i]=100*Math.random();
}
ArrayAlg.Pair p=ArrayAlg.minmax(d);
System.out.println("min="+p.getFirst());
System.out.println("max="+p.getSecond());
}
}
class ArrayAlg{
public static class Pair{
private double first;
private double second;
public Pair(double f,double s) {
first=f;
second=s;
}
public double getFirst() {
return first;
}
public double getSecond() {
return second;
}
}
public static Pair minmax(double[] values) {
double min=Double.POSITIVE_INFINITY;
double max=Double.NEGATIVE_INFINITY;
for(double v:values) {
if(min>v)min=v;
if(max<v)max=v;
}
return new Pair(min,max);
}
}
运行结果: