回调(callback)是一种设计模式,可以指定某个特定事件发生时应该采取的动作。如:每过一秒钟,就打印当前时间和哔一声。
定时器(时间,动作监听器):面向对象,传入的是对象而不是函数。
package timer;
/**
@version 1.02 2017-12-14
@author Cay Horstmann
*/
import java.awt.*;
import java.awt.event.*;
import java.time.*;
import javax.swing.*;
public class TimerTest
{
public static void main(String[] args)
{
var listener = new TimePrinter();
// construct a timer that calls the listener once every second
var timer = new Timer(1000, listener);
timer.start();
// keep program running until the user selects "OK"
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is " + Instant.ofEpochMilli(event.getWhen()));
Toolkit.getDefaultToolkit().beep();
}
}
举一个更好理解的例子:
package mytest;
import javax.swing.*;
import java.awt.*;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
public class TimerTest
{
public static void main(String[] args) throws InterruptedException {
// construct a timer that calls the listener once every second
// lambda表达式-代码块或函数,简化函数式接口-只有一个抽象方法的接口。
// 即java实现函数时编程的方式
var timer = new Timer(1000, event -> {
System.out.println("At the tone, the time is " + Instant.ofEpochMilli(event.getWhen()));
Toolkit.getDefaultToolkit().beep();
});
timer.start();
// main thread keep running
while (true) {
TimeUnit.MILLISECONDS.sleep(300);
System.out.println("I'm running!");
}
}
}
主程序已经跑到while循环了,但是每当触发事件(每过一秒),就还是会回去执行约定好的动作!
package innerClass;
import java.awt.*;
import java.awt.event.*;
import java.time.*;
import javax.swing.*;
/**
* This program demonstrates the use of inner classes.
* @version 1.11 2017-12-14
* @author Cay Horstmann
*/
public class InnerClassTest
{
public static void main(String[] args)
{
var clock = new TalkingClock(1000, true);
clock.start();
// keep program running until the user selects "OK"
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
/**
* A clock that prints the time in regular intervals.
*/
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()
{
var listener = new TimePrinter();
var timer = new Timer(interval, listener);
timer.start();
}
public class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is "
+ Instant.ofEpochMilli(event.getWhen()));
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
}
内部类可以访问外部类的实例字段。内部类有一个外部类的引用,称之为outer。外部类new内部类时把this对象引用通过内部类的构造器传递给outer变量。
内部类可以是私有的,这样只能通过外部类构造内部类对象了。
package anonymousInnerClass;
import java.awt.*;
import java.awt.event.*;
import java.time.*;
import javax.swing.*;
/**
* This program demonstrates anonymous inner classes.
* @version 1.12 2017-12-14
* @author Cay Horstmann
*/
public class AnonymousInnerClassTest
{
public static void main(String[] args)
{
var clock = new TalkingClock();
clock.start(1000, true);
// keep program running until the user selects "OK"
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
/**
* A clock that prints the time in regular intervals.
*/
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)
{
var listener = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is "
+ Instant.ofEpochMilli(event.getWhen()));
if (beep) Toolkit.getDefaultToolkit().beep();
}
};
var timer = new Timer(interval, listener);
timer.start();
}
}
匿名局部内部类。
1、对外完全隐藏。局部内部类甚至不能由外部类的其他方法访问。
2、可以访问局部变量,但要求其是事实最终变量。
3、几乎被lambda表达式取代。
package staticInnerClass;
/**
* This program demonstrates the use of static inner classes.
* @version 1.02 2015-05-12
* @author Cay Horstmann
*/
public class StaticInnerClassTest
{
public static void main(String[] args)
{
var values = new double[20];
for (int i = 0; i < values.length; i++)
values[i] = 100 * Math.random();
ArrayAlg.Pair p = ArrayAlg.minmax(values);
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);
}
}
静态内部类:
无外部类引用。
只要内部类不需要访问外部类对象,就应该使用静态内部类。只是为了把一个类隐藏在另外一个类的内部。