达拉草201771010105《面向对象程序设计(java)》第八周学习总结
实验六接口的定义与使用
实验时间 2018-10-18
1、实验目的与要求
(1) 掌握接口定义方法;
(2) 掌握实现接口类的定义要求;
(3) 掌握实现了接口类的使用要求;
(4) 掌握程序回调设计模式;
(5) 掌握Comparator接口用法;
(6) 掌握对象浅层拷贝与深层拷贝方法;
(7) 掌握Lambda表达式语法;
(8) 了解内部类的用途及语法要求。
2、实验内容和步骤
实验1: 导入第6章示例程序,测试程序并进行代码注释。
测试程序1:
l 编辑、编译、调试运行阅读教材214页-215页程序6-1、6-2,理解程序并分析程序运行结果;
l 在程序中相关代码处添加新知识的注释。
l 掌握接口的实现用法;
l 掌握内置接口Compareable的用法。
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 EmployeeSortTest 11 { 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 21 Arrays.sort(staff);//标准类名,用static方法修饰 22 23 // 输出所有关于Employee对象的信息 24 for (Employee e : staff) 25 System.out.println("name=" + e.getName() + ",salary=" + e.getSalary()); 26 } 27 }
1 package interfaces; 2 3 public class Employee implements Comparable<Employee>//创建一个泛型Comparable接口 4 5 { 6 private String name; 7 private double salary; 8 9 public Employee(String name, double salary)//构造方法 10 { 11 this.name = name; 12 this.salary = salary; 13 } 14 15 public String getName() 16 { 17 return name; 18 } 19 20 public double getSalary() 21 { 22 return salary; 23 } 24 25 public void raiseSalary(double byPercent) 26 { 27 double raise = salary * byPercent / 100; 28 salary += raise; 29 } 30 31 /** 32 * Compares employees by salary 33 * @param other another Employee object 34 * @return a negative value if this employee has a lower salary than 35 * otherObject, 0 if the salaries are the same, a positive value otherwise 36 */ 37 public int compareTo(Employee other) 38 { 39 return Double.compare(salary, other.salary);//调用Double包装器类的compare方法 40 } 41 }
结果如下:
总结:
1. 在Java中一个类只能继承一个直接的父类,但可以实现多个接口,间接的实现了多继承。
2.若实现接口的类不是抽象类,则必须实现所有 接口的所有方法,即为所有的抽象方法定义方 法体。
3.一个类在实现某接口抽象方法时,必须使用完 全相同的方法名、参数列表和返回值类型。
4.接口抽象方法的访问控制符已指定为public, 所以类在实现时,必须显式地使用public修饰 符,否则被警告缩小了接口中定义的方法的访 问控制范围。
5.接口不能构造接口对象,但可以声明接口变量以 指向一个实现了该接口的类对象。
5.可以用instanceof检查对象是否实现了某个接口。
测试程序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); } } |
调试结果如下:
1 package bjkn; 2 interface A 3 { 4 double g=9.8; 5 void show( ); 6 }
1 package bjkn; 2 3 class C implements A 4 { 5 public void show( ) 6 {System.out.println("g="+g);} 7 }
1 package bjkn; 2 3 class InterfaceTest 4 { 5 public static void main(String[ ] args) 6 { 7 A a=new C( ); 8 a.show( ); 9 System.out.println("g="+C.g); 10 } 11 }
运行结果如下:
测试程序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.Timer 14 15 public class TimerTest 16 { 17 public static void main(String[] args) 18 { 19 ActionListener listener = new TimePrinter(); 20 21 // 构造一个timer对象存放在变量里,叫做listener 22 // 每次间隔10秒 23 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 ActionListener 32 { 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 /** 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 try 13 { 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 }
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 CloneNotSupportedException 20 { 21 // call Object.clone() 22 Employee cloned = (Employee) super.clone(); 23 24 // clone mutable fields 25 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 day 33 * @param month the month of the hire day 34 * @param day the day of the hire day 35 */ 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 mutation 41 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.当拷贝一个对象变量时,原始变量与拷贝变量 引用同一个对象。这样,改变一个变量所引用 的对象会对另一个变量产生影响。
2.如果要创建一个对象新的copy,它的最初状态与 original一样,但以后可以各自改变状态,就需 要使用Object类的clone方法。
3.浅层拷贝:被拷贝对象的所有常量成员和基本类 型属性都有与原来对象相同的拷贝值,而若成员 域是一个对象,则被拷贝对象该对象域的对象引 用仍然指向原来的对象。
4.深层拷贝:被拷贝对象的所有成员域都含有与原 来对象相同的值,且对象域将指向被复制过的新对 象,而不是原有对象被引用的对象。换言之,深 层拷贝将拷贝对象内引用的对象也拷贝一遍。
实验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-12 11 * @author Cay Horstmann 12 */ 13 public class LambdaTest 14 { 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())/*lambda表达式*/); 29 t.start(); 30 31 // keep program running until user selects "Ok" 32 JOptionPane.showMessageDialog(null, "Quit program?"); 33 System.exit(0); 34 } 35 }
运行结果如下:
总结:
Java Lambda 表达式是Java 8 引入的一个新的功能,主 要用途是提供一个函数化的语法来简化编码。
实验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 Moom{ 13 private static ArrayList<Mest> studentlist; 14 public static void main(String[] args) { 15 studentlist = new ArrayList<>(); 16 Scanner scanner = new Scanner(System.in); 17 File file = new File("D:\身份证号.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 Mest student = new Mest(); 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 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<studentlist.size();i++) 67 { 68 j=studentlist.get(i).getage(); 69 if(j>max) 70 { 71 max=j; 72 k1=i; 73 } 74 if(j<min) 75 { 76 min=j; 77 k2=i; 78 } 79 80 } 81 System.out.println("年龄最大:"+studentlist.get(k1)); 82 System.out.println("年龄最小:"+studentlist.get(k2)); 83 break; 84 case "3": 85 System.out.println("家庭住址:"); 86 String find = scanner.next(); 87 String place=find.substring(0,3); 88 for (int i = 0; i <studentlist.size(); i++) 89 { 90 if(studentlist.get(i).getprovince().substring(1,4).equals(place)) 91 System.out.println("province"+studentlist.get(i)); 92 } 93 break; 94 95 case "4": 96 System.out.println("年龄:"); 97 int yourage = scanner.nextInt(); 98 int near=agematched(yourage); 99 int value=yourage-studentlist.get(near).getage(); 100 System.out.println(""+studentlist.get(near)); 101 break; 102 case "5": 103 isTrue = false; 104 System.out.println("退出程序!"); 105 break; 106 default: 107 System.out.println("输入错误"); 108 109 } 110 } 111 } 112 public static int agematched(int age) { 113 int j=0,min=53,value=0,k=0; 114 for (int i = 0; i < studentlist.size(); i++) 115 { 116 value=studentlist.get(i).getage()-age; 117 if(value<0) value=-value; 118 if (value<min) 119 { 120 min=value; 121 k=i; 122 } 123 } 124 return k; 125 } 126 127 }
1 public class Mest implements Comparable<Mest> { 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 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(Mest o) { 44 return this.name.compareTo(o.getName()); 45 } 46 47 public String toString() { 48 return name+" "+sex+" "+age+" "+number+" "+province+" "; 49 } 50 51 }
结果如下:
实验程序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 ArrayAlg 22 { 23 /** 24 * A pair of floating-point numbers 25 */ 26 public static class Pair 27 { 28 private double first; 29 private double second; 30 31 /** 32 * Constructs a pair from two floating-point numbers 33 * @param f the first number 34 * @param s the second number 35 */ 36 public Pair(double f, double s) 37 { 38 first = f; 39 second = s; 40 } 41 42 /** 43 * Returns the first number of the pair 44 * @return the first number 45 */ 46 public double getFirst() 47 { 48 return first; 49 } 50 51 /** 52 * Returns the second number of the pair 53 * @return the second number 54 */ 55 public double getSecond() 56 { 57 return second; 58 } 59 } 60 61 /** 62 * Computes both the minimum and the maximum of an array 63 * @param values an array of floating-point numbers 64 * @return a pair whose first element is the minimum and whose second element 65 * is the maximum 66 */ 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 }
总结:
1.如果用static修饰一个内部类,这个类就相当于是一个外部定义的类,所以static的内部类中可声明static成员,但非static的内部类中的成员是不能声明为static的。static的内部类不能再使用外部类的非static的成员变量。
2.静态内部类可以创建静态的成员,而非静态的内部类不可以。
3.静态内部类只可以访问外部类中的静态成员变量与成员方法,而非静态的内部类即可以访问所有的外部类成员方法与成员变量。
运行结果如下:
实验总结:
通过这次的实验我知道了在java中类与接口在用法上的一些区别, 在Java中一个类只能继承一个直接的父类,但可以实现多个接口,间接的实现了多继承。还有了解了深层拷贝与浅层拷贝,以及Comparator接口的用法,知道了lambda表达式。最后了解了静态内部类的一些用法,静态内部类可以创建静态的成员,而非静态的内部类不可以。静态内部类只可以访问外部类中的静态成员变量与成员方法,而非静态的内部类即可以访问所有的外部类成员方法与成员变量。