201871010124-王生涛 《面向对象程序设计(java)》第八周学习总结
博文正文开头格式:(2分)
项目 |
内容 |
这个作业属于哪个课程 |
https://www.cnblogs.com/nwnu-daizh/ |
这个作业的要求在哪里 |
https://www.cnblogs.com/nwnu-daizh/p/11435127.html |
作业学习目标 |
|
第一部分:总结第五章理论知识(30分)
Java中类于类之间的关系以及代码示例:
一、继承关系
继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力。在Java中继承关系通过关键字extends明确标识,在设计时一般没有争议性。在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或者子接口指向父接口。
二、实现关系
实现指的是一个class类实现interface接口(可以是多个)的功能,实现是类与接口之间最常见的关系。在Java中此类关系通过关键字implements明确标识,在设计时一般没有争议性。在UML类图设计中,实现用一条带空心三角箭头的虚线表示,从类指向实现的接口。
三、依赖关系
简单的理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是类B的变化会影响到类A。比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖。表现在代码层面,为类B作为参数被类A在某个method方法中使用。在UML类图设计中,依赖关系用由类A指向类B的带箭头虚线表示。
四、关联关系
关联体现的是两个类之间语义级别的一种强依赖关系,比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可以是单向、双向的。表现在代码层面,为被关联类B以类的属性形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端可以标注关联双方的角色和多重性标记。
五、聚合关系
聚合是关联关系的一种特例,它体现的是整体与部分的关系,即has-a的关系。此时整体与部分之间是可分离的,它们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。比如计算机与CPU、公司与员工的关系等,比如一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力攻击潜艇等。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,聚合关系以空心菱形加实线箭头表示。
六、组合关系
组合也是关联关系的一种特例,它体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合。它同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束,比如人和人的大脑。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,组合关系以实心菱形加实线箭头表示。
注意: 继承与实现是类于类,或者类与接口之间的一种纵向关系,其他的四种关系体现的是类和类、或者类与接口间的引用、横向关系,是比较难区分的,有很多事物间的关系要想准确定位是很难的。前面也提到,这四种关系都是语义级别的,所以从代码层面并不能完全区分各种关系,但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖。
1、接口:Java为了克服单继承的特点,Java使用了接口,一个类可以实现一个或者多个接口;
2、在Java中,接口不是类,而是对类的一组需求描述 ,由常量和一组抽象方法组成;
3、接口中不包括变量和具体方法的实现;
4、只要类实现了接口,则该类要遵从接口描述的统一格式进行定义,并且可以在任何需要接口的地方使用这个类得额对象;
5、接口的类型:
用户自定义接口;
标准接口;
1、自定义接口的声明:
(1)声明方式: public interface 接口名
{······}
(2)接口体中包含常量定义和抽象方法的定义 ,接口中只进行方法的声明,不提供实现的方法;
2、类似建立类的继承关系,接口也可以扩展;
3、接口的扩展技术使得从具有较高通用性的接口存在多条链延伸到具有较高专用性的接口;
4、扩展方法:
public interface 接口1 extends 接口2
{······ }
说明:(1)通常接口的名字以able或者ible结尾;
(2)可以通过extends来继承接口的常量和抽象方法,扩展形成新的接口;
(3)接口中的所有常量必须都是 public static final,方法必须是public abstract ,这是系统默认的,写不写修饰符都是一样的;
5、接口的实现:
(1)在类声明时用implements关键字来声明使用一个或者多个接口
class Employee implements Printable
{······ }
(2)一个类使用了某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体;
(3)一个类可以实现多个接口,接口间应该用逗号隔开。
class Employee implements Cloneable , Comparable
说明:(1)若实现接口的类不是抽象类,则必须实现所有接口的所有方法,即为所有的抽象方法定义方法体;
(2)一个类在实现某接口方法时,必须使用完全相同的方法名、参数列表和返回值类型;
(3)接口抽象方法的访问控制符已指定为 public,所以类在实现时,必须显示的使用public修饰符,否则被警告缩小了接口中定义的方法的访问控制范围;
6、接口的使用:
(1)接口不能构造接口对象,但可以声明接口变量以指向一个实现了该接口的类对象;
Comparable x = new Comparable(······ ) //错误
Comparable x = new Employee(······ ) //正确
(2)可以用instanceof来检查对象是否实现了某个接口
if (anObject instanceof Comparable)
{······ }
7、接口与抽象类:
(1)抽象类:用abstract来声明,没有具体实例对象的类,不能用new来创建对象。可包含常规类所包含的任何东西,抽象类必须由子类继承,如果abstract类的子类不是抽象类,那么子类必须重写父类中的所有的abstract方法;
(2)接口:用interface来声明,是抽象方法和常量值构成的集合。从本质上来讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和抽象方法的定义,而没有变量和方法的定义,接口中只能定义抽象方法,而且这些方法默认为public的,只要类实现了接口,就可以在任何需要该接口的地方使用这个类的对象。此外,一个类可以实现多个接口。
8、接口与抽象类的区别:
(1)接口不能实现任何方法,而抽象类可以;
(2)类可以实现很多接口,但只有一个父类;
(3)接口不是一个类分级结构中的一部分,无任何联系的类可以实现相同的接口。
6.2 接口示例
接口与回调
(1)回调:(callback):一种程序设计模式,在这种模式中,可指出某个特定事件发生时,程序应该采取的动作;
(2)在Java.Swing包中有一个Timer类,可以使用它在到达给定的时间间隔时触发的一个事件。
Comparable接口:
用途(1):处理字符串按长度进行排序的操作;
对象克隆:
1、object类当中 的clone方法:
(1)当拷贝一个对象变量时,原始变量与拷贝变量引用同一个对象,这样,改变一个变量所引用的对象会对另一个变量产生影响;
(2)如果要创建一个对象新的copy,它的最初状态与original一样,但以后可以各自改变状态,就需要使用clone方法;
(3)object类中的clone()方法是一个native方法;
(4)object类中的clone()方法被protected修饰符修饰,着以为着在用户编写的代码中不能直接调用它。如果要直接应用clone()方法,就需要覆盖clone()方法,并要把clone()方法的属性设置为public;
(5)object类中的clone()方法返回一个object对象,必须进行强制转换类型才能得到需要的类型;
2、浅层拷贝和深层拷贝
(1)浅层拷贝:被拷贝对象的所有常量成员和基本类型属性都有与原来对象相同的拷贝值,而若成员域是一个对象,则被拷贝对象该对象鱼的对象引用仍然指向原来的对象;
(2)深层拷贝:被拷贝对象的所有成员域都含有与原来对象相同的拷贝值,且对象域将指向被复制过的新对象,而不是原来对象被引用的而对象。
想要实现深层拷贝,必须克隆类中所有的对象的实例域。
3、Java中克隆对象的实现:
对象克隆要点:
(1)在子类中实现Cloneable接口;
(2)为了获取对象的一份拷贝,可以利用Object类的clone方法;
(3)在子类中覆盖超类的clone方法,声明为public;
(4)在子类的clone方法中,调用super.clone();
4、public interface Cloneable{
}
可以看到,这个内置接口Cloneable是空的,它仅仅是一个标志,这样的接口称为标志接口,且这个接口只针对Object类的clone()方法;
如果一个类没有实现Cloneable接口,且调用了Object类的clone()方法(即调用了super.clone()方法),那么Object类的clone方法就会抛出CloneNotSupportedException 异常。
接口学习中的几个问题:
1、精简程序结构,免除代码的重复使用;
(1)如果有两个及以上的类拥有相同的方法,但是实现功能不一样,就可以定义一个接口(抽象类),将这个方法提炼出来,在需要使用该方法的类中去实现,就免除了多个类定义系统方法的麻烦;
(2)由于Java只支持单继承,如果被提炼的方法定义为抽象类,若某个类要扩展两个以上这样的抽象类就会被限制,则这时就可以定义为接口。
6·3、Lambda表达式:主要是提供一个函数化的语法来简化编码。
(1)Lambda表达式本质上是一个匿名方法。
public int add(int x, int y){
return x + y;} 将其转成Lambda表达式为: (int x , int y) -> x + y;
参数类型可以省略,Java编译器会根据上下文推断出来:
(x, y)-> x + y; //返回两数之和
(x, y)->{return x + y;} //显式指明返回值
(2)Lambda表达式的语法基本结构: (arguments)-> body
有如下几种情况:
a、参数类型可推导时,不需要指定类型;eg: (a)->System.out.println(a)
b、只有一个参数且类型可推导时,不强制写(), eg:a->System.out.println(a)
c、参数指定类型时,必须有括号, eg:(int a) -> System.out.println(a)
d、参数可以为空,eg:()-> System.out.println("Hello")
e、body需要用{}包含语句,当只有一条语句时{}可以省略。
(3)函数式接口Functionalinterface
a、Java Lambda表达式以函数式接口为应用基础;
b、函数式接口,只有一个方法的接口,这类接口的目的是为了一个单一的操作;
c、函数式接口用作表示Lambda表达式的类型。
(4)创建函数式接口:
有时候需要自定义一个函数式接口,做法也很简单,首先此接口只能有一个函数操作,然后在接口操作类型上标注注解@Functionalinterface即可
6·4 内部类
(1)内部类(inner class )是定义在一个类内部的类;
(2)外层的类称为外部类(outer class);
(3)内部类主要用于处理事件;
(4)使用内部类的原因:
a、内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据;
b、内部类能够隐藏起来,不为同一包中的其他类可见;
c、想要定义一个回调函数且不想编写大量的代码时,使用匿名内部类比较便捷;
(5)内部类的声明:
class outerClass{
【修饰符】class inner Class{
...........
}
...........
}
内部类可以直接访问外部类的成员,包括private成员,但是内部类的成员却不能被外部类直接访问;
2、实验内容和步骤
实验1: 导入第6章示例程序,测试程序并进行代码注释。
测试程序1:
l 编辑、编译、调试运行阅读教材214页-215页程序6-1、6-2,理解程序并分析程序运行结果;
l 在程序中相关代码处添加新知识的注释。
l 掌握接口的实现用法;
l 掌握内置接口Compareable的用法。
实验代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package interfaces; public class Employee implements Comparable<Employee> //接口的定义,Comparable是内置接口 { private String name; //私有变量的定义 private double salary; public Employee(String name, double salary) //Employee构造器 { this .name = name; this .salary = salary; } public String getName() //getName方法访问器 { return name; } public double getSalary() //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 a lower salary than * otherObject, 0 if the salaries are the same, a positive value otherwise */ public int compareTo(Employee other) //按工资输出 { return Double.compare(salary, other.salary); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package interfaces; import java.util.*; /** * This program demonstrates the use of the Comparable interface. * @version 1.30 2004-02-27 * @author Cay Horstmann */ public class EmployeeSortTest //EmployeeSortTest类 { public static void main(String[] args) { Employee[] staff = new Employee[ 3 ]; //Employee对象数组的创建 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) //调用getNname()方法以及getSalary()方法输出所有雇员的信息 System.out.println( "name=" + e.getName() + ",salary=" + e.getSalary()); } } |
运行结果如下:
测试程序2:
l 编辑、编译、调试以下程序,结合程序运行结果理解程序;
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
interface A //A接口 { double g= 9.8 ; void show( ); } class C implements A //定义C继承接口A { public void show( ) { System.out.println( "g=" +g); //将g的值输出在控制台上 } } class InterfaceTest //InterfaceTest类的定义 { public static void main(String[ ] args) { A a= new C( ); a.show( ); System.out.println( "g=" +C.g); //输出g的值在控制台上 } } |
运行结果如下:
l 在elipse IDE中调试运行教材223页6-3,结合程序运行结果理解程序;测试程序3:
实验代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
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) { ActionListener listener = new TimePrinter(); //构造这个类的一个对象,并将它传递给Timer构造器 //ActionListener接口对象,创建实现类接口的对象 // construct a timer that calls the listener // once every second Timer timer = new Timer( 1000 , listener); //创建定时器类对象timer timer.start(); //启动定时器 // keep program running until the user selects "OK" JOptionPane.showMessageDialog( null , "Quit program?" ); //启动程序后,将会立即弹出一个包含"Quit program?"字样的对话框 System.exit( 0 ); } } class TimePrinter implements ActionListener //接口 { public void actionPerformed(ActionEvent event) //actionPerformed方法的ActionEvent参数,提供了事件的相关信息 { System.out.println( "At the tone, the time is " + Instant.ofEpochMilli(event.getWhen())); //每隔10秒,这条信息就会输出一次,然后响一声铃 Toolkit.getDefaultToolkit().beep(); //返回Toolkit,调用getDefaultToolkit()方法,获得默认的工具箱 } } |
运行结果如下:
l 26行、36行代码参阅224页,详细内容涉及教材12章。
l 在程序中相关代码处添加新知识的注释。
l 掌握回调程序设计模式;
测试程序4:
l 调试运行教材229页-231页程序6-4、6-5,结合程序运行结果理解程序;
l 在程序中相关代码处添加新知识的注释。
l 掌握对象克隆实现技术;
l 掌握浅拷贝和深拷贝的差别。
实验代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
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) //Employee构造器 { this .name = name; this .salary = salary; hireDay = new Date(); } public Employee clone() throws CloneNotSupportedException //声明异常,在一个对象上调用clone,但这个 对象的类并没有实现Cloneable的接口,然后Object类的clone方法就会抛出一个 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 + "]" ; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package clone; /** * This program demonstrates cloning. * @version 1.11 2018-03-16 * @author Cay Horstmann */ public class CloneTest { public static void main(String[] args) throws CloneNotSupportedException { Employee original = new Employee( "John Q. Public" , 50000 ); original.setHireDay( 2000 , 1 , 1 ); Employee copy = original.clone(); //原始变量与拷贝变量引用统一个对象,这样,使用Object类的Clone对象,改变一个对象所引用的对象就不会影响另一个对象 copy.raiseSalary( 10 ); //copy会增长10%的薪资,但是original不会变 copy.setHireDay( 2002 , 12 , 31 ); System.out.println( "original=" + original); System.out.println( "copy=" + copy); } } |
运行结果如下:
浅层拷贝和深层拷贝的差别:
(1)浅层拷贝:被拷贝对象的所有常量成员和基本类型属性都有与原来对象相同的拷贝值,而若成员域是一个对象,则被拷贝对象该对象鱼的对象引用仍然指向原来的对象;
(2)深层拷贝:被拷贝对象的所有成员域都含有与原来对象相同的拷贝值,且对象域将指向被复制过的新对象,而不是原来对象被引用的而对象。
想要实现深层拷贝,必须克隆类中所有的对象的实例域。
实验2: 导入第6章示例程序6-6,学习Lambda表达式用法。
l 调试运行教材233页-234页程序6-6,结合程序运行结果理解程序;
l 在程序中相关代码处添加新知识的注释。
l 将27-29行代码与教材223页程序对比,将27-29行代码与此程序对比,体会Lambda表达式的优点。
实验代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package lambda; import java.util.*; import javax.swing.*; import javax.swing.Timer; /** * This program demonstrates the use of lambda expressions. * @version 1.0 2015-05-12 * @author Cay Horstmann */ public class LambdaTest //LambdaTest类 { public static void main(String[] args) { String[] planets = new String[] { "Mercury" , "Venus" , "Earth" , "Mars" , "Jupiter" , "Saturn" , "Uranus" , "Neptune" }; //创建一个String类数组对象 System.out.println(Arrays.toString(planets)); //调用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()); //可以推导出first以及second的类型 System.out.println(Arrays.toString(planets)); Timer timer = new Timer( 1000 , event -> //如果方法只有一个参数,则这个参数的类型可以推导出 System.out.println( "The time is " + new Date())); timer.start(); //计时器开始 // keep program running until user selects "OK" JOptionPane.showMessageDialog( null , "Quit program?" ); System.exit( 0 ); } } |
运行结果如下:
实验2:内部类语法验证实验
实验程序1:
l 编辑、调试运行教材246页-247页程序6-7,结合程序运行结果理解程序;
l 了解内部类的基本用法。
实验代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
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) { TalkingClock clock = new TalkingClock( 1000 , true ); //创建TalkingClock对象, clock.start(); // keep program running until the user selects "OK" JOptionPane.showMessageDialog( null , "Quit program?" ); //当程序开始运行的时候立即出现写有“Quit program”的对话框 System.exit( 0 ); } } /** * A clock that prints the time in regular intervals. */ class TalkingClock //抽象一个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) //TalkingClock构造器 { this .interval = interval; this .beep = beep; } /** * Starts the clock. */ public void start() //方法声明 { TimePrinter listener = new TimePrinter(); //创建一个TimePrinter对象,其在TalkingClock的内部 Timer timer = new Timer(interval, listener); timer.start(); //启动 } public class TimePrinter implements ActionListener //将TimePrinter类声明为实现ActionListener接口 { public void actionPerformed(ActionEvent event) //actionPerformed方法在发出铃声之前检查了beep标志 { System.out.println( "At the tone, the time is " + Instant.ofEpochMilli(event.getWhen())); if (beep) Toolkit.getDefaultToolkit().beep(); } } } |
运行结过如下:
实验程序2:
l 编辑、调试运行教材254页程序6-8,结合程序运行结果理解程序;
l 掌握匿名内部类的用法。
实验代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
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) { TalkingClock clock = new TalkingClock(); //创建一个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 //抽象一个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) //方法声明 { ActionListener listener = new ActionListener() //创建一个实现ActionListener接口的类的新对象, { public void actionPerformed(ActionEvent event) //需要实现的方法定义在ActionListener括号{}内 { System.out.println( "At the tone, the time is " + Instant.ofEpochMilli(event.getWhen())); if (beep) Toolkit.getDefaultToolkit().beep(); //在响铃之前actionPerformed检查了beep } }; Timer timer = new Timer(interval, listener); //创建一个Timer类对象 timer.start(); //启动计时器 } } |
运行结果如下:
实验程序3:
l 在elipse IDE中调试运行教材257页-258页程序6-9,结合程序运行结果理解程序;
l 了解静态内部类的用法。
实验代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
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) { double [] values = new double [ 20 ]; //定义一个double对象数组 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()); //这个方法的调用者可以使用getFirst和getSecond方法获得答案 System.out.println( "max = " + p.getSecond()); } } class ArrayAlg //抽象一个ArrayAlg类 { /** * A pair of floating-point numbers */ public static class Pair //在Pair对象中不需要引用任何其他的对象,所以将这个内部类声明为static { 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) //Pair构造器 { first = f; second = s; } /** * Returns the first number of the pair * @return the first number */ public double getFirst() //getFirst方法声明 { return first; } /** * Returns the second number of the pair * @return the second number */ public double getSecond() //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) //必须使用静态内部类,因为内部类对象是在静态方法中定义的,如果没有将Pair声明为static,编译器会报错,没有可用的隐式ArrayAlg类型对象初始化内部对象 { 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); //minmax必须返回返回一个Pair类型的对象 } } |
运行结过如下:
实验3: 编程练习
l 编制一个程序,将身份证号.txt 中的信息读入到内存中;
l 按姓名字典序输出人员信息;
l 查询最大年龄的人员信息;
l 查询最小年龄人员信息;
l 输入你的年龄,查询身份证号.txt中年龄与你最近人的姓名、身份证号、年龄、性别和出生地;
l 查询人员中是否有你的同乡。
实验代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Scanner; public class IDTest{ private static ArrayList<Student> studentlist; public static void main(String[] args) { studentlist = new ArrayList<>(); Scanner scanner = new Scanner(System.in); File file = new File( "D:\\java\\身份证号.txt" ); //将文件引入 try { FileInputStream fis = new FileInputStream(file); BufferedReader in = new BufferedReader( new InputStreamReader(fis)); String temp = null ; while ((temp = in.readLine()) != null ) { Scanner linescanner = new Scanner(temp); linescanner.useDelimiter( " " ); String name = linescanner.next(); String number = linescanner.next(); String sex = linescanner.next(); String age = linescanner.next(); String province =linescanner.nextLine(); Student student = new Student(); student.setName(name); student.setnumber(number); student.setsex(sex); int a = Integer.parseInt(age); student.setage(a); student.setprovince(province); studentlist.add(student); } } catch (FileNotFoundException e) { System.out.println( "学生信息文件找不到" ); e.printStackTrace(); } catch (IOException e) { System.out.println( "学生信息文件读取错误" ); e.printStackTrace(); } boolean isTrue = true ; while (isTrue) { System.out.println( "1:按姓名字典序输出人员信息;" ); System.out.println( "2:查询最大年龄与最小年龄人员信息;" ); System.out.println( "3.输入你的年龄,查询身份证号.txt中年龄与你最近人的姓名、身份证号、年龄、性别和出生地" ); System.out.println( "4:按省份找你的同乡;" ); System.out.println( "5:退出" ); String m = scanner.next(); switch (m) { case "1" : Collections.sort(studentlist); System.out.println( "排序后的结果为:" + "\n" ); System.out.println(studentlist.toString()); break ; case "2" : int max= 0 ,min= 100 ; int j,k1 = 0 ,k2= 0 ; for ( int i= 1 ;i<studentlist.size();i++) { j=studentlist.get(i).getage(); if (j>max) { max=j; k1=i; } if (j<min) { min=j; k2=i; } } System.out.println( "Max age:" +studentlist.get(k1)); System.out.println( "Min age:" +studentlist.get(k2)); break ; case "3" : System.out.println( "age:" ); int yourage = scanner.nextInt(); int near=agenear(yourage); int value=yourage-studentlist.get(near).getage(); System.out.println( "年龄与你最近的人的姓名、身份证号、年龄、性别和出生地为:" + "\n" ); System.out.println( "" +studentlist.get(near)); break ; case "4" : System.out.println( " Which province were you born in?" ); String find = scanner.next(); String place=find.substring( 0 , 3 ); for ( int i = 0 ; i <studentlist.size(); i++) { if (studentlist.get(i).getprovince().substring( 1 , 4 ).equals(place)) System.out.println( "查找到的老乡有:" + "\n" +studentlist.get(i)); } break ; case "5" : isTrue = false ; System.out.println( "退出程序!!!!" ); break ; default : System.out.println( "信息输入有误!!!" ); } } } public static int agenear( int age) { int j= 0 ,min= 53 ,value= 0 ,k= 0 ; for ( int i = 0 ; i < studentlist.size(); i++) { value=studentlist.get(i).getage()-age; if (value< 0 ) value=-value; if (value<min) { min=value; k=i; } } return k; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
public class Student implements Comparable<Student> { //定义实现Comparable<Student>接口的类Student private String name; //私有变量的定义 private String number ; private String sex ; private int age; private String province; public String getName() { //构造器 return name; } public void setName(String name) { //访问器 this .name = name; } public String getnumber() { return number; } public void setnumber(String number) { this .number = number; } public String getsex() { return sex ; } public void setsex(String sex ) { this .sex =sex ; } public int getage() { return age; } public void setage( int age) { this .age= age; } public String getprovince() { return province; } public void setprovince(String province) { this .province=province ; } public int compareTo(Student o) { //compareTo方法将会返回一个整型数值 return this .name.compareTo(o.getName()); } public String toString() { return name+ "\t" +sex+ "\t" +age+ "\t" +number+ "\t" +province+ "\n" ; } } |
运行结果如下:
实验总结:(10分)
主要了解了接口,接口和继承在某些方面比较相似,但是接口又在继承的基础上发展了一些优点,克服了java单继承的缺点。实现接口类的定义要求,实现了接口类的使用要求,理解程序回调设计模式,掌握了Comparator接口用法:对象克隆需要实现Cloneable接口,如果没有实现Cloneable接口,且调用了Object的clone()方法,就会抛出CloneNotSupportedException异常 ,掌握到对象浅层拷贝与深层拷贝方法了解到它们的区别,Lambda表达式语法等等的要求