第六章:接口、lambda表达式与内部类
到目前为止,读者已经学习了 Java 面向对象程序设计的全部基本知识。本章将开始介 绍几种常用的高级技术。这些内容可能不太容易理解,但一定要掌握它们,以便完善自己的 Java 工具箱。 首先,介绍一下接口( interface) 技术, 这种技术主要用来描述类具有什么功能,而并不 给出每个功能的具体实现。一个类可以实现( implement) —个或多个接口,并在需要接口的地方, 随时使用实现了相应接口的对象。 了解接口以后,再继续介绍lambda表达式,这是一种表示可以在将来某个时间点执行的代码块的简洁方法。使用 lambda 表达式,可以用一 种精巧而简洁的方式表示使用回调或变量行为的代码。 接下来,讨论内部类( inner class) 机制。理论上讲,内部类有些复杂, 内部类定义在另 外一个类的内部, 其中的方法可以访问包含它们的外部类的域。内部类技术主要用于设计具有相互协作关系的类集合。 在本章的最后还将介绍代理(proxy), 这是一种实现任意接口的对象。代理是一种非常 专业的构造工具,它可以用来构建系统级的工具。如果是第一次学习这本书,可以先跳过这个部分。
知识点整理(不包含代理那节)
接口
EmployeeSortTest.java
package interfaces;
import java.util.Arrays;
public class EmployeeSortTest {
public static void main(String[] args) {
Employee[] staff = new Employee[3];
staff[0] = new Employee("Harry Hacker", 35000);
staff[1] = new Employee("Carl Cracker", 75000);
staff[2] = new Employee("Tony Tester", 38000);
Arrays.sort(staff);
//print out information about all Employee objects
for(Employee e : staff)
System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
}
}
Employee.java
package interfaces;
public class Employee implements Comparable<Employee>{
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
/*
* Compares employees by salary
* @param other another Employee object
* @return a negative value if this employee has lower salary than otherObject,
* o if the salaries are the same, a positive value otherwise
*/
public int compareTo(Employee other) {
return Double.compare(salary, other.salary);
}
}
接口示例
接口与回调
TimerTest.java
package timer;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
//to resolve conflict with java.util.Timer
public class TimerTest {
public static void main(String[] args) {
ActionListener listener = new TimePrinter();
//construct a timer that calls the listener
//once every 10 seconds
Timer t = new Timer(5000, listener);
t.start();
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
class TimePrinter implements ActionListener{
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the tiome is " + new Date());
Toolkit.getDefaultToolkit().beep();
}
}
对象克隆
CloneTest.java
package clone;
public class CloneTest {
public static void main(String[] args) {
try {
Employee original = new Employee("John Q. Public", 50000);
original.setHireDay(2000, 1, 1);
Employee copy = original.clone();
copy.raiseSalary(10);
copy.setHireDay(2002, 12, 31);
System.out.println("original=" + original);
System.out.println("copy=" + copy);
} catch(CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
Employee.java
package clone;
import java.util.Date;
import java.util.GregorianCalendar;
public class Employee implements Cloneable{
private String name;
private double salary;
private Date hireDay;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
hireDay = new Date();
}
public Employee clone() throws CloneNotSupportedException
{
//call Object.clone()
Employee cloned = (Employee) super.clone();
//clone mutable fields
cloned.hireDay = (Date)hireDay.clone();
return cloned;
}
/*
* Set the hire day to a given date.
* @param year the year of the hire day
* @param month the month of the hire day
* @param day the day of the hire day
*/
public void setHireDay(int year, int month, int day) {
Date newHireDay = new GregorianCalendar(year, month - 1, day).getTime();
//Example of instance field mutation
hireDay.setTime(newHireDay.getTime());
}
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
public String toString() {
return ("Employee[name=" + name +",salary=" + salary + ",hireDay=" + hireDay + "]");
}
}
lambda表达式
lambda表达式的语法
LambdaTest.java
package lambda;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class LambdaTest {
public static void main(String[] args) {
String[] planets = new String[] { "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"};
System.out.println(Arrays.toString(planets));
System.out.println("Sorted in dictionary order:");
Arrays.sort(planets);
System.out.println(Arrays.toString(planets));
System.out.println("Sorted by length:");
Arrays.sort(planets, (first, second) -> first.length() - second.length());
System.out.println(Arrays.toString(planets));
Timer t = new Timer(1000, event -> System.out.println("The time is " + new Date()));
t.start();
//keep program running until user selects "Ok"
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
内部类
使用内部类访问对象状态
InnerClassTest.java
package innerClass;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class InnerClassTest {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock(1000, true);
clock.start();
// kepp program running until 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() {
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();
}
}
}
匿名内部类
AnonymousInnerClassTest
package anonymousInnerClass;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class AnonymousInnerClassTest {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock();
clock.start(1000, true);
// keep program running until 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 molliseconds)
* @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();
}
}
静态内部类
StaticInnerClassTest
package staticInnerClass;
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;
}
/**
* Return 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);
}
}