实验六 接口的定义与使用
实验时间 2018-10-18
1、实验目的与要求
(1) 掌握接口定义方法
JAVA中通过interface关键字定义接口;
接口中只能定义public static final(也可以在定义时不写,系统是默认的)修饰的变量以及抽象方法
接口中定义的变量必须有初始值
(2) 掌握实现接口类的定义要求;
接口体中包含常量定义和方法定义,接口中只进行方法的声明,不提供方法的实现;且接口中的任何方法都自动是public,字段也总是public static final的。
(3) 掌握实现了接口类的使用要求;
接口不能构造接口对象,但可以声明接口变量以指向一个实现了该接口的类的对象。
可以用instanceof来检查对象是否实现了某个接口。
通常接口的名字以able或ible结尾;
可以使用extends来继承接口的常量和抽象方法,扩展形成新的接口;
接口中的所有常量必须是public static final,方法必须是public abstract,这是系统默认的,不管你在定义接口时,写不写修饰符都是一样的。
在类声明时用implements关键字声明使用一个或多个接口
一个类使用了某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体。
一个类可以实现多个接口,接口间应该用逗号分隔开。
若实现接口的类不是抽象类,则必须实现所有接口的所有方法,即为所有的抽象方法定义方法体。
一个类在实现某接口抽象方法时,必须使用完全相同的方法名,参数列表,返回值类型。
接口的抽象方法的访问控制符已指定为public,所以类在实现时,必须显示的使用public修饰符,否则被警告缩小了接口中定义的方法的访问控制范围。
区分重载与覆盖。
(4) 掌握程序回调设计模式;
回调(callback)是一种常见的程序设计模式,在这种模式中,可以指出某个特定事件发生时应该采取的动作。
在java.swing包中有一个Timer类,可以使用它在到达给定的时间间隔是触发一个事件
(5) 掌握Comparator接口用法;
(6) 掌握对象浅层拷贝与深层拷贝方法;
浅层拷贝: 被拷贝的对象的所有成员属性都有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅层拷贝仅仅拷贝所考虑的对象,而不拷贝它所引用的对象。(概念不好理解,请结合下文的示例去理解)
深层拷贝:被拷贝对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不是原有的那些被引用的对象。换言之,深层拷贝要拷贝的对象引用的对象都拷贝一遍
(7) 掌握Lambda表达式语法;
lambda表达式由如下几个部分组成:
在圆括号中以逗号分隔的形参列表。在CheckPerson.test方法中包含一个参数p,代表了一个Person类的实例。(8) 了解内部类的用途及语法要求。
内部类(inner class)是定义在另一个类内部的类。
使用内部类的原因有以下三个:
内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。
内部类能够隐藏起来,不为同一包中的其他类所见。
想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。
内部类可以直接访问外部类的成员,包括private成员,但是内部类的成员却不能被外部类直接访问。
局部内部类
在内部类对象保存了一个对外部类对象的引用,当内部类的成员方法中访问某一变量时,如果在该方法和内部类中都没有定义过这个变量,内部类中对this的引用会被传递给那个外部类对象的引用。
内部类并非只能在类里定义,也可以在几个程序块的范围之内定义局部内部类。例如,在方法中,或甚至在for循环体内部,都可以定义内部类 。
局部内部类不能用public或private访问修饰符进行声明,它的作用域被限定在声明这个局部类的块中。
局部内部类不仅能够访问包含它们的外部类,还可以访问方法中的final类型的局部变量,用final定义的局部变量相当于是一个常量,它的生命周期超出方法运行的生命周期。
匿名内部类
将局部内部类的使用再深入一步,假如只创建这个类的一个对象,就不必命名,将这种类称为匿名内部类(anonymous inner class)。
由于构造器的名字必须与类名相同,而匿名类没有类名,所以匿名类不能有构造器,取而代之的是将构造器参数传递给超类的构造器。尤其是在内部类实现接口的时候,不能有任何构造参数。
如果构造参数的闭圆括号跟一个开花括号,正在定义的就是匿名内部类。
静态内部类
如果用static修饰一个内部类,这个类就相当于是一个外部定义的类,所以static的内部类中可声明static成员,但是,非static的内部类中的成员是不能声明为static的。static的内部类不能再使用外部类的非static的成员变量,这个道理不难想象!所以static内部类很少使用。
2、实验内容和步骤
实验1: 导入第6章示例程序,测试程序并进行代码注释。
测试程序1:
l 编辑、编译、调试运行阅读教材214页-215页程序6-1、6-2,理解程序并分析程序运行结果;
l 在程序中相关代码处添加新知识的注释。
l 掌握接口的实现用法;
l 掌握内置接口Compareable的用法
1 package interfaces; 2 3 public class Employee implements Comparable4 { 5 private String name; 6 private double salary; 7 8 public Employee(String name, double salary) 9 {10 this.name = name;11 this.salary = salary;12 }13 14 public String getName()15 {16 return name;17 }18 19 public double getSalary()20 {21 return salary;22 }23 24 public void raiseSalary(double byPercent)25 {26 double raise = salary * byPercent / 100;27 salary += raise;28 }29 30 /**31 * Compares employees by salary32 * @param other another Employee object33 * @return a negative value if this employee has a lower salary than34 * otherObject, 0 if the salaries are the same, a positive value otherwise35 */36 public int compareTo(Employee other)37 {38 return Double.compare(salary, other.salary);39 }40 }
1 package interfaces; 2 3 import java.util.*; 4 5 /** 6 * This program demonstrates the use of the Comparable interface. 7 * @version 1.30 2004-02-27 8 * @author Cay Horstmann 9 */10 public class EmployeeSortTest11 {12 public static void main(String[] args)13 {14 Employee[] staff = new Employee[3];15 16 staff[0] = new Employee("Harry Hacker", 35000);17 staff[1] = new Employee("Carl Cracker", 75000);18 staff[2] = new Employee("Tony Tester", 38000);19 20 Arrays.sort(staff);21 22 // print out information about all Employee objects23 for (Employee e : staff)24 System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());25 }26 }
测试程序2:
l 编辑、编译、调试以下程序,结合程序运行结果理解程序;
interface A { double g=9.8; void show( ); } class C implements A { public void show( ) {System.out.println("g="+g);} }
class InterfaceTest { public static void main(String[ ] args) { A a=new C( ); a.show( ); System.out.println("g="+C.g); } } |
测试程序3:
l 在elipse IDE中调试运行教材223页6-3,结合程序运行结果理解程序;
l 26行、36行代码参阅224页,详细内容涉及教材12章。
l 在程序中相关代码处添加新知识的注释。
l 掌握回调程序设计模式;
1 package timer; 2 3 /** 4 @version 1.01 2015-05-12 5 @author Cay Horstmann 6 */ 7 8 import java.awt.*; 9 import java.awt.event.*;10 import java.util.*;11 import javax.swing.*;12 import javax.swing.Timer; 13 // to resolve conflict with java.util.Timer14 15 public class TimerTest16 { 17 public static void main(String[] args)18 { 19 ActionListener listener = new TimePrinter();20 21 // construct a timer that calls the listener22 // once every 10 seconds23 Timer t = new Timer(10000, listener);24 t.start();25 26 JOptionPane.showMessageDialog(null, "Quit program?");27 System.exit(0);28 }29 }30 31 class TimePrinter implements ActionListener32 { 33 public void actionPerformed(ActionEvent event)34 { 35 System.out.println("At the tone, the time is " + new Date());36 Toolkit.getDefaultToolkit().beep();37 }38 }
测试程序4:
l 调试运行教材229页-231页程序6-4、6-5,结合程序运行结果理解程序;
l 在程序中相关代码处添加新知识的注释。
l 掌握对象克隆实现技术;
l 掌握浅拷贝和深拷贝的差别。
1 package clone; 2 3 import java.util.Date; 4 import java.util.GregorianCalendar; 5 6 public class Employee implements Cloneable 7 { 8 private String name; 9 private double salary;10 private Date hireDay;11 12 public Employee(String name, double salary)13 {14 this.name = name;15 this.salary = salary;16 hireDay = new Date();17 }18 19 public Employee clone() throws CloneNotSupportedException20 {21 // call Object.clone()22 Employee cloned = (Employee) super.clone();23 24 // clone mutable fields25 cloned.hireDay = (Date) hireDay.clone();26 27 return cloned;28 }29 30 /**31 * Set the hire day to a given date. 32 * @param year the year of the hire day33 * @param month the month of the hire day34 * @param day the day of the hire day35 */36 public void setHireDay(int year, int month, int day)37 {38 Date newHireDay = new GregorianCalendar(year, month - 1, day).getTime();39 40 // Example of instance field mutation41 hireDay.setTime(newHireDay.getTime());42 }43 44 public void raiseSalary(double byPercent)45 {46 double raise = salary * byPercent / 100;47 salary += raise;48 }49 50 public String toString()51 {52 return "Employee[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";53 }54 }
1 package clone; 2 3 /** 4 * This program demonstrates cloning. 5 * @version 1.10 2002-07-01 6 * @author Cay Horstmann 7 */ 8 public class CloneTest 9 {10 public static void main(String[] args)11 {12 try13 {14 Employee original = new Employee("John Q. Public", 50000);15 original.setHireDay(2000, 1, 1);16 Employee copy = original.clone();17 copy.raiseSalary(10);18 copy.setHireDay(2002, 12, 31);19 System.out.println("original=" + original);20 System.out.println("copy=" + copy);21 }22 catch (CloneNotSupportedException e)23 {24 e.printStackTrace();25 }26 }27 }
实验2: 导入第6章示例程序6-6,学习Lambda表达式用法。
l 调试运行教材233页-234页程序6-6,结合程序运行结果理解程序;
l 在程序中相关代码处添加新知识的注释。
l 将27-29行代码与教材223页程序对比,将27-29行代码与此对比,体会Lambda表达式的优点。
1 package lambda; 2 3 import java.util.*; 4 5 import javax.swing.*; 6 import javax.swing.Timer; 7 8 /** 9 * This program demonstrates the use of lambda expressions.10 * @version 1.0 2015-05-1211 * @author Cay Horstmann12 */13 public class LambdaTest14 {15 public static void main(String[] args)16 {17 String[] planets = new String[] { "Mercury", "Venus", "Earth", "Mars", 18 "Jupiter", "Saturn", "Uranus", "Neptune" };19 System.out.println(Arrays.toString(planets));20 System.out.println("Sorted in dictionary order:");21 Arrays.sort(planets);22 System.out.println(Arrays.toString(planets));23 System.out.println("Sorted by length:");24 Arrays.sort(planets, (first, second) -> first.length() - second.length());25 System.out.println(Arrays.toString(planets));26 27 Timer t = new Timer(1000, event ->28 System.out.println("The time is " + new Date()));29 t.start(); 30 31 // keep program running until user selects "Ok"32 JOptionPane.showMessageDialog(null, "Quit program?");33 System.exit(0); 34 }35 }
注:以下实验课后完成
实验3: 编程练习
l 编制一个程序,将身份证号.txt 中的信息读入到内存中;
l 按姓名字典序输出人员信息;
l 查询最大年龄的人员信息;
l 查询最小年龄人员信息;
l 输入你的年龄,查询身份证号.txt中年龄与你最近人的姓名、身份证号、年龄、性别和出生地;
l 查询人员中是否有你的同乡
1 import java.io.BufferedReader; 2 import java.io.File; 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.util.ArrayList; 8 import java.util.Arrays; 9 import java.util.Collections; 10 import java.util.Scanner; 11 12 public class Check{ 13 private static ArrayListstudentlist; 14 public static void main(String[] args) { 15 studentlist = new ArrayList<>(); 16 Scanner scanner = new Scanner(System.in); 17 File file = new File("C:\\下载\\身份证号.txt"); 18 try { 19 FileInputStream fis = new FileInputStream(file); 20 BufferedReader in = new BufferedReader(new InputStreamReader(fis)); 21 String temp = null; 22 while ((temp = in.readLine()) != null) { 23 24 Scanner linescanner = new Scanner(temp); 25 26 linescanner.useDelimiter(" "); 27 String name = linescanner.next(); 28 String number = linescanner.next(); 29 String sex = linescanner.next(); 30 String age = linescanner.next(); 31 String province =linescanner.nextLine(); 32 Student student = new Student(); 33 student.setName(name); 34 student.setnumber(number); 35 student.setsex(sex); 36 int a = Integer.parseInt(age); 37 student.setage(a); 38 student.setprovince(province); 39 studentlist.add(student); 40 41 } 42 } catch (FileNotFoundException e) { 43 System.out.println("学生信息文件找不到"); 44 e.printStackTrace(); 45 } catch (IOException e) { 46 System.out.println("学生信息文件读取错误"); 47 e.printStackTrace(); 48 } 49 boolean isTrue = true; 50 while (isTrue) { 51 System.out.println("选择你的操作,输入正确格式的选项"); 52 System.out.println("1.按姓名字典序输出人员信息"); 53 System.out.println("2.输出年龄最大和年龄最小的人"); 54 System.out.println("3.查找老乡"); 55 System.out.println("4.查找年龄相近的人"); 56 System.out.println("5.退出"); 57 String m = scanner.next(); 58 switch (m) { 59 case "1": 60 Collections.sort(studentlist); 61 System.out.println(studentlist.toString()); 62 break; 63 case "2": 64 int max=0,min=100; 65 int j,k1 = 0,k2=0; 66 for(int i=1;i max) 70 { 71 max=j; 72 k1=i; 73 } 74 if(j
1 public class Student implements Comparable{ 2 3 private String name; 4 private String number ; 5 private String sex ; 6 private int age; 7 private String province; 8 9 public String getName() {10 return name;11 }12 public void setName(String name) {13 this.name = name;14 }15 public String getnumber() {16 return number;17 }18 public void setnumber(String number) {19 this.number = number;20 }21 public String getsex() {22 return sex ;23 }24 public void setsex(String sex ) {25 this.sex =sex ;26 }27 public int getage() {28 29 return age;30 }31 public void setage(int age) {32 // int a = Integer.parseInt(age);33 this.age= age;34 }35 36 public String getprovince() {37 return province;38 }39 public void setprovince(String province) {40 this.province=province ;41 }42 43 public int compareTo(Student o) {44 return this.name.compareTo(o.getName());45 }46 47 public String toString() {48 return name+"\t"+sex+"\t"+age+"\t"+number+"\t"+province+"\n";49 } 50 }
实验4:内部类语法验证实验
实验程序1:
l 编辑、调试运行教材246页-247页程序6-7,结合程序运行结果理解程序;
l 了解内部类的基本用法。
1 package innerClass; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.util.*; 6 import javax.swing.*; 7 import javax.swing.Timer; 8 9 /**10 * This program demonstrates the use of inner classes.11 * @version 1.11 2015-05-1212 * @author Cay Horstmann13 */14 public class InnerClassTest15 {16 public static void main(String[] args)17 {18 TalkingClock clock = new TalkingClock(1000, true);19 clock.start();20 21 // keep program running until user selects "Ok"22 JOptionPane.showMessageDialog(null, "Quit program?");23 System.exit(0);24 }25 }26 27 /**28 * A clock that prints the time in regular intervals.29 */30 class TalkingClock31 {32 private int interval;33 private boolean beep;34 35 /**36 * Constructs a talking clock37 * @param interval the interval between messages (in milliseconds)38 * @param beep true if the clock should beep39 */40 public TalkingClock(int interval, boolean beep)41 {42 this.interval = interval;43 this.beep = beep;44 }45 46 /**47 * Starts the clock.48 */49 public void start()50 {51 ActionListener listener = new TimePrinter();52 Timer t = new Timer(interval, listener);53 t.start();54 }55 56 public class TimePrinter implements ActionListener57 {58 public void actionPerformed(ActionEvent event)59 {60 System.out.println("At the tone, the time is " + new Date());61 if (beep) Toolkit.getDefaultToolkit().beep();62 }63 }64 }
实验程序2:
l 编辑、调试运行教材254页程序6-8,结合程序运行结果理解程序;
l 了解匿名内部类的用法。
1 package anonymousInnerClass; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.util.*; 6 import javax.swing.*; 7 import javax.swing.Timer; 8 9 /**10 * This program demonstrates anonymous inner classes.11 * @version 1.11 2015-05-1212 * @author Cay Horstmann13 */14 public class AnonymousInnerClassTest15 {16 public static void main(String[] args)17 {18 TalkingClock clock = new TalkingClock();19 clock.start(1000, true);20 21 // keep program running until user selects "Ok"22 JOptionPane.showMessageDialog(null, "Quit program?");23 System.exit(0);24 }25 }26 27 /**28 * A clock that prints the time in regular intervals.29 */30 class TalkingClock31 {32 /**33 * Starts the clock.34 * @param interval the interval between messages (in milliseconds)35 * @param beep true if the clock should beep36 */37 public void start(int interval, boolean beep)38 {39 ActionListener listener = new ActionListener()40 {41 public void actionPerformed(ActionEvent event)42 {43 System.out.println("At the tone, the time is " + new Date());44 if (beep) Toolkit.getDefaultToolkit().beep();45 }46 };47 Timer t = new Timer(interval, listener);48 t.start();49 }50 }
实验程序3:
l 在elipse IDE中调试运行教材257页-258页程序6-9,结合程序运行结果理解程序;
l 了解静态内部类的用法。
1 package staticInnerClass; 2 3 /** 4 * This program demonstrates the use of static inner classes. 5 * @version 1.02 2015-05-12 6 * @author Cay Horstmann 7 */ 8 public class StaticInnerClassTest 9 {10 public static void main(String[] args)11 {12 double[] d = new double[20];13 for (int i = 0; i < d.length; i++)14 d[i] = 100 * Math.random();15 ArrayAlg.Pair p = ArrayAlg.minmax(d);16 System.out.println("min = " + p.getFirst());17 System.out.println("max = " + p.getSecond());18 }19 }20 21 class ArrayAlg22 {23 /**24 * A pair of floating-point numbers25 */26 public static class Pair27 {28 private double first;29 private double second;30 31 /**32 * Constructs a pair from two floating-point numbers33 * @param f the first number34 * @param s the second number35 */36 public Pair(double f, double s)37 {38 first = f;39 second = s;40 }41 42 /**43 * Returns the first number of the pair44 * @return the first number45 */46 public double getFirst()47 {48 return first;49 }50 51 /**52 * Returns the second number of the pair53 * @return the second number54 */55 public double getSecond()56 {57 return second;58 }59 }60 61 /**62 * Computes both the minimum and the maximum of an array63 * @param values an array of floating-point numbers64 * @return a pair whose first element is the minimum and whose second element65 * is the maximum66 */67 public static Pair minmax(double[] values)68 {69 double min = Double.POSITIVE_INFINITY;70 double max = Double.NEGATIVE_INFINITY;71 for (double v : values)72 {73 if (min > v) min = v;74 if (max < v) max = v;75 }76 return new Pair(min, max);77 }78 }
实验总结:
通过第六章的学习,明白了继承与接口实现的区别,两者最大的区别就是,类只能继承一个父类,一个类可以实现多个借口,类通过使用关键字implements声明自己实现一个或多个类,如果一个非抽象类实现了某个借口,那么这个非抽象类必须重写该接口的所有方法。使用clone的方法,可以有别于直接复制,可以对复制的内容重新定义方法等,通过对示例代码的测试,对第六章内容有了进一步的理解。