• 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表达式。

  • 相关阅读:
    查看DNS、IP、Mac等
    windows测试物理网络
    ACCEPT详解
    oracle动静视图-权限-角色-参数
    [ PHP+jQuery ] ajax 多级联动菜单的应用:电商网站的用户地址选择功能 ( 二 )
    使用Python爬取网页的相关内容(图片,文字,链接等等)
    使用Python爬取网页的相关内容(图片,文字,链接等等)
    使用Pycharm安装插件时发生错误
    使用Pycharm安装插件时发生错误
    使用Pycharm安装插件时发生错误
  • 原文地址:https://www.cnblogs.com/qyhq/p/11697292.html
Copyright © 2020-2023  润新知