201871010135 张玉晶 《面向对象程序设计(java)》第八周学习总结》
项目 |
内容 |
这个作业属于哪个课程 |
<任课教师博客主页链接> https://www.cnblogs.com/nwnu-daizh/ |
这个作业的要求在哪里 |
<作业链接地址>https://www.cnblogs.com/nwnu-daizh/p/11703678.html |
作业学习目标 |
|
第一部分:总结第六章理论知识
一: 接口:
a. Java为了克股单继承的缺点。Java使用了接口,一个类可以实现一个或多个接口.
b. 在Java中。 接口不是类而是对类的一组需求描述。由常量和一组抽象方法组成.
c. 接口中不包括变量和有具体实现的方法。
d. 接口不能构造接口对象,但可以声明接口变量
e. 自定义接口的声明: public interface 接口名
f. 类实现某个接口: class 类 inplements 接口名
g. 接口可以扩展 public interface 接口1 extends 接口2
h. int compareTo(T other)
用这个对象与other进行比较,如果这个对象小于other则返回负值,如果相等则返回0,否则返回正值。
static void sort(Object[ ] a)
对数组a中的元素进行排序。要求数组中的元素必须属于实现了Comparable接口的类,并且元素之间必须是可比较的。
static int compare(int x,int y)7
如果x<y返回一个一个负整数,如果x和y相等,则返回0,否则返回一个负整数。
static int compare(double x,double y)1.4
如果x<y返回一个负数,如果x和y相等则返回一个0,否则返回一个负数。
i. 接口与抽象类的区别:
(1)接口不能实现任何方法,而抽象类可以;
(2)类可以实现很多接口,但只有一个父类;
(3)接口不是一个类分级结构中的一部分,无任何联系的类可以实现相同的接口。
二:接口示例:
1. 接口与回调:回调:一种程序设计模式,可以指出某个特定事件发生时应该采取的动作。java.swing包中Timer类,可以使用它在到达给定的时间间隔时触发一个事件。
2. 对象克隆: 当拷贝一个对象变量时,原始变量与拷贝变量引用同一个对象,这样,改变一个变量所引用的对象会对另一个变量产生影响;
如果要创建一个对象新的copy,它的最初状态与original一样,但以后可以各自改变状态,就需要使用0bject类的clone方法。
三:Lambda表达式:
(String first,String second) -> first.length() - second.length() 参数 箭头 表达式
1 .参数类型可推导时.不得要指定类型.如(a)> System.out.println(a)
2. 只有一个参数且类型可推导时。不强制写()
3. 参数指定类型时。必须有括号。
四:内部类:
1. 内部类可以直接访问外部类的成员保括private成员,但是内部类的成员却不能被外部类直接访问。
2. 在内部类对象保存了一个对外部类对象的引用,当内部类的成员方法中访问某一变量时, 如果在该方法和内部类中都未定义过这个变里,内部类中对变里的引用会被传递给外部类对象的引用。
3. 内部类并非只能在类内定义,也可以在程序块内定义局部内部类。例如,在方法中,甚至在for循环体内部。
4. 局部内部类不能用publi c或pr ivate访问修饰符进行声明,它的作用域被限定在声明这个局部类的块中。
匿名内部类
1. 若只创建类的一个对象,则不必为该类命名,这种类称为匿名内部类。
2. 由于匿名类没有类名,所以匿名类不能有构造器,取而代之的是将构造器参数传递给超类的构造器。若匿名内部类实现接口时,则匿名内部类不能有任何构造参数。
3. 如果构造参数的闭圆括号跟一个开花括号,表明正在定义的就是匿名内部类
静态内部类: 静态内部类不持有外部类的引用,只能访问外部类的静态成员变量和方法,而不能访问外部类的非静态成员属性和非静态方法,如果要调用和访问,必须实例化外部类对象。
当静态内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的
是静态内部类的成员。如果要访问外部类的非静态同名成员,不能再使用外部类.this.成员
的形式,而是要实例化外部类对象。如果要访问外部类的静态同名成员,可以通过外部类.成员
的方式来访问。
与常规内部类不同,静态内部类可以有静态变量和静态方法。可以通过外部类.内部类.静态成员
方式来访问。
第二部分
1、实验目的与要求
(1) 掌握接口定义方法;
(2) 掌握实现接口类的定义要求;
(3) 掌握实现了接口类的使用要求;
(4) 掌握程序回调设计模式;
(5) 掌握Comparator接口用法;
(6) 掌握对象浅层拷贝与深层拷贝方法;
(7) 掌握Lambda表达式语法;
(8) 了解内部类的用途及语法要求。
2、实验内容和步骤
实验1: 导入第6章示例程序,测试程序并进行代码注释。
测试程序1:
EmployeeSortTest.java
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 Arrays.sort(staff);//使用Arrays类的sort方法,对Employee 对象数组进行排序 21 22 // 打印出关于 Employee 类的所有信息 23 for (Employee e : staff) 24 System.out.println("name=" + e.getName() + ",salary=" + e.getSalary()); 25 } 26 }
运行结果如下:
a. Employee.java:
1 package interfaces; 2 3 public class Employee implements Comparable<Employee>//Employee类实现泛型Comparable接口 4 { 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 salary 32 * @param other another Employee object 33 * @return a negative value if this employee has a lower salary than 34 * otherObject, 0 if the salaries are the same, a positive value otherwise 35 */ 36 //实现compareTo方法 37 public int compareTo(Employee other) 38 { 39 return Double.compare(salary, other.salary); 40 } 41 }
运行结果如下:
b.:
1 package interfaces; 2 3 public class Employee implements Comparable<Employee>//Employee类实现泛型Comparable接口 4 { 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 salary 32 * @param other another Employee object 33 * @return a negative value if this employee has a lower salary than 34 * otherObject, 0 if the salaries are the same, a positive value otherwise 35 */ 36 //实现compareTo方法 37 public int compareTo(Employee other) 38 { 39 return name.compareTo(other.name);//按姓名排序 40 } 41 }
测试程序2:
编辑、编译、调试以下程序,结合程序运行结果理解程序;
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); } } |
Interface Test.java:
1 package interfaces; 2 interface A //自定义一个接口A 3 { 4 double g=9.8; 5 void show( ); 6 } 7 class C implements A//类C 实现接口A 8 { 9 public void show( ) 10 {System.out.println("g="+g);} 11 } 12 13 class InterfaceTest 14 { 15 public static void main(String[ ] args) 16 { 17 A a=new C( ); 18 a.show( ); 19 System.out.println("g="+C.g); 20 } 21 }
运行结果如下:
测试程序3:
在elipse IDE中调试运行教材223页6-3,结合程序运行结果理解程序;
TimerTest.java:
1 package timer; 2 3 /** 4 @version 1.02 2017-12-14 5 @author Cay Horstmann 6 */ 7 8 import java.awt.*; 9 import java.awt.event.*; 10 import java.time.*; 11 import javax.swing.*; 12 13 public class TimerTest 14 { 15 public static void main(String[] args) 16 { 17 ActionListener listener = new TimePrinter(); 18 19 // 构造一个listener的计时器 20 // once every second 21 Timer t = new Timer(1000, listener); 22 t.start(); 23 24 // 保持程序运行,直到用户选择 "OK" 25 JOptionPane.showMessageDialog(null, "Quit program?"); 26 System.exit(0); 27 } 28 } 29 30 class TimePrinter implements ActionListener//类TimePrinter实现接口ActionListener 31 { 32 public void actionPerformed(ActionEvent event) 33 { 34 System.out.println("At the tone, the time is " 35 + Instant.ofEpochMilli(event.getWhen())); 36 Toolkit.getDefaultToolkit().beep(); 37 } 38 }
运行结果如下:
测试程序4:
调试运行教材229页-231页程序6-4、6-5,结合程序运行结果理解程序;
CloneTest.java:
1 package clone; 2 3 /** 4 * This program demonstrates cloning. 5 * @version 1.11 2018-03-16 6 * @author Cay Horstmann 7 */ 8 public class CloneTest 9 { 10 public static void main(String[] args) throws CloneNotSupportedException //如果在一个对象上调用clone,如果对象的类没有实现Cloneable的接口。clone方法就会抛出CloneNotSupportedException 11 { 12 Employee original = new Employee("John Q. Public", 50000); 13 original.setHireDay(2000, 1, 1); 14 //clone方法创建新对象copy,初始状态与Original相同,之后有不同的状态 15 Employee copy = original.clone(); 16 copy.raiseSalary(10); 17 copy.setHireDay(2002, 12, 31); 18 System.out.println("original=" + original); 19 System.out.println("copy=" + copy); 20 } 21 }
运行结果如下:
Employee.java:
1 package clone; 2 3 import java.util.Date; 4 import java.util.GregorianCalendar; 5 6 public class Employee implements Cloneable// Employee类 实现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 //如果在一个对象上调用clone,如果对象的类没有实现Cloneable的接口。clone方法就会抛出CloneNotSupportedException 20 { 21 // call Object.clone() 22 Employee cloned = (Employee) super.clone(); 23 24 // 克隆可变字段 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 }
运行结果如下:
实验2: 导入第6章示例程序6-6,学习Lambda表达式用法。
LambdaTest.java:
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));//toString()方法输出planets 20 System.out.println("Sorted in dictionary order:"); 21 Arrays.sort(planets);//Arrays.sort方法按字符顺序排序 22 System.out.println(Arrays.toString(planets)); 23 System.out.println("Sorted by length:"); 24 //Arrays.sort方法按字符串长度排序 25 Arrays.sort(planets, (first, second) -> first.length() - second.length()); 26 System.out.println(Arrays.toString(planets)); 27 //lambda表达式:(argument)->body 28 Timer timer = new Timer(1000, event -> 29 System.out.println("The time is " + new Date())); 30 timer.start(); 31 32 // 程序保持运行,直到用户选择 "OK" 33 JOptionPane.showMessageDialog(null, "Quit program?"); 34 System.exit(0); 35 } 36 }
运行结果如下:
实验3: 编程练习
l 编制一个程序,将身份证号.txt 中的信息读入到内存中;
l 按姓名字典序输出人员信息;
l 查询最大年龄的人员信息;
l 查询最小年龄人员信息;
l 输入你的年龄,查询身份证号.txt中年龄与你最近人的姓名、身份证号、年龄、性别和出生地;
l 查询人员中是否有你的同乡。
程序代码如下:
1 package ID; 2 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.FileInputStream; 6 import java.io.FileNotFoundException; 7 import java.io.IOException; 8 import java.io.InputStreamReader; 9 import java.util.ArrayList; 10 import java.util.Scanner; 11 import java.util.Collections; 12 13 public class Main { 14 private static ArrayList<Citizen> citizenlist; 15 16 public static void main(String[] args) { 17 citizenlist = new ArrayList<>(); 18 Scanner scanner = new Scanner(System.in); 19 File file = new File("D://身份证号.txt"); 20 try { 21 FileInputStream fis = new FileInputStream(file); 22 BufferedReader in = new BufferedReader(new InputStreamReader(fis)); 23 String temp = null; 24 while ((temp = in.readLine()) != null) { 25 26 Scanner linescanner = new Scanner(temp); 27 28 linescanner.useDelimiter(" "); 29 String name = linescanner.next(); 30 String id = linescanner.next(); 31 String sex = linescanner.next(); 32 String age = linescanner.next(); 33 String birthplace = linescanner.nextLine(); 34 Citizen citizen = new Citizen(); 35 citizen.setName(name); 36 citizen.setId(id); 37 citizen.setSex(sex); 38 // 将字符串转换成10进制数 39 int ag = Integer.parseInt(age); 40 citizen.setage(ag); 41 citizen.setBirthplace(birthplace); 42 citizenlist.add(citizen); 43 44 } 45 } catch (FileNotFoundException e) { 46 System.out.println("信息文件找不到"); 47 e.printStackTrace(); 48 } catch (IOException e) { 49 System.out.println("信息文件读取错误"); 50 e.printStackTrace(); 51 } 52 boolean isTrue = true; 53 while (isTrue) { 54 55 System.out.println("1.按姓名字典序输出人员信息"); 56 System.out.println("2.查询最大年龄的人员信息、查询最小年龄人员信息"); 57 System.out.println("3.查询人员中是否有你的同乡"); 58 System.out.println("4.输入你的年龄,查询文件中年龄与你最近人的姓名、身份证号、年龄、性别和出生地"); 59 System.out.println("5.退出"); 60 int nextInt = scanner.nextInt(); 61 switch (nextInt) { 62 case 1: 63 Collections.sort(citizenlist); 64 System.out.println(citizenlist.toString()); 65 break; 66 case 2: 67 int max = 0, min = 100; 68 int m, k1 = 0, k2 = 0; 69 for (int i = 1; i < citizenlist.size(); i++) { 70 m = citizenlist.get(i).getage(); 71 if (m > max) { 72 max = m; 73 k1 = i; 74 } 75 if (m < min) { 76 min = m; 77 k2 = i; 78 } 79 } 80 System.out.println("年龄最大:" + citizenlist.get(k1)); 81 System.out.println("年龄最小:" + citizenlist.get(k2)); 82 break; 83 case 3: 84 System.out.println("出生地:"); 85 String find = scanner.next(); 86 String place = find.substring(0, 3); 87 for (int i = 0; i < citizenlist.size(); i++) { 88 if (citizenlist.get(i).getBirthplace().substring(1, 4).equals(place)) 89 System.out.println("出生地" + citizenlist.get(i)); 90 } 91 break; 92 case 4: 93 System.out.println("年龄:"); 94 int yourage = scanner.nextInt(); 95 int near = peer(yourage); 96 int j = yourage - citizenlist.get(near).getage(); 97 System.out.println("" + citizenlist.get(near)); 98 break; 99 case 5: 100 isTrue = false; 101 System.out.println("程序已退出!"); 102 break; 103 default: 104 System.out.println("输入有误"); 105 } 106 } 107 } 108 109 public static int peer(int age) { 110 int flag = 0; 111 int min = 53, j = 0; 112 for (int i = 0; i < citizenlist.size(); i++) { 113 j = citizenlist.get(i).getage() - age; 114 if (j < 0) 115 j = -j; 116 if (j < min) { 117 min = j; 118 flag = i; 119 } 120 } 121 return flag; 122 } 123 }
1 package ID; 2 public class Citizen implements Comparable<Citizen> { 3 4 private String name; 5 private String id; 6 private String sex; 7 private int age; 8 private String birthplace; 9 10 public String getName() { 11 return name; 12 } 13 14 public void setName(String name) { 15 this.name = name; 16 } 17 18 public String getId() { 19 return id; 20 } 21 22 public void setId(String id) { 23 this.id = id; 24 } 25 26 public String getSex() { 27 return sex; 28 } 29 30 public void setSex(String sex) { 31 this.sex = sex; 32 } 33 34 public int getage() { 35 return age; 36 } 37 38 public void setage(int age) { 39 this.age = age; 40 } 41 42 public String getBirthplace() { 43 return birthplace; 44 } 45 46 public void setBirthplace(String birthplace) { 47 this.birthplace = birthplace; 48 } 49 50 public int compareTo(Citizen other) { 51 return this.name.compareTo(other.getName()); 52 } 53 54 public String toString() { 55 return name + "\t" + sex + "\t" + age + "\t" + id + "\t" + birthplace + "\n"; 56 } 57 }
运行结果如下:
实验4:内部类语法验证实验
实验程序1:
l 编辑、调试运行教材246页-247页程序6-7,结合程序运行结果理解程序;
l 了解内部类的基本用法。
InnerClassTest.java:
1 package innerClass; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.time.*; 6 7 import javax.swing.*; 8 9 /** 10 * This program demonstrates the use of inner classes. 11 * @version 1.11 2017-12-14 12 * @author Cay Horstmann 13 */ 14 public class InnerClassTest 15 { 16 public static void main(String[] args) 17 { 18 TalkingClock clock = new TalkingClock(1000, true); 19 clock.start(); 20 21 // 保持程序运行直到用户选择"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 TalkingClock 31 { 32 private int interval; 33 private boolean beep; 34 35 /** 36 * Constructs a talking clock 37 * @param interval the interval between messages (in milliseconds) 38 * @param beep true if the clock should beep 39 */ 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 TimePrinter listener = new TimePrinter(); 52 Timer timer = new Timer(interval, listener); 53 timer.start(); 54 } 55 56 public class TimePrinter implements ActionListener//类TimePrinter 实现接口 ActionListener 57 { 58 public void actionPerformed(ActionEvent event) 59 { 60 System.out.println("At the tone, the time is " 61 + Instant.ofEpochMilli(event.getWhen())); 62 if (beep) Toolkit.getDefaultToolkit().beep(); 63 } 64 } 65 }
运行结果如下:
实验程序2:
l 编辑、调试运行教材254页程序6-8,结合程序运行结果理解程序;
l 掌握匿名内部类的用法。
程序代码如下:
1 package AnonymouslnnerClass; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.time.*; 6 7 import javax.swing.*; 8 9 /** 10 * This program demonstrates anonymous inner classes. 11 * @version 1.12 2017-12-14 12 * @author Cay Horstmann 13 */ 14 public class AnonymousInnerClassTest 15 { 16 public static void main(String[] args) 17 { 18 TalkingClock clock = new TalkingClock(); 19 clock.start(1000, true); 20 21 // 保持程序运行直到用户选择"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 TalkingClock 31 { 32 /** 33 * Starts the clock. 34 * @param interval the interval between messages (in milliseconds) 35 * @param beep true if the clock should beep 36 */ 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 " 44 + Instant.ofEpochMilli(event.getWhen())); 45 if (beep) Toolkit.getDefaultToolkit().beep(); 46 } 47 }; 48 Timer timer = new Timer(interval, listener); 49 timer.start(); 50 } 51 }
运行结果如下:
实验程序3:
l 在elipse IDE中调试运行教材257页-258页程序6-9,结合程序运行结果理解程序;
l 了解静态内部类的用法。
程序代码如下:
1 /** 2 * This program demonstrates the use of static inner classes. 3 * @version 1.02 2015-05-12 4 * @author Cay Horstmann 5 */ 6 public class StaticInnerClassTest 7 { 8 public static void main(String[] args) 9 { 10 double[] values = new double[20]; 11 for (int i = 0; i < values.length; i++) 12 values[i] = 100 * Math.random(); 13 ArrayAlg.Pair p = ArrayAlg.minmax(values); 14 System.out.println("min = " + p.getFirst()); 15 System.out.println("max = " + p.getSecond()); 16 } 17 } 18 19 class ArrayAlg 20 { 21 /** 22 * A pair of floating-point numbers 23 */ 24 public static class Pair //在Pair对象中不需要引用任何其他的对象,所以将这个内部类声明为static 25 { 26 private double first; 27 private double second; 28 29 /** 30 * Constructs a pair from two floating-point numbers 31 * @param f the first number 32 * @param s the second number 33 */ 34 public Pair(double f, double s) 35 { 36 first = f; 37 second = s; 38 } 39 40 /** 41 * Returns the first number of the pair 42 * @return the first number 43 */ 44 public double getFirst() 45 { 46 return first; 47 } 48 49 /** 50 * Returns the second number of the pair 51 * @return the second number 52 */ 53 public double getSecond() 54 { 55 return second; 56 } 57 } 58 59 /** 60 * Computes both the minimum and the maximum of an array 61 * @param values an array of floating-point numbers 62 * @return a pair whose first element is the minimum and whose second element 63 * is the maximum 64 */ 65 public static Pair minmax(double[] values)//必须使用静态内部类,因为内部类对象是在静态方法中定义的,如果没有将Pair声明为static,编译器会报错,没有可用的隐式ArrayAlg类型对象初始化内部对象 66 { 67 double min = Double.POSITIVE_INFINITY; 68 double max = Double.NEGATIVE_INFINITY; 69 for (double v : values) 70 { 71 if (min > v) min = v; 72 if (max < v) max = v; 73 } 74 return new Pair(min, max); //minmax必须返回返回一个Pair类型的对象 75 } 76 }
运行结果如下:
实验总结: 在本次实验中,我学习了接口,接口克服了java单继承的缺点,一个类可以实现一个或多个接口., 接口中不包括变量和有具体实现的方法,接口不能构造接口对象,但可以声明接口变量;
自定义接口的声明: public interface 接口名; 类实现某个接口: class 类 inplements 接口名 ; 接口可以扩展 public interface 接口1 extends 接口,以及接口的一些方法;
Lambda表达式: (String first,String second) -> first.length() - second.length() 参数 箭头 表达式 , 参数指定类型时,必须有括号, 只有一个参数且类型可推导时,不强制写();还有内部类,匿名内部类和静态内部类。 在实验过程中遇到了很多困难,尤其是编程练习的时候,在参考了其他代码以及问同学的情况下,还算有了一些进步。