201871010102-常龙龙《面向对象程序设计(java)》第八周学习总结
项目 |
内容 |
这个作业属于哪个课程 |
https://www.cnblogs.com/nwnu-daizh/ |
这个作业的要求在哪里 |
https://www.cnblogs.com/nwnu-daizh/p/11703678.html |
作业学习目标 |
|
第一部分:总结第六章理论知识(30分)
一、接口
1.接口技术主要用来描述类具有什么功能,而并不给出每个功能的具体实现。一个类可以实现一个或多个接口,并在需要接口的地方,随时使用实现了相应接口的对象。
●Java为了克服单继承的缺点,Java使用了接口,一 -个类可以实现-一个或多个接口。
●在Java中,接口不是类,而是对类的-组需求描述,由常量和一组抽象方法组成。
●接口中不包括变量和有具体实现的方法。
●只要类实现了接口,则该类要遵从接口描述的统一 格式进行定义,并且可以在任何需要该接口的地方使用这个类的对象。
●接口类型
1.用户自定义接口
2.标准接口。
2.自定义接口的声明
1>声明方式:public interface 接口名
{.....}
2> 接口体中包含常量定义和抽象方法定义,接口中
只进行方法的声明,不提供方法的实现。
3> 说明
(1) 通常接口的名字以able或ible结尾;
(2) 可以使用ex tends来继承接口的常量和抽象方法,扩展形成新的接口;
(3) 接口中的所有常量必须是public static final,方法必须是public abstract,这是系统默认的,不管你在定义接口时,写不写修饰符都是一样的。
3.接口的实现
● 在类声明时用implements关键字声明使用一个或多个接口
class Employee implements Printable
{ ....... }
●一个类使用了某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体。
●一个类可以实现多个接口,接口间应该用逗号分隔开。
class Employee implements Cl oneable, Comparable
{.....}
说明:
(1)若实现接口的类不是抽象类,则必须实现所有接口的所有方法,即为所有的抽象方法定义方法体。
(2)一个类在实现某接口抽象方法时,必须使用完全相同的方法名、参数列表和返回值类型。
(3)接口抽象方法的访问控制符已指定为public,所以类在实现时,必须显式地使用public修饰符,否则被警告缩小了接口中定义的方法的访问控制范围。
4.接口的使用
●接口不能构造接口对象,但可以声明接口变量以指向一个实现了该接口的类对象。
Comparable x = new Comparabe() ;//error
Comparable x= new Employee(); //0K
●可以用instanceof检查对象是否实现了某个接口
if (an0bject instanceof Comparable)
{ ......}
5.接口与抽象类的区别:
(1)接口不能实现任何方法,而抽象类可以。
(2)类可以实现许多接口,但只有一个父类。
(3)接口不是类分级结构的一部分,无任何联系的类可以实现相同的接口。
二、Lambda表达式
1.Lambda表达式的语法基本结构(arguments)->body
有如下几种情况: ●参数类型可推导时,不需要指定类型,如(a)->System.out.println(a)
●只有一个参数且类型可推导时,不强制写(),如a->System.out.println(a)
●参数指定类型时,必须有括号,如(inta)>System.out.println(a)
●参数可以为空,如()->System.out.println(“hello”)
● body需要用包含语句,当只有一条语句时&可省略;
2.Java Lambda表达式是Java8引入的一个新的功能,主要用途是提供一个函数化的语法来简化编码。
Lambda表达式本质上是一个匿名方法。
public int add(int x,int y){returnx+y;}
转成Lambda表达式后是这个样子:(int x,int y)->x+y;
参数类型也可以省略,Java编译器会根据上下文推断出来:(x,y)->x+y;//返回两数之和或者(x,y)->{returnx+y;}//显式指明返回值
三、内部类
1.内部类(inner class)是定义在一个类内部的类。外层的类成为外部类(outer class).内部类主要用于事件处理。使用内部类的原因:
●内部类方法可以访问该类定义所在的作用域中的数据, 包括私有的数据。
●内部类可以对同一个包中的其他类隐藏起来。
●当想要定义一个回调函数且不想编写大量代码时,使用匿名 (anonymous) 内部类比较便捷。
2.局部内部类
●可以在一个方法中定义局部类,并且不能用public或private访问说明符进行声明,它的作用域被限定在声明这个局部类的块中。
●局部类可以对外部世界完全隐藏起来,即使方法所在类中的其他代码也不能访问。除了定义它的方法外,没有任何方法知道它的存在。
●局部类的另一个优势:不仅可以访问包含它们的外部类,还可以访问局部变量,但那些局部变量必须被声明为final
3.匿名内部类
●将局部内部类的使用再深人一步。 假如只创建这个类的一个对象,就不必命名了。这种类被称为匿名内部类(anonymous inner class)。
●由于构造器的名字必须与类名相同, 而匿名类没有类名, 所以, 匿名类不能有构造器。取而代之的是,将构造器参数传递给超类 ( superclass) 构造器。尤其是在内部类实现接口的时候, 不能有任何构造参数。如果构造参数的闭小括号后面跟一个开大括号, 正在定义的就是匿名内部类 。
注意:建立一个与超类大体类似(但不完全相同)的匿名子类通常会很方便。不过, 对于 equals 方法要特别当心。
●SuperType可以是接口,内部类就要实现这个接口;也可以是一个类,内部类就要扩展它。
4.静态内部类
.有时使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象。为此,可以将内部类声明为 static, 以便取消产生的引用。 只有内部类可以声明为 static。静态内部类的对象除了没有对生成它的外围类对象的引用特权外, 与其他所冇内部类完全一样。在我们列举的示例中, 必须使用静态内部类,这是由于内部类对象是在静态方法中构造的
注意:(1)在内部类不需要访问外围类对象的时候, 应该使用静态内部类。 有些程序员用嵌套类 (nested class ) 表示静态内部类
( 2)与常规内部类不同,静态内部类可以有静态域和方法。
(3)声明在接口中的内部类自动成为 static 和 public 类
第二部分:实验部分
实验1: 导入第6章示例程序,测试程序并进行代码注释。
测试程序1:
l 编辑、编译、调试运行阅读教材214页-215页程序6-1、6-2,理解程序并分析程序运行结果;
l 在程序中相关代码处添加新知识的注释。
l 掌握接口的实现用法;
l 掌握内置接口Compareable的用法。
代码如下:
1>Employee类
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 a lower salary than * otherObject, 0 if the salaries are the same, a positive value otherwise */ //重写接口的compare To方法 public int compareTo(Employee other) { return Double.compare(salary, other.salary); } }
2>EmployeeSortTest类
import java.util.*; /** * This program demonstrates the use of the Comparable interface. * @version 1.30 2004-02-27 * @author Cay Horstmann */ 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); //使用mergesort算法对数组staff中的元素进行排序。要求数组中的元素必须实现了Comparable接口中的类,并且元素之间是可比较的。 Arrays.sort(staff); //打印有关所有员工对象的信息 for (Employee e : staff) System.out.println("name=" + e.getName() + ",salary=" + e.getSalary()); } }
运行结果如下:
测试程序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); } } |
代码及注释如下:
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引用了实现了接口A的类对象 A a=new C( ); //使用接口变量调用实现了接口A的类对象的方法 a.show( ); System.out.println("g="+C.g); } }
运行结果如下:
测试程序3:
l 在elipse IDE中调试运行教材223页6-3,结合程序运行结果理解程序;
l 26行、36行代码参阅224页,详细内容涉及教材12章。
l 在程序中相关代码处添加新知识的注释。
l 掌握回调程序设计模式;
代码如下:
/**
@version 1.02 2017-12-14
@author Cay Horstmann
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import javax.swing.Timer;
public class TimerTest
{
public static void main(String[] args)
{
TimePrinter listener = new TimePrinter();
// 构造一个调用listener的计时器
// 每1秒一次
Timer timer = new Timer(1000, listener);
timer.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 time is "
+ new Date());
Toolkit.getDefaultToolkit().beep();
}
}
运行结果如下:
测试程序4:
l 调试运行教材229页-231页程序6-4、6-5,结合程序运行结果理解程序;
l 在程序中相关代码处添加新知识的注释。
l 掌握对象克隆实现技术;
l 掌握浅拷贝和深拷贝的差别。
代码如下:
1>Employee类
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 { //检查调用clone的对象的类有没有实现cloneable接口 //调用object.clone() Employee cloned = (Employee)super.clone(); // 克隆可变字段 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 + "]"; } }
2>CloneTest类
/** * 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(); copy.raiseSalary(10); copy.setHireDay(2002, 12, 31); System.out.println("original=" + original); System.out.println("copy=" + copy); } }
运行结果如下:
实验2: 导入第6章示例程序6-6,学习Lambda表达式用法。
l 调试运行教材233页-234页程序6-6,结合程序运行结果理解程序;
l 在程序中相关代码处添加新知识的注释。
l 将27-29行代码与教材223页程序对比,将27-29行代码与此程序对比,体会Lambda表达式的优点。
代码如
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 { public static void main(String[] args) { var planets = new String[] { "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune" }; //定义数组plants; System.out.println(Arrays.toString(planets)); System.out.println("Sorted in dictionary order:"); Arrays.sort(planets);//Arrays.sort方法接受Lambda类的对象; 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));//提供lanbda表达式在底层,Arrays.sort方法会接收实现Comparator<string>某各类的对象; var 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?"); //保持程序运行,直到用户选择“OK" System.exit(0); } }
运行结果如下:
注:以下实验课后完成
实验3: 编程练习
l 编制一个程序,将身份证号.txt 中的信息读入到内存中;
l 按姓名字典序输出人员信息;
l 查询最大年龄的人员信息;
l 查询最小年龄人员信息;
l 输入你的年龄,查询身份证号.txt中年龄与你最近人的姓名、身份证号、年龄、性别和出生地;
l 查询人员中是否有你的同乡。
代码如下:
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.Scanner; import java.util.Collections;//对集合进行排序、查找、修改等; public class Main { private static ArrayList<Citizen> citizenlist; public static void main(String[] args) { citizenlist = 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 id = linescanner.next(); String sex = linescanner.next(); String age = linescanner.next(); String birthplace = linescanner.nextLine(); Citizen citizen = new Citizen(); citizen.setName(name); citizen.setId(id); citizen.setSex(sex); // 将字符串转换成10进制数 int ag = Integer.parseInt(age); citizen.setage(ag); citizen.setBirthplace(birthplace); citizenlist.add(citizen); } } 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.查询人员中是否有你的同乡"); System.out.println("4.输入你的年龄,查询文件中年龄与你最近人的姓名、身份证号、年龄、性别和出生地"); System.out.println("5.退出"); int nextInt = scanner.nextInt(); switch (nextInt) { case 1: Collections.sort(citizenlist); System.out.println(citizenlist.toString()); break; case 2: int max = 0, min = 100; int m, k1 = 0, k2 = 0; for (int i = 1; i < citizenlist.size(); i++) { m = citizenlist.get(i).getage(); if (m > max) { max = m; k1 = i; } if (m < min) { min = m; k2 = i; } } System.out.println("年龄最大:" + citizenlist.get(k1)); System.out.println("年龄最小:" + citizenlist.get(k2)); break; case 3: System.out.println("出生地:"); String find = scanner.next(); String place = find.substring(0, 3); for (int i = 0; i < citizenlist.size(); i++) { if (citizenlist.get(i).getBirthplace().substring(1, 4).equals(place)) System.out.println("出生地" + citizenlist.get(i)); } break; case 4: System.out.println("年龄:"); int yourage = scanner.nextInt(); int near = peer(yourage); int j = yourage - citizenlist.get(near).getage(); System.out.println("" + citizenlist.get(near)); break; case 5: isTrue = false; System.out.println("程序已退出!"); break; default: System.out.println("输入有误"); } } } public static int peer(int age) { int flag = 0; int min = 53, j = 0; for (int i = 0; i < citizenlist.size(); i++) { j = citizenlist.get(i).getage() - age; if (j < 0) j = -j; if (j < min) { min = j; flag = i; } } return flag; } }
运行结果如下:
实验总结: 本周测试中的lamdba表达式我有些没有理解清楚,在听了助教的讲解后,使我自己加深了它的理解。本次实验有很多的测试程序,在写代码注释的时候我更加着重的理解了它们的代码层次。尤其是本章的程序编写题目,虽然刚开始不会做,在读入文件时对于他的位置有些不懂,但在和同学交流之后我正确理解了它的意义。在今后的编程练习题中,我会更加努力,坚持自己写代码,早日提高自己的编程水平。