• 201871010128杨丽霞《面向对象程序设计(java)》第八周学习总结


    201871010128-杨丽霞《面向对象程序设计(java)》第八周学习总结

     

    项目

    内容

    这个作业属于哪个课程

    https://www.cnblogs.com/nwnu-daizh/

    这个作业的要求在哪里

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

    作业学习目标

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

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

    6.1接口

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

    (1)接口声明:interface 接口名;    

    接口体:包括常量定义和方法定义,方法只允许声明不允许实现。

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

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

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

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

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

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

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

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

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

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

    6.2接口示例

    1)接口回调:把实现接口的类的对象的引用赋给该接口声明的接口变量中。那么该接口变量就可以调用该对象实现的接口方法。实际上,当接口变量调用接口实现的方法时,就是通知相应的对象调用接口方法。(整个过程和上转型类似)

    2)接口做参数:如果方法参数是接口类型,就可以将实现接口类的实例引用传给该接口参数,那么该接口参数就可以回调类实现的接口方法。如有一个接口M,类A实现了接口M,B类中有个方法Hello(M m),则接口做参数形式:  B  b=new B();b.Hello(new   A).

    3)java的比较器有两类,分别是Comparable接口和Comparator接口。

    继承Comparable接口,并实现compareTo()方法;
    定义一个单独的对象比较器,继承自Comparator接口,实现compare()方法。
    在为对象数组进行排序时,比较器的作用非常明显,首先来讲解Comparable接口。
    让需要进行排序的对象实现Comparable接口,重写其中的compareTo(T o)方法,在其中定义排序规则,那么就可以直接调用java.util.Arrays.sort()来排序对象数组

    4)JAVA实现克隆有两种形式

    • 浅克隆
    • 深克隆
    • 浅克隆与深克隆的区别
    JAVA将数据类型分为基本数据类型以及引用数据类型,我认为浅克隆与深克隆的区别主要在于对引用类型的成员属性的操作。深度克隆应该递归克隆引用类型的成员属性。
    浅克隆实现
    • 实现Cloneable接口
    • 重写clone方法,调用父类的clone方法

    6.3 lambda表达式

    lambda表达式的标准格式
    由三个部分组成:
    1.一些参数
    2.一个箭头
    3.一段代码
    格式:
    (参数列表) -> {一些重写方法的代码}
    说明:
    1.():接口中抽象方法的参数列表,没有参数就空着,有参数就写出,多个参数用逗号分隔。
    2.-> :指的是传参,把括号中的参数传到方法体中。
    3.{}:重写接口抽象方法的方法体。
    lambda表达式省略以及省略前提
    lambda表达式:凡是可以根据上下文推导出来的内容,全部可以省略不写。
    可以省略的内容:
    1.(参数列表):括号中参数列表的数据类型,可以省略不写。
    2.(参数列表):括号中的参数如果只有一个,那么类型和()都可以省略。
    3.(一些代码):如果方法体中只有一行,无论是否有返回值,都可以省略{},return和分号。注意:这三个要省略就要一起省略,否则不要省略,不能只省略其中一个或两个。
    lambda的使用前提
    1.使用lambda必须有接口,且该接口中有且仅有一个抽象方法,这样的接口被称为函数式接口。
    2.使用lambda必须具有上下文推断,也就是方法的参数或局部变量类型必须为lambda对应的接口类型,才能使用lambda作为该接口的实例。

    函数式接口
    对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式,这种接口称为函数式接口。
    为什么函数接口必须要有一个抽象方法呢?是因为接口完全有可能重新声明Object类的方法,这些声明有可能让方法不再是抽象的。
           在java 8中已经为我们定义了很多常用的函数式接口它们都放在java.util.function包下面,一般有以下常用的四大核心接口:

    6.4内部类

    类中除了可以有成员变量和方法之外,还可以有另一成员内部类。

    (1)在一个类内部声明另一个类,这个类叫做内部类;包含内部类的类叫做这个内部类的外嵌类 ;

    (2)内部类的外嵌类的成员变量在内部类中仍然有效,内部类中的方法可以调用外嵌类的方法;

    (3)内部类的类体中不可以声明类变量和类方法;

    (4)外嵌类的类体中可以用内部类声明对象;

    (5)如:A类里有内部类B类,b类中有方法speak(),在A类类体中 B b=new B(); 又创建A a=new A(),则调用speak()函数形式为:a.b.speak()

    6.5 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

    静态代理:

    public interface dao {
    
        public void save();
    
    }
    
    public class daoImpl implements dao {
    
        public void save() {
    
            System.out.println("save");
    
        }
    
    }
    
    public class daoImplProxy implement dao {
    
        public daoImpl target;
    
        public daoImplProxy(daoImpl target) {
    
            this.target = target;
    
        }
    
        public void save() {
    
            System.out.println("before save");
    
            target.save();
    
            System.out.println("after save");
    
        }
    
    }
    
    public class Main {
    
        public static void main(String[] args) {
    
            daoImpl dao = new daoImpl();
    
            daoImplProxy daoProxy = new daoImplProxy(dao);
    
            daoProxy.save();
    
        }
    
    }

    缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护

    jdk动态代理

    代理对象,不需要实现接口,代理对象的生成,是利用jdk的api动态的在内存中构建代理对象(需指定代理对象的接口类型)

    jdk动态代理的局限性:通过反射类Proxy和InvocationHandler回调接口实现的jdk动态代理,要求委托类必须实现一个接口,但事实上并不是所有类都有接口,对于没有实现接口的类,便无法使用该方方式实现动态代理。

     

    第二部分:实验部分

    1、实验目的与要求

    (1) 掌握接口定义方法;

    (2) 掌握实现接口类的定义要求;

    (3) 掌握实现了接口类的使用要求;

    (4) 掌握程序回调设计模式;

    (5) 掌握Comparator接口用法;

    (6) 掌握对象浅层拷贝与深层拷贝方法;

    (7) 掌握Lambda表达式语法;

    (8) 了解内部类的用途及语法要求。

    2、实验内容和步骤

    实验1: 导入第6章示例程序,测试程序并进行代码注释。

    测试程序1:

    l 编辑、编译、调试运行阅读教材214页-215页程序6-1、6-2,理解程序并分析程序运行结果;

    l 在程序中相关代码处添加新知识的注释。

    l 掌握接口的实现用法;

    l 掌握内置接口Compareable的用法。

    程序6-1:

    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
    {
       public static void main(String[] args)
       {
          Employee[] staff = new Employee[3];  
          // 新建一个Empioyee数组对象,给staff所引用,数组大小为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());
       }
    }

    运行结果如下:

     

     

     

     程序6-2:

    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;//用关键字this定义员工的名字与工资
       }
    
       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)
       {
          return Double.compare(salary, other.salary);
       }
    }

    运行结果如下:

     

     

     口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。

    Comparable接口的声明以及作用,可以看到它可以使继承他的类进行比较大小,只需要调用实现类的compareTo方法即可 

    测试程序2:

    l 编辑、编译、调试以下程序,结合程序运行结果理解程序;

     程序源代码:

    package interfaces;
    
    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=new C( );
           a.show( );
           System.out.println("g="+C.g);
      }
    }

     

    
    

     运行结果:

    测试程序3:

    l 在elipse IDE中调试运行教材223页6-3,结合程序运行结果理解程序;

    l 26行、36行代码参阅224页,详细内容涉及教材12章。

    l 在程序中相关代码处添加新知识的注释。

    l 掌握回调程序设计模式;

    程序6-3:

     

    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()方法,获得默认的工具箱
       }
    }

    运行结果:

     

     

     

    测试程序4:

    l 调试运行教材229页-231页程序6-4、6-5,结合程序运行结果理解程序;

    l 在程序中相关代码处添加新知识的注释。

    l 掌握对象克隆实现技术;

    l 掌握浅拷贝和深拷贝的差别。

    程序6-4:

    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);
          //clone方法 创建新对象copy,初始状态与Original相同,之后有不同的状态
          Employee copy = original.clone(); 
          copy.raiseSalary(10);
          copy.setHireDay(2002, 12, 31);
          System.out.println("original=" + original);
          System.out.println("copy=" + copy);
       }
    }

     

    程序6-5:

    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)
       {
          this.name = name;
          this.salary = salary;
          hireDay = new Date();
       }
    
       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 + "]";
       }
    }

    运行截图:

     

    总结: 浅拷贝和深拷贝的差别

    浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝 

    实验2: 导入第6章示例程序6-6,学习Lambda表达式用法。

    l 调试运行教材233页-234页程序6-6,结合程序运行结果理解程序;

    l 在程序中相关代码处添加新知识的注释。

    l 将27-29行代码与教材223页程序对比,将27-29行代码与此程序对比,体会Lambda表达式的优点。

    程序6-6:

    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" };
          //toString方法输出planets对象
          System.out.println(Arrays.toString(planets));
          System.out.println("Sorted in dictionary order:");
          //Arrays.sort方法按照字符顺序排序
          Arrays.sort(planets);
          System.out.println(Arrays.toString(planets));
          System.out.println("Sorted by length:");
          //Arrays.sort方法按照字符串长度排序
          Arrays.sort(planets, (first, second) -> first.length() - second.length());
          System.out.println(Arrays.toString(planets));
                 
          //lambda表达式: (argument)-> body
          var timer = new Timer(1000, event -> System.out.println("The time is " + new Date()));
          timer.start();   
              
          //直到选择OK程序将一直进行
          JOptionPane.showMessageDialog(null, "Quit program?");
          System.exit(0);         
       }
    }

    运行截图:

    Lambda表达式的优点:

    1. 简洁。

    2. 非常容易并行计算。

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

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

     实验3: 编程练习

    l 编制一个程序,将身份证号.txt 中的信息读入到内存中;

    | 按姓名字典序输出人员信息;

    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.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;         
          }
     
    } 
    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";
        }    
    }

    运行截图

     

     

     

    实验4:内部类语法验证实验

    实验程序1:

    l 编辑、调试运行教材246页-247页程序6-7,结合程序运行结果理解程序;

    l 了解内部类的基本用法。

    程序6-7:

    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 掌握匿名内部类的用法。

    程序6-8

    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,结合程序运行结果理解程序;

    | 了解静态内部类的用法。

    程序6-9:

    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类型的对象
       }
    }

    运行截图:

     

     实验总结:

    本周学习了接口,接口是没有静态代码块或者构造方法的。一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。

    如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。

    如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
    如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写
    一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法

    接口与接口间的关系,接口与类的关系,类与类间的关系

    1. 类与类之间是单继承的。直接父类只有一个。
    2. 类与接口之间是多实现的。一个类可以实现多个接口。
    3. 接口与接口之间是多继承的
  • 相关阅读:
    Educational Codeforces Round 66 (Rated for Div. 2)
    数学模板整理
    多项式全家桶
    [Scoi2016]背单词(trie+贪心)
    Codeforces Round #563 (Div. 2) 划水记
    应届生秋招可能会遇到的三个问题
    基于vue(element ui) + ssm + shiro 的权限框架
    ASP.NET 分页+组合查询 练习
    登录,注册页面练习
    HTML css 样式表
  • 原文地址:https://www.cnblogs.com/ylxzjh/p/11697255.html
Copyright © 2020-2023  润新知