Java核心技术(卷I) 15、内部类
2021-03-13 本文已影响0人
kaiker
内部类是定义在另一个类中的类
- 可以对同一个包中的其他类隐藏
- 可以访问定义这个类的作用域中的数据,包括原本私有数据
1、对象类访问对象状态
这个beep并不是TimePrinter的对象,但是TimePrinter作为内部类可以访问
class TalkingClock
{
private int interval;
private boolean beep;
/**
* Constructs a talking clock
* @param interval the interval between messages (in milliseconds)
* @param beep true if the clock should beep
*/
public TalkingClock(int interval, boolean beep)
{
this.interval = interval;
this.beep = beep;
}
/**
* Starts the clock.
*/
public void start()
{
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}
public class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
}
内部类对象有一个外围类对象引用
- 外围类的引用在构造器中设置。编译器会修改所有内部类构造器,添加一个对应外围类引用的参数。
public TimePrinter(TalkingClock clock){
outer = clock;
}
- 虚拟机会把内部类转换为常规文件,用$分隔外部类名和内部类名
public class innerClass.TalkingClock$TimePrinter {
final innerClass.TalkingClock this$0;
}
2、局部内部类
- 声明不能有访问说明符
- 对外部完全隐藏
- 可以访问是事实最终变量的局部变量,比如下面的beep就不再是TalkingClock的变量了(局部变量是随着方法的调用而调用,使用完毕就消失,而堆内存的数据并不会立即消失 https://www.zhihu.com/question/26954130)
class TalkingClock
{
/**
* Starts the clock.
* @param interval the interval between messages (in milliseconds)
* @param beep true if the clock should beep
*/
public void start(int interval, boolean beep)
{
class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}
}
- 编译器处理成
Class TalkingClock$TimePrinter {
TalkingClock$TimePrinter(TalkingClock, boolean);
final boolean val$beep;
}
3、匿名内部类
- 如果只是想创建这个类的一个对象,可以不为类指定名字
- 使用lambda表达式会更好
class TalkingClock
{
/**
* Starts the clock.
* @param interval the interval between messages (in milliseconds)
* @param beep true if the clock should beep
*/
public void start(int interval, boolean beep)
{
ActionListener listener = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
}
};
Timer t = new Timer(interval, listener);
t.start();
}
}
4、静态内部类
- 只是为了把一个类隐藏在另一个类的内部,并不需要内部类有外围类对象的引用,可以使用静态内部类
- 没有外部类对象,也可以创建静态内部类对象 https://www.zhihu.com/question/26954130
- 下面这个例子里,不需要构建ArrayAlg的对象,可以通过ArrayAlg.Pair p调用
public class StaticInnerClassTest
{
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
{
/**
* A pair of floating-point numbers
*/
public static class Pair
{
private double first;
private double second;
/**
* Constructs a pair from two floating-point numbers
* @param f the first number
* @param s the second number
*/
public Pair(double f, double s)
{
first = f;
second = s;
}
/**
* Returns the first number of the pair
* @return the first number
*/
public double getFirst()
{
return first;
}
/**
* Returns the second number of the pair
* @return the second number
*/
public double getSecond()
{
return second;
}
}
/**
* Computes both the minimum and the maximum of an array
* @param values an array of floating-point numbers
* @return a pair whose first element is the minimum and whose second element
* is the maximum
*/
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);
}
}