201871010116-祁英红《面向对象程序设计(java)》第八周学习总结

项目

内容

《面向对象程序设计(java)》

https://home.cnblogs.com/u/nwnu-daizh/

这个作业的要求在哪里

https://www.cnblogs.com/nwnu-daizh/p/11703678.html

作业学习目标

  1. 掌握接口定义方法;
  2. 掌握实现接口类的定义要求;
  3. 掌握实现了接口类的使用要求;
  4. 理解程序回调设计模式;
  5. 掌握Comparator接口用法;
  6. 掌握对象浅层拷贝与深层拷贝方法;
  7. 掌握Lambda表达式语法;
  8. 了解内部类的用途及语法要求。

随笔博文正文内容包括:

第一部分:总结第六章理论知识(30分)

一、接口:

(1)接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。如果类遵从某个特定接口,那么就履行这项服务。

(2)Java不支持多继承性,即一个子类只能有一个父类;单继承使得java简单,易于管理,但如果要克服单继承性的缺点就要使用接口技术,是一个类可以实现多个接口,用关键字interface关键字来定义一个接口。

(3)接口声明:interface 接口名;    接口体:包括常量定义和方法定义,方法只允许声明不允许实现。

(4)接口使用:class A implements print,add       或者  class A extends A1 implements print,add

(5)接口中的所有方法自动地属于public,因此,在接口中声明方法时,不必提供关键字public。

(6)接口不能含有实例域,提供实例域和方法实现的任务应该由实现接口地那个类来完成,为了让类实现一个接口:1)将类声明为实现给定的接口。2)对接口中的所有方法进行定义。

(8)当某个类使用接口的时候,必须给出所有方法的实现,方法的类型、参数一定要和接口的一致;接口的方法默认为public abstract,故类在实现时一定不能漏写public关键字;接口常量默认关键字为public static。

(9)int compareTo(T other)

用这个对象与other进行比较,如果这个对象小于other则返回负值,如果相等则返回0,否则返回正值。

static void sort(Object[ ] a)

使用mergesort算法对数组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,否则返回一个负数。

(10)接口不是类,不能使用new运算符实例化一个接口,x=new Comparable(...); //ERROR

不能构造接口的对象,但能声明接口的变量,接口变量必须引用实现了接口的类对象,可以使用instance检查一个对象是否实现了某个特定的接口。

(11)因为接口中只含有public static final 常量和public abstract方法,故在写接口的时候可以省略这些关键字。

(12)如果接口的返回类型不是void,那么实现方法体的时候,至少要有一个return语句;如果接口的返回类型是void,可以除了大括号之外可以没有任何语句。

(13)Java提供的接口都在相应的包中,可以通过引入包使用相应的接口;也可以自定义接口,一个源文件就是由类和接口来组成的。

(14)类实现的接口的方法以及接口中的常量可以通过类的对象进行调用,常量也可以通过类名和接口名进行调用。

(15)接口声明的时候,如果加上关键字public,那么接口可以被任一个类进行调用,如果没有public则为友好型接口,只能被同一个包内的类进行调用。

(16)如果父类使用某个接口,那么子类也就使用了接口,不用再使用implements。

(17)接口可以通过extends继承接口。

(18)如果一个类声明实现一个接口但没有实现接口的所有方法,那么这个类一定得是abstract类。

(19)静态方法:从Java SE 8开始,允许在接口中增加静态方法,并给静态方法提供方法体实现,该静态方法只能通过接口名.静态方法来调用。实现语法只要在方法前面加static关键字即可,这理论上讲是可以的,但这有违于接口作为抽象规范的初衷。静态方法只能被具体实现类继承,不能在实现类中重写。

(20)默认方法:可以为接口方法提供一个默认方法体实现,在方法前加default修饰符即可,这样子类无需重写这个方法也能得到一个接口的默认实现。默认方法也可以被具体实现类重写。在实现类中调用默认方法要使用接口名.super.默认方法来调用。 

(21)解决默认方法的冲突:

如果先在一个接口中将一个方法定义为默认方法,然后又在超类或另一个接口中定义了同样的方法,会发生冲突。解决冲突规则如下:

  1. 超类和接口冲突。如果超类提供了一个具体方法,那么根据超类优先原则,同名而且有相同参数类型的默认方法会被忽略。
  2. 多接口之间冲突。如果一个实现类实现了多个接口,一个接口提供了一个默认方法,另一个接口提供了一个同名而且参数类型(不论是否是默认参数)相同的方法,此时就发生了接口冲突,必须在实现类中重写这个方法来解决冲突。

(22)解决重名常量的方法:

        1. 超类和接口冲突。如果一个类继承了一个超类和实现了若干接口,此时不像默认方法冲突一样有超类优先原则。只能通过在实现类中覆盖该常量来解决冲突。
        2. 多接口之间冲突。如果一个类实现了多个接口,而这些接口又有重名常量,此时会发生冲突。必须用接口名.常量的方式来精确指明要使用的常量。

(23)Comparator接口:Comparator接口意为"比较器"接口,是一个泛型接口,可用于自定义排序规则和大小比较等。要进行自定义排序,Arrays.sort方法有一个重载版本,需要提供一个数组和一个比较器作为参数。

(24)对象克隆:原变量和副本都会指向同一个对象,这说明,任何一个变量的改变都会影响到另一个变量。如果有一个对象original,希望创建一个对象copy使得其初始状态与original相同,但是之后它们各自回有自己不同的状态,这种情况下就可以使用克隆。clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

(25)接口和抽象类:

区别:
1.接口所有的变量必须是public static final;抽象类的变量无限制

2.接口没有构造方法,不能用new操作符实例化;抽象类有构造方法,由子类通过构造方法链调用,不能用new操作符实例化

3.接口所有方法必须是公共抽象实例方法(Java SE 8开始允许定义静态方法),抽象类无限制

4.一个类只可以继承一个父类,但可以实现多个接口

5.所有的类有一个共同的根Object类,接口没有共同的根

6.抽象类和子类的关系应该是强的“是一种”关系(strong is-a relationship),而接口和子类的关系是弱的"是一种"关系(weak is-a relationship)。接口比抽象类更灵活,因为实现接口的子类只需要具有统一的行为即可,不需要都属于同一个类型的类。

 二、lambda表达式:

(1)lambda表达式是一个可传递的代码块,可以在以后执行一次或多次

(2)lambda表达式的语法:

包含三个部分

  1. 一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数

  2. 一个箭头符号:->

  3. 方法体,可以是表达式和代码块,方法体函数式接口里面方法的实现,如果是代码块,则必须用{}来包裹起来,且需要一个return 返回值,但有个例外,若函数式接口里面方法返回值是void,则无需{ }

(3)函数式接口:对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式,这种接口称为函数式接口。

(4)方法引用:其实是lambda表达式的一个简化写法,所引用的方法其实是lambda表达式的方法体实现,语法也很简单,左边是容器(可以是类名,实例名),中间是"::",右边是相应的方法名。

一般方法的引用格式是

  1. 如果是静态方法,则是ClassName::methodName。如 Object ::equals

  2. 如果是实例方法,则是Instance::methodName。如Object obj=new Object();obj::equals;

  3. 构造函数.则是ClassName::new

 (5)构造器引用:构造器引用与方法引用类似,只不过方法名为new。例如Employee::new是Employee构造器的一个引用。至于是哪一个构造器取决于上下文,比如Function<Integer,Employee> func1 = Employee :: new;就相当于Function<Integer,Employee> func = x -> new Employee(x); 

数组类型也有构造器引用,如int[]::new等价于lambda表达式x -> new int[x]

(6)处理lambda表达式:

我们之前提到,lambda表达式的重点是延迟执行,之所以希望以后再执行代码,有很多原因,如:

1. 在一个单独的线程中运行代码

2. 多次运行代码

3. 在算法的恰当位置运行代码(例如,排序中的比较操作)

4. 发生某种情况时执行代码(如,点击了一个按钮、数据到达等)

5. 只在必要时才运行代码

下面是常用的函数式接口和基本类型的函数式接口:

 
 

(7)为什么需要lambda表达式:

主要有三个原因:

        1. 更加紧凑的代码

        2. 修改方法的能力

        3. 更好地支持多核处理

三、内部类:

(1)内部类,或者称为嵌套类,是一个定义在另一个类范围中的类。一个内部类可以如常规类一样使用。通常,在一个类只被它的外部类所使用的时候,才将它定义为内部类,内部类机制主要用于设计具有互相协作关系的类集合。

(2)使用内部类的好处:

  1.内部类可以很好地实现隐藏:一般的非内部类,是不允许有 private 与protected权限的,但内部类可以。
  2.成员内部类拥有外围类的所有元素的访问权限:内部类可以访问包含它的外部类的所有数据域(包括私有数据域)和方法,没有必要将外部类对象的引用传递给内部类的构造方法,内部类有一个指向外部类对象的隐式引用,如果显式写出,外部类的引用是OuterClass.this。

  3.可以间接实现多重继承:比如在A类中定义两个内部类innerClass1和innerClass2分别继承B类和C类,则A类就具有了B类和C类的属性和方法,间接实现了多重继承。

  4.减小了类文件编译后的产生的字节码文件的大小。

(3)内部类具有一下特征:

  1. 一个内部类被编译成一个名为OuterClassName$InnerClassName的类。例如,一个定义在Test类中的成员内部类A被编译成Test$A.class 。
  2. 内部类对象通常在外部类中创建,但是你也可以从另外一个类中来创建一个内部类的对象。如果是成员内部类,你必须先创建一个外部类的实例,然后使用下面的语法创建一个内部类对象:OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 如果是静态内部类的,使用下面语法来创建一个内部类对象:OuterClass.InnerClass innerObject = new OuterClass.InnerClass();

 (4)局部内部类:可以把内部类定义在一个方法中,称为局部内部类,也叫方法内部类。局部内部类就像是方法里面的一个局部变量一样,不能有public、protected、private以及static修饰符。它的作用域被限定在声明这个局部类的块中。局部类有一个优势,即对外部世界完全隐藏起来。即使外部类中的其他代码也不能访问它。除了其所在的方法之外,没有任何方法知道该局部类的存在。局部内部类只能访问被final修饰的局部变量。 

(5)匿名内部类:有时我们在程序中对一个类只使用一次,此时就可以把类的定义和实例化对象整合在一起,来简化对于抽象类和接口实现的操作,这就是匿名内部类。

(6)静态内部类:有时候,使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类的元素。为此,可以为内部类加上static关键字声明为静态内部类。

静态内部类不持有外部类的引用,只能访问外部类的静态成员变量和方法,而不能访问外部类的非静态成员属性和非静态方法,如果要调用和访问,必须实例化外部类对象。当静态内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的

是静态内部类的成员。如果要访问外部类的非静态同名成员,不能再使用外部类.this.成员的形式,而是要实例化外部类对象。如果要访问外部类的静态同名成员,可以通过外部类.成员的方式来访问。

与常规内部类不同,静态内部类可以有静态变量和静态方法。可以通过外部类.内部类.静态成员方式来访问。

 四、代理:

(1)利用代理可以在运行时创建一个实现了一组给定接口的新类。

(2)创建代理对象:

要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法,这个方法有三个参数:

  1. 一个类加载器(class loader)

  2. 一个class对象数组

  3. 一个调用处理器

(3)代理类的特性:

  1. 所有的代理类都扩展于Proxy类。

  2. 所有的代理类都覆盖了Object类中的方法toString、equals和hashCode。

  3. 没有顶定义代理类的名字,Sun虚拟机中的Proxy类将生成一个以字符串$Proxy开头的类名。

  4. 代理类一定是public和final。

第二部分:实验部分

实验1:测试程序1(5分)

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  //用EmployeeTest关联Employee
{
   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);

      Arrays.sort(staff); //进行排序

      // print out information about all Employee objects
      for (Employee e : staff)
         System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
   }
}

  

package interfaces;

public class Employee implements Comparable<Employee> //为泛型数组Comparable接口提供一个类型参数
{
   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
    */
   public int compareTo(Employee other) //用Employee对象与other进行比较
   {
      return Double.compare(salary, other.salary);  //使用静态Double.compare方法
   }
}

  程序运行结果如下:

接口中的所有方法自动地属于pubic,在接口中声明方法时,不必提供关键字public。

为了让类实现一个接口,需要:

(1)将类声明为实现给定的接口,使用关键字implements.

(2)对接口中的所有方法进行定义。

 comparable接口:类对象之间比较“大小”往往是很有用的操作,比如让对象数组排序时,就需要依赖比较操作。对于不同的类有不同的语义。如Student类,比较2个学生对象可以比较他们的score分数来评判。

Java不支持预算符重载,我们通过实现Comparable接口达到相同的目的。当类实现了Comparable接口,则认为这个类的对象之间是可比较的。

int compareTo(T other)

用这个对象与other进行比较,如果这个对象小于other则返回负值,如果相等则返回0,否则返回正值。

 

实验1:测试程序2(5分)

程序代码如下:

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:测试程序3(5分)

程序代码如下:

package timer;

/**
   @version 1.02 2017-12-14
   @author Cay Horstmann
*/

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;


public class TimerTest
{  
   public static void main(String[] args)
   {  
      ActionListener listener = new TimePrinter();  //构造ActionListener listener类的一个对象,并将它传递给Timer构造器

      // construct a timer that calls the listener
      // once every 10 seconds
      Timer t = new Timer(1000, listener);
      t.start();  //启动定时器

      // keep program running until the user selects "OK"
      JOptionPane.showMessageDialog(null, "Quit program?");
      System.exit(0);
   }
}
 
//定义一个实现ActionListener接口的类
class TimePrinter implements ActionListener  //定时器需要知道调用的方法,并要求传递的对象所属的类实现了java。awt.event包中的ActionListener接口
{  
   public void actionPerformed(ActionEvent event)  //当到达指定的时间间隔时,定时器就调用actionPerformed方法
   {  
      System.out.println("At the tone, the time is " 
         + new Date());
      Toolkit.getDefaultToolkit().beep();
   }
}

  程序运行结果如下:

回调设计模式:

核心总结:

1.接口作为方法参数,实际传入的是具体的实现类对象

2.A类让B类做一件事情,B做完后告诉A

实验1:测试程序4(5分)

程序代码如下:

 

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
   {
      var 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);
   }
}

  

package clone;

import java.util.Date;
import java.util.GregorianCalendar;

public class Employee implements Cloneable //将克隆定义为public,调用super.clone()
{
   private String name;
   private double salary;
   private Date hireDay;

   public Employee(String name, double salary)
   {
      this.name = name;
      this.salary = salary;
      hireDay = new Date();
   }
   //创建深拷贝的clone方法
   public Employee clone() throws 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. 对象克隆实现技术:克隆这个词大家并不陌生,实质就是拷贝对象,形成一个对象的副本。克隆对象就是对已有的一个对象进行拷贝。

进行克隆的目的(意义):被克隆和克隆对象之间完全复制、相互之间没有影响的目的。

为什么要使用克隆对象:当我们new一个对象之后是要对该对象进行初始化的,不然这个对象是空的没有内容。而使用克隆,则会得到一个原对象以及原对象里面包含的内容。例如,你有一个User对象,里面的包含了相关的属性。此时你想要修改里面的某一属性,但又不想破坏原对象里面的数据,此时就可以克隆User这个对象,然后在克隆的这个User对象上进行修改操作。除此,如果你在操作完之后判断一下属性是否更改成功,则使用克隆的对象和原对象做一下对比即可。

2.浅拷贝和深拷贝的差别:浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。例如:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2 中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。

若不对clone()方法进行改写,则调用此方法得到的对象即为浅拷贝。

实验2:(10分)

程序代码如下:

 

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" };
      System.out.println(Arrays.toString(planets));
      System.out.println("Sorted in dictionary order:");
      Arrays.sort(planets);    //调用Arrays类的sort方法
      System.out.println(Arrays.toString(planets));
      System.out.println("Sorted by length:");
      Arrays.sort(planets, (first, second) -> first.length() - second.length());  //lambda表达式
      System.out.println(Arrays.toString(planets));
            
      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?");   //窗口显示信息"Quit program?"
      System.exit(0);         
   }
}

  程序运行结果如下:

lambda表达式的优缺点:

优点:

1. 简洁。

2. 非常容易并行计算。

3. 可能代表未来的编程趋势。

4. 结合 hashmap 的 computeIfAbsent 方法,递归运算非常快。java有针对递归的专门优化。

缺点:

1. 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势,并行计算目前对 Collection 类型支持的好,对其他类型支持的一般)

2. 不容易调试。

3. 若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂。

4. 在 lambda 语句中强制类型转换貌似不方便,一定要搞清楚到底是 map 还是 mapToDouble 还是 mapToInt

实验3:编程练习(25分)

 程序代码如下:

package ID;
 
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://身份证号.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;
    }
}

  

package ID;
public class Citizen implements Comparable<Citizen> {
 
    private String name;
    private String id;
    private String sex;
    private int age;
    private String birthplace;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
    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 getBirthplace() {
        return birthplace;
    }
 
    public void setBirthplace(String birthplace) {
        this.birthplace = birthplace;
    }
 
    public int compareTo(Citizen other) {
        return this.name.compareTo(other.getName());
    }
 
    public String toString() {
        return name + "\t" + sex + "\t" + age + "\t" + id + "\t" + birthplace + "\n";
    }
}

  程序运行结果如下:

实验总结:(10分)

通过这周的实验学习,初步掌握了接口的一些简单知识:接口本身就是一个特殊的类;接口不能实例化(不能new,但是可是使用多态去进行实例化);接口的子类可以是抽象类,也可以是具体类(重写接口类里的所有方法);接口的成员变量(默认是常量):成员特点:只能是常量,并且是静态,因为默认情况下接口成员变量的修饰符是:public static final;构造方法:接口没有构造方法;成员方法:只能是抽象方法,其中默认修饰符是:public abstract  ; 注意:抽象方法中不能有主题;接口不能创建对象;接口没有构造方法;因为接口是提供给类使用,当非抽象类去实现一个接口时,必须把接口中所有方法都实现。还了解了lambda表达式的用法及优缺点,为什么要使用lambda表达式。

猜你喜欢

转载自www.cnblogs.com/qyhq/p/11697292.html