201871010112-梁丽珍《面向对象程序设计(java)》第6、七周学习总结

项目html

内容java

这个做业属于哪一个课程算法

           <任课教师博客主页连接>    https://www.cnblogs.com/nwnu-daizh/                                   编程

这个做业的要求在哪里数组

<做业连接地址>https://www.cnblogs.com/nwnu-daizh/p/11605051.html缓存

做业学习目标安全

              深刻理解程序设计中算法与程序的关系;app

              深刻理解java程序设计中类与对象的关系;ide

              理解OO程序设计的第2个特征:继承、多态;函数

              学会采用继承定义类设计程序(重点、难点);

              可以分析与设计至少包含3个自定义类的程序;

              掌握利用父类定义子类的语法规则及对象使用要求。

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

  本章内容:

  类、超类和子类;

  Object:全部类的超类;

  泛型数组列表;

  对象包装器和自动装箱;

  参数数量可变的方法;

  枚举类;

  反射;

  继承设计的技巧;

1.继承:用已有类来构建新类的一种机制。当定义了一个新类继承了一个类时,这个新类就继承了这个类的方法和域,同时在新类中添   加新的方法和域以适应新状况。

2.继承的特色:具备层次结构 子类继承了父类的域和方法。

3.继承的优势:代码可重用性  父类的域和方法可用于子类  能够轻松定义子类  设计应用程序变得更加简单。

4.反射是指在程序运行期间发现更多的类及其属性的能力。 

(1)类、超类和子类

  1.“is-a”关系是继承的一个明显特征。

  2.在Java中,全部的继承都是公有继承,而没有C++中的私有继承和保护继承.。

  3.类继承的格式:

    Class 新类名 extends 已有类名

  4.已有类名称为: 超类(superclass)、基类(bass class)或父类(parent class)

       来自系统类库

      用户自定义类

  5.新类称做:子类(subclass)、派生类(derived class)或孩子类(child class

  6.通常来讲,子类比超类拥有的功能更加丰富

   7.经过扩展超类定义子类时,仅须要指出子类与超类的不一样之处。在子类中能够增长域、增长方法或覆盖超类的方法,但绝对不能删除超类的任何域和方法。

  8.关键字this有两个用途:一是引用隐式参数,而是调用该类其余的构造器。一样,super是一个指示编译器调用超类方法的特有关键字,它不是一个对象引用,不能将super赋给另外一个对象变量。Super关键字通常有两个用途:以是调用超类的方法

   (格式:super.方法名()),二是调用超类的构造器(格式:super())。

  9.若子类构造器没有显示地调用超类地构造器,则将自动地调用超类默认构造器。若是超类只定义了带参数地构造器,若子类构造器没有显示地调用超类地构造器,则Java编译器将报告错误。

  1)继承层次从一个超类扩展而来地类集合称为继承层次。在继承层次中,从某个类到其祖先地路径被称为该类地继承链。

    Java不支持多继承。

  2)多态性

    概念:多态性泛指在程序中同一个符号在不一样地状况下具备不一样解释地现象。

    超类中定义地域或方法,被子类继承以后,能够具备不一样地数据类型或表现出不一样的行为。

    这使得在超类及其各个子类中同名的域或方法具备不一样的语义。

    超类中的的方法在子类中可方法重写。

  12.在Java中,不须要将方法声明为虚拟方法。动态绑定是默认的处理方式。若是不但愿让一个方法具备虚拟特征,能够将它标记为final。

  3)抽象类

    观察类的继承层次结构,位于上层的类更具通用性,甚至可能更加抽象。从某种角度看,祖先类更加通用,人们只将它做为派生其余类的基类,而不做为特定的实例类。

    为了提升程序清晰度,包含一个或多个抽象方法的类自己必须被声明为抽象类。除了抽象方法以外,抽象类还能够包含具体数据和具体方法。

    抽象方法充当着占位的角色,它们的具体实如今子类中。扩展抽象类能够有两种选择:一种是在子类中实现部分抽象方法,这样就必须将子类也标记为抽象类;另外一种是实现所有抽象方法,这样子类就能够不是抽象类。此外,类即便不含抽象方法,也能够将类声明为抽象类。

    抽象类不能被实例化,即不能建立对象,只能产生子类。能够建立抽象类的对象变量,只是这个变量必须指向它的非抽象子类的对象。

  4)动态绑定

    概念:又称为运行时绑定。即程序在运行时会自动选择调用哪一个方法。

  调用对象方法的执行过程

    首先,编译器检查对象的声明类型和方法名,搜素相应类(Son)及其父类(father)的方法表,找出全部访问属性为publicmethod方法。

    接下来,编译器检查方法调用中提供的参数类型,找出一个彻底匹配的方法,这个过程称为重载解析。

    若是方法时privatestaticfinal修饰的,或者是构造器,那么编译器能准确地判断应该调用哪一个方法,这称为静态绑定 

    程序运行时,若是子类son中定义了method()方法,则直接调用子类中地相应方法:若是子类son中没有定义相应地方法,则到其父类中寻找method()方法。

    动态绑定中每次调用方法都要进行搜素,时间开销至关大。所以虚拟机预先为每一个类建立了一个方法表,其中列了全部方法地签名和实际调用地方法。

    方法地名称和参数列表称为方法地签名

          例如,f(int)和f(String)是两个具备相同名字,不一样签名的方法。若是在子类中定义了一个与超类签名相同的方法,那么子类中的这个方法就覆盖了超类中的这个相同签名的方法。不过,返回类型不是签名的一部分,所以,在覆盖方法时,必定要保证返回类型的兼容性。容许子类将覆盖方法的返回类型定义为原返回类型的子类型。

  5)阻止继承:final类和方法

    不容许继承地类称为final类,在类的定义中用final修饰符加以说明。

    Final class Executive extends Manager

    {   ........ }

     类中的方法可定义为final的。这时子类就不能覆盖该方法。

    若是一个类声明为final,属于它的方法会被自动设为final,但不包括域(若是域定义为final,在对象构造之后,final域就不能再修改了)。

    Private final int Max = 100

    String类是final类的一个例子,不能扩展该类。

  6)强制类型转换

    若是要把一个超类对象赋给一个子类对象变量,就必须进行强制类型转换。其格式为:

    子类  对象 = (子类) (超类对象)

    Manager boss = (Manager) staff[0];   //ok!

    类型转换必须在继承层次内进行;并且在超类转换为子类以前。应必须使用instanceof操做符进行继承链检查。

  7)继承小结

    封装、继承和多态是面对对象的主要特征。

    继承可提升代码重用性,用extends关键字来实现。除构造方法以外,父类的全部方法和属性都被子类继承。

    继承创建了类与类间的关系,同时也是多态特征的前提。

    Java只支持单继承,不直接支持多继承(避免两个父类出现同名方法的调用选择困难)

    Abstract修饰的抽象类不能被实例化为对象,只能扩展子类:抽象类中的抽象方法充当着占位的角色,它们的具体实如今子类中。 

    Final类不容许被继承;类中final方法不容许被子类重写。

  8)受保护访问

    若是但愿超类的某些方法或域容许被子类直接访问,就须要在超类定义时,将这些方法或域声明为protected

    Protected违背了OOP提倡的数据封装原则。实际中要谨慎使用protected的访问属性。

    若定义类时要限制类中某个方法的使用,就能够将它声明为protected。这代表子类获得信任,可使用这个方法,而其余类则不行。

    Java4个访问权限修饰符:

    访问修饰符:private  protected  public  默认

    使用访问修饰符的缘由:实现受限信息隐藏

    信息隐藏目的:

      对类中任何实现细节的更改不会影响使用该类的代码

      防止用户意外删除数据

      易于使用类

    访问修饰符:

      Public  该类或非该类都可访问

      Private  只有该类能够访问

      protected  该类及其子类的成员能够访问,同一个包中的类也能够访问

      默认  相同包中的类能够访问

位置

Private

默认

protected

Public

同一个类

同一个包内的类

不一样包内的子类

不一样包而且不是子类

            注:不写访问修饰符时默认为friendly

 (2)Object :全部类的超类

  1.Object 类是Java中全部类的祖先——每个类都由它扩展而来。在不给出超类的状况下,Java会自动把Object做为要定义类的超类。

  2.可使用类型为Object 的变量指向任意类型的对象。但要对它们进行专门的操做都要进行类型转换。

    Object obj = new Employee(“Harry Hacker”35000);

    Employee e = (Employee)obj;

  3.在Java中,只有基本类型(pimitive types)不是对象,例如,数组、字符和布尔类型的值都不是对象。全部的数组类型,无论是对象数组仍是基本类型的数组都扩展于Object类。

  1)equals方法

   Object类中的equals方法用于测试某个对象是否同另外一个对象相等。它在Object类中的实现是判断两个对象是否具备相同的引用。若是两个对象具备相同的引用,它们必定是相等的。

   若是须要检测两个对象状态的相等性,就须要在新类的定义中须要覆盖equals方法。

   定义子类的equals方法时,可调用超类的equals方法。

    Super.equalsotherObject

   getClass方法将返回一个对象所属的类。在检测中,只有两个对象属于同一个类时,才有可能相等。

  2)hashCode方法

    1.Object类中的hashCode方法导出某个对象的散列码。散列码时任意整数,表示对象的存储地址。

     2.两个相等对象的散列码相等。

     3.字符串的散列值是由内容导出的,s与t的散列值是同样的。字符串缓存sb与tb是不一样的。

    4.若是从新定义equals方法,就必须从新定义hashCode方法,以便用户能够将对象插入到散列表中。

    5.hashCode方法应该返回一个整型数值(也能够是负数),并合理地组合实例域的散列码,以便可以让各个不一样的对象产生的散列码更加均匀。

    6.须要组合多个散列值时,能够调用Objects.hash并提供多个参数。这个方法会对各个参数调用Objects.hashCode,并组合这些散列值。

     7.Equals与hashCode的定义必须一致:若是x.equals(y)返回true,那么x.hashCode()就必须与y.hashCode()具备相同的值。

     8.若是存在数组类型的域,那么可使用静态的Ayyas.hashCode方法计算一个散列码,这个散列码由数组元素的散列码组成。

     9.java.lang.Object 1.0

      int hashCode()
      返回对象的散列码。散列码能够是任意的整数,包括正数或负数。两个想等的对象要求返回相等的散列码。

     10.java.lang.Objects 7

      int hash(Object… objects)
      返回一个散列码,由提供的全部对象的散列码组合而获得。

      static int hashCode(Object a)
      若是a为null返回0,不然返回a.hashCode()。

    11.java.util.Arrays 1.2

      static int hashCode(type[] a) 5.0
      计算数组a的散列码。组成这个数组的元素类型能够是object,int,long,short,char,byte,boolean,float或double。

   3)toString方法

    1.Object类的toString方法返回一个表明该对象域值的字符串。

    2.定义子类中的toString方法时,可先调用超类的toString方法。

      super.toString( )

    3.toString方法是很是重要的调试工具。标准类库中,多数类定义了toString方法,以便用户得到对象状态的必要信息。

    4.java.lang.Object 1.0

      Class getClass()
      返回包含对象信息的类对象。

      boolean equals(Object otherObject)

      比较两个对象是否相等,若是两个对象指向同一块存储区域,方法返回true;不然方法返回false。在自定义的类中,应该覆盖这个方法。

      String toString()

      返回描述该对象的字符串。在自定义的类中,应该覆盖这个方法。

    5.java.lang.Class 1.0

      String getName()
      返回这个类的名字。

      Class getSuperclass()
      以Class对象的形式返回这个类的超类信息。

  4)泛型数组列表

    Java中,利用ArrayList类,可容许程序在运行时肯定数组的大小。

    ArrayList是一个采用类型参数的泛型类。为指定数组列表保存元素的对象类型,须要用一对尖括号将数组元素的对象类名括号起来加在后面。

    ArrayList<Employee> staff = new ArrayList<Employee>();

    没有< >ArrayList将被认为是一个删去了类型参数的“原始”类型。

      数组列表的操做

        ArrayList定义

        ArrayList <T>对象=new ArrayList<T>();

        例: ArrayList<Employee> staff = new ArrayList<Employee>(;

        API: ArrayList 的构造器

        ArrayList<T>()构造一 个 空数组列表

        - ArrayList<T>(int initialCapacity)构造 -一个具备指定容量的空数组列表

      b.添加新元素

        API: boolean add(T obj)

        把元素obj追加到数组列表的结尾

        例: staff.add(new Empleoy(..);

      c.统计个数

        API: int size()

        返回数组列表中当前元素个数

        例: staff.size();

      d.调整大小

        API: void trimToSize()

        把数组列表的存贮空间调整到当前大小

      e.访问

        API: void set(int index, T obj)

        将obj放入数组列表index位置,将覆盖这个位置的原有内容。

        API: T get(int index)

        得到指定位置index的元素值

        例: Employee harry = new Employee(..);

        staff.set(1, harry);

        Employeee = staff.get(1);

      f.增长与删除

        API: boolean add(int index, T obj)

        向后移动元素,在第n个位置插入obj

        API: T remove(int index);

        将第n个位置存放的对象删除,并将后面的元素前移动

        例:

        staff.add(i,harry);

        Employee e = staff.remove(i);

     5)对象包装器与自动装箱

      全部基本数据类型都有着与之对应的预约义类,它们被称为对象包装器(wrapper)

      如下前6个对象包装器类都是从公共包装器类Number继承而来。

        Integer

        Long

        F loat

        Double

        Short

        Byte

        Character

        Void :

        Boolean

      对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。且对象包装器类仍是final,此不能定义它们的子类。

      使用对象包装器的好处:

        基本类型转化为对象

        定义一些有用的基本方法(static方法)

      在JavaSE5.0中,能够自动的将基本数据类型转换为包装器类的对象,将这种变换称为自动打包(autohoxine)

        ArrayList<Integer> list = new ArrayList<Integer> () ;

        list. add(3);//翻译成

        li st. add(new Integer (3)) ;

      相反地,当对一个包装器类的对象进行赋值或算法运算时,将会自动地拆包。

        intn = list. get(i);

        翻译成

        int n = list. get (i). intValue;

        integer n =3;

        n++;

      打包和拆包是编译器承认的。

     6)参数数量可变的方法

      在Java SE 5. 0之前的版本中,每一个Java方法都有固定数量的参数。然而,如今的版本提供了可以用可变的参数数量调用的方法(称为“可变参”方法)

      用户本身能够定义可变参数的方法,并将参数指定为任意类型,甚至是基本类型。 

      public PrintStream printf(String fmt, Object... args)

      {

        return format(fmt, args); }

        System.out.print(%d %s”,n,widgets");

      实际的调用过程为:

        System.out.printf(%d %s",new Object[ ] {new Integer(n),widgets"});

      public static double max(double... values)

      {

        double largest = Double.MIN_ VALUE;

        for (double v: values) if (v > largest) largest = V;

        return largest;

      }

      double m = max(3.1, 40.4, -5);

      编译器将new double[] {3.1, 40.4, -5}传递给max方法。

     7)枚举类

      要定义一个成绩类,成绩的范围只能是ABCDE,接受其它类型的值都是违法的,应该如何定义呢?如何表示成绩呢?整型、字符型?都不合适,由于为没有明确的类型对应,即便是字符型,超出了ABCDE”范围的字符程序须要特别处,以便保证应用安全。

      JavaSE5.0之后版本中提供了一种称为枚举的类型定义方法。

      声明枚举类

        public enum Grade { A, B, C, D, E};

        它包括一~个关键字enum, -一个新枚举类型的名字

        Grade以及为Grade定义的一组值,这里的值既非整型,亦非字符型。

      枚举类说明

        枚举类是一个类,它的隐含超类是java. lang. Enum

        枚举值并非整数或其它类型,是被声明的枚举类的自身实例,例如AGrade-一个实例。

        枚举类不能有public修饰的构造函数,构造函数都是隐含pr ivate,编译器自动处理。

        枚举值隐含都是由publicstaticfinal修饰的,无须本身添加这些修饰符。

        在比较两个枚举类型的值时,永远不须要调用equals方法,直接使用=="进行相等比较。

      为枚举类增长构造函数

        1.enum Size

        2.

        3.SMALL("S"), MEDIUM("MI"), LARGE("L"),

        EXTRA_ LARGE("XL"); :

        4.

        5.private Size(String abbreviation)

        6.

        7.this. abbreviation = abbreviation;

        8.

        9.public String getAbbreviation(

        10. {

         return abbreviation; }

        1l.

        12.private String abbreviation;

        13. }

    8)反射

      1.反射库(reflection library)提供了一个很是丰富且精心设计的工具集,以便编写可以动态操纵Java代码的程序。特别是在设计或运行中添加新类时,可以快速地应用开发工具动态地查询新添加类的能力。

      2.可以分析类能力的程序称为反射(reflaction)。反射机制的功能及其强大,在下面能够看到,反射机制能够用来:

         在运行中分析类的能力。

         在运行中查看对象。

         实现通用的数组操做代码。

         利用Method对象,这个对象很像C++中的函数指针。

    9)Class类

      1.在程序运行期间,Java运行时系统始终为全部的对象维护一个被称为运行时的类型标识。这个信息跟踪着每一个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。然而,能够经过专门的Java类访问这些信息。保存这些信息的类被称为Class。Object类中的getClass()方法将会返回一个Class类型的实例。

      2.一个Class对象将表示一个特定类的属性。

      3.能够调用Class类的静态方法forName得到类名对应的Class对象。若是类名保存在字符串中,并可在运行中改变,就可使用这个方法。固然,这个方法只有在className是类名或接口名时才能执行。不然,forName方法将抛出一个checkedexception(已检查异常)。不管什么时候使用这个方法,都应该提供一个异常处理器(exception handler)。·

      4.一个Class对象实际上表示的是一个类型,而这个类型未必是一种类。

      5.虚拟机为每一个类型管理一个Class对象。所以,能够利用==运算符实现两个类对象比较的操做。

      6.Class类的方法newInstance(),能够用来快速地建立一个类的实例。newInstance方法调用默认的构造器(没有参数的构造器)初始化新建立的对象。若是这个类没有默认的构造器,就会抛出一个异常。

    10)捕获异常

      1.异常有两种类型:未检查异常和已检查异常。对于已检查异常,编译器将会检查是否提供了处理器。未检查异常编译器不会查看是否为这些错误提供了处理器。

      2.java.lang.Class 1.0

        static Class forName(String className)
        返回描述类名为className的Class对象。

        Object newInstance()
        返回这个类的一个新实例。

      3.java.lang.reflect.Constructor 1.1

        Object newInstance(Object[] args)
        构造一个这个构造器所属类的新实例。
        参数:args 这是提供给构造器的参数。

      4.java.lang.Throwable 1.0

        void printStackTrace()
        将Throwable对象和栈的轨迹输出到标准错误流。

    11)利用反射分析类的能力

      1.在java.lang.reflact包中有三个类Field、Method和Constructor分别用于描述类的域、方法和构造器、这三个类都有一各叫作getName的方法,用来返回项目的名称。Field类有一个getType方法,用来返回描述域所属类型的Class对象。Method和Constructor类有可以报告参数类型的方法,它将返回一个整型数值,用不一样的位开关描述public和static这样修饰符使用情况。另外,还能够利用java.lang.reflect包中的Modifier类的静态方法分析getModifiers返回的整型数值。还能够利用Modifier.toString方法将修饰符打印出来。

      2.Class类中的getFields、getMethods和getConstructors方法将分别返回类提供的public域、方法和构造器数组,其中包括超类的公有成员。Class类的getDelareFields、getDeclareMethods和getDeclaredConstructors方法将分别返回类中声明的所有域、方法和构造器,其中包括私有和受保护成员,但不包括超类的成员。

    12)在运行时使用反射分析对象

      1.查看对象域的关键方法是Field类中的get方法。

      2.除非拥有访问权限,不然Java安全机制只容许查看任意对象有哪些域,而不容许读取他们的值。

      3.反射机制的默认行为受限于Java的访问机制。然而,若是一个Java程序没有受到安全管理器的控制,就能够覆盖访问控制。

      4.setAccessible方法是AccessibleObject类中的一个方法,它是Field、Method和Constructor类的公共超类。这个特性是为调试、持久存储和类似机制提供的。

      5.调用Field的f.set(obj,value)能够将obj对象的f域设置成新值。

      6.使用Class的getDeclaredFields获取全部的数据域,而后使用setAccessible将全部的域设置为可访问的。对于每一个域,得到了名字和值。

    13)使用反射编写泛型数组代码

      1.java.lang.reflect包中的Array类容许动态地建立数组。

      2.能够经过调用Array.getLength(a)得到数组的长度,也能够经过Array类的静态getLength方法的返回值获得任意数组的长度。而要得到新数组元素类型,就须要进行如下工做:
        1)首先得到数组的类对象。
        2)确认它是一个数组。
        3)使用Class类(只能定义表示数组的类对象)的getComponentType方法肯定数组对应的类型。

    14)调用任意方法

      1.在Method类中有一个invoke方法,它容许调用包装在当前Method对象中的方法。invoke方法的签名是:Object invoke(Object obj,Object... args),第一个参数是隐式参数,其他的对象提供了显式参数。对于静态方法,第一个参数能够被忽略,便可以将它设置为null。

      2.如何获得Method对象呢?固然,能够经过调用getDeclareMethods方法,而后对返回的Method对象数组进行查找,直到发现想要的方法为止。也能够调用Class类中的getMethod方法获得想要的方法。它与getField方法相似。getField方法根据表示域名的字符串,返回一个Field对象。然而,有可能存在若干个相同名字的方法,所以要格外当心,以确保可以准确地获得想要的那个方法。有鉴于此,还必须提供想要的方法的参数类型。getMethod的签名是:Method getMethod(String name,Class... parameterTypes)

      3.若是在调用方法的时候提供了一个错误的参数,那么invoke方法将会抛出一个异常。

      4.nvoke的参数和返回值必须是Object类型的。这就意味着必须进行屡次的类型转换。这样作将会使编译器错过检查代码的机会。所以,等到测试阶段才会发现这些错误,找到并改正它们将会更加困难。不只如此,使用反射得到方法指针的代码要比仅仅直接调用方法明显慢一些。有鉴于此,建议仅在必要的时候才使用Method对象,而最好使用接口和内部类。特别要重申:建议Java开发者不要使用Method对象的回调功能。使用接口进行回调会使得代码的执行速度更快,更易于维护。

      5.java.lang.reflect.Method 1.1

        public Object invoke(Object implicitParameter,Object[] explicitParamenters)

        调用这个对象所描述的方法,传递给定参数,并返回方法的返回值。对于静态方法,把null做为隐式参数传递。在使用包装器传递基本类型的值时,基本类型的返回值必须是未包装的。

    15)继承设计的技巧

      ①将公共操做和域放在超类。

      ②不要使用受保护的域。

      ③使用继承实现“ is- -a”关系。

      ④除非全部继承的方法都有意义,不然就不要使用继承。

      ⑤在覆盖方法时,不要改变预期的行为。

      ⑥使用多态,而非类型信息。

第二部分:实验部分

一、实验目的与要求

(1) 理解继承的定义;

(2) 掌握子类的定义要求

(3) 掌握多态性的概念及用法;

(4) 掌握抽象类的定义及用途。

二、实验内容和步骤

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

测试程序1:

  在elipse IDE中编辑、调试、运行程序5-1 —5-3(教材152-153

  掌握子类的定义及用法;

  结合程序运行结果,理解并总结OO风格程序构造特色,理解EmployeeManager类的关系子类的用途,并在代码中添加注释;

  删除程序中Manager类、ManagerTest类,背录删除类的程序代码,在代码录入中理解父类与子类的关系和使用特色。

 

子类的定义及用法:一个父类能够有多个子类,可是一个子类只能有一个父类。子类能够经过extends关键字来继承父类。

OO风格程序构造特色:封装,继承,多态,抽象

 

5-1程序代码:

package inheritance;		//package继承

/**
 * This program demonstrates inheritance.
 * @version 1.21 2004-02-21
 * @author Cay Horstmann
 */
public class ManagerTest
{
   public static void main(String[] args)
   {
      // construct a Manager object			(构造一个管理对象)
      var boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);
      boss.setBonus(5000);				//使用setBonus方法

      var staff = new Employee[3];		//定义一个包含3个雇员的数组

      // fill the staff array with Manager and Employee objects    (用 Manager 和Employee对象填充staff数组)

      staff[0] = boss;
      staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
      staff[2] = new Employee("Tommy Tester", 40000, 1990, 3, 15);

      // print out information about all Employee objects   (打印出全部Employee对象的信息,输出每一个人的薪水)
      for (Employee e : staff)
         System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
   }
}

5-2程序代码:

package inheritance;	//包继承

import java.time.*;

public class Employee
{
   private String name;
   private double salary;
   private LocalDate hireDay;

   public Employee(String name, double salary, int year, int month, int day)
   {
      this.name = name;
      this.salary = salary;
      hireDay = LocalDate.of(year, month, day);
   }

   public String getName()		//getName方法
   {
      return name;
   }

   public double getSalary()	//getSalary方法
   {
      return salary;
   }

   public LocalDate getHireDay()	//getHireDay方法
   {
      return hireDay;
   }

   public void raiseSalary(double byPercent)
   {
      double raise = salary * byPercent / 100;
      salary += raise;
   }
}

5-3程序代码:

package inheritance;		//包继承

public class Manager extends Employee
{
   private double bonus;

   /**
    * @param name the employee's name
    * @param salary the salary
    * @param year the hire year
    * @param month the hire month
    * @param day the hire day
    */
   public Manager(String name, double salary, int year, int month, int day)		//提供一个子类构造器
   {
      super(name, salary, year, month, day);		//调用超类Employee中含有n,s,year,month和day参数的构造器
      bonus = 0;
   }

   public double getSalary()		// Manager类中的 getSalary方法
   {
      double baseSalary = super.getSalary();	//使用关键字super调用Employee类中的 getSalary方法
      return baseSalary + bonus;
   }

   public void setBonus(double b)
   {
      bonus = b;
   }
}

程序运行结果以下:

删除程序中Manager类、ManagerTest类 的结果及修改:

 

测试程序2:

   编辑、编译、调试运行教材PersonTest程序(教材163-165)

   掌握超类的定义及其使用要求;

   掌握利用超类扩展子类的要求;

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

   删除程序中Person类、PersonTest类,背录删除类的程序代码,在代码录入中理解抽象类与子类的关系和使用特色。

5-4代码:

package abstractClasses;

/**
 * This program demonstrates abstract classes.
 * @version 1.01 2004-02-21
 * @author Cay Horstmann
 */
public class PersonTest
{
   public static void main(String[] args)
   {
      var people = new Person[2];

      // fill the people array with Student and Employee objects
      //用Student和Employee对象填充people数组
      people[0] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
      people[1] = new Student("Maria Morris", "computer science");

      // print out names and descriptions of all Person objects
      //打印出全部Person对象的名称和描述
      for (Person p : people)
         System.out.println(p.getName() + ", " + p.getDescription());
   }
}

5-5代码:

package abstractClasses;

public abstract class Person		//定义了抽象超类Person
{
   public abstract String getDescription();		//使用abstract关键字
   private String name;

   public Person(String name)			//Person类中保存着姓名和一个返回姓名的具体方法
   {
      this.name = name;
   }

   public String getName()
   {
      return name;
   }
}

5-6代码:

package abstractClasses;

import java.time.*;

public class Employee extends Person		//定义了子类Employee
{
   private double salary;
   private LocalDate hireDay;

   public Employee(String name, double salary, int year, int month, int day)	//提供一个子类构造器
   {
      super(name);
      this.salary = salary;
      hireDay = LocalDate.of(year, month, day);
   }

   public double getSalary()			//getSalary方法
   {
      return salary;
   }

   public LocalDate getHireDay()		// getHireDay方法
   {
      return hireDay;
   }

   public String getDescription()			//getDescription方法
   {
      return String.format("an employee with a salary of $%.2f", salary);
   }

   public void raiseSalary(double byPercent)	//raiseSalary方法
   {
      double raise = salary * byPercent / 100;
      salary += raise;
   }
}

5-7代码:

package abstractClasses;

public class Student extends Person		//定义了子类Student
{
   private String major;

   /**
    * @param name the student's name
    * @param major the student's major
    */
   public Student(String name, String major)
   {
      // pass name to superclass constructor	(将名称传递给超类构造函数)
      super(name);
      this.major = major;
   }

   public String getDescription()		//getDescription方法
   {
      return "a student majoring in " + major;
   }
}

代码运行结果以下:

删除程序中Person类、PersonTest 的结果以及修改:

测试程序3:

  编辑、编译、调试运行教材程序5-85-95-10,结合程序运行结果理解程序(教材174-177页);

  掌握Object类的定义及用法;

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

5-8程序代码:

package equals;

/**
 * This program demonstrates the equals method.
 * @version 1.12 2012-01-26
 * @author Cay Horstmann
 */
public class EqualsTest			//此程序实现了Employee类和Manager类的equals,hashCode,toString方法
{
   public static void main(String[] args)
   {
      var alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15);
      var alice2 = alice1;
      var alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15);
      var bob = new Employee("Bob Brandson", 50000, 1989, 10, 1);

      System.out.println("alice1 == alice2: " + (alice1 == alice2));

      System.out.println("alice1 == alice3: " + (alice1 == alice3));

      System.out.println("alice1.equals(alice3): " + alice1.equals(alice3));

      System.out.println("alice1.equals(bob): " + alice1.equals(bob));

      System.out.println("bob.toString(): " + bob);

      var carl = new Manager("Carl Cracker", 80000, 1987, 12, 15);
      var boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);
      boss.setBonus(5000);
      System.out.println("boss.toString(): " + boss);
      System.out.println("carl.equals(boss): " + carl.equals(boss));
      System.out.println("alice1.hashCode(): " + alice1.hashCode());
      System.out.println("alice3.hashCode(): " + alice3.hashCode());
      System.out.println("bob.hashCode(): " + bob.hashCode());
      System.out.println("carl.hashCode(): " + carl.hashCode());
   }
}

5-9程序代码:

package equals;

import java.time.*;
import java.util.Objects;

public class Employee		
{
   private String name;
   private double salary;
   private LocalDate hireDay;

   public Employee(String name, double salary, int year, int month, int day)	
   {
      this.name = name;
      this.salary = salary;
      hireDay = LocalDate.of(year, month, day);
   }

   public String getName()		// getName方法
   {
      return name;
   }

   public double getSalary()	//getSalary方法
   {
      return salary;
   }

   public LocalDate getHireDay()	//getHireDay方法
   {
      return hireDay;
   }

   public void raiseSalary(double byPercent)	//raiseSalary方法
   {
      double raise = salary * byPercent / 100;
      salary += raise;
   }

   public boolean equals(Object otherObject)
   {
      // a quick test to see if the objects are identical	
      if (this == otherObject) return true;					//检测this与otherObject是否引用同一个对象

      // must return false if the explicit parameter is null	
      if (otherObject == null) return false;				//检测otherObject是否为null,若是为null,返回false

      // if the classes don't match, they can't be equal		
      if (getClass() != otherObject.getClass()) return false;	//比较this与otherObject是否属于同一个类

      // now we know otherObject is a non-null Employee		
      var other = (Employee) otherObject;					//强制类型转换

      // test whether the fields have identical values		(测试字段是否具备相同的值)
      return Objects.equals(name, other.name) 
         && salary == other.salary && Objects.equals(hireDay, other.hireDay);
   }

   public int hashCode()			//hashCode方法
   {
      return Objects.hash(name, salary, hireDay); 
   }

   public String toString()			//toString方法
   {
      return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" 
         + hireDay + "]";
   }
}

5-10程序代码:

package equals;

public class Manager extends Employee	
{
   private double bonus;

   public Manager(String name, double salary, int year, int month, int day)		//提供一个子类构造器
   {
      super(name, salary, year, month, day);
      bonus = 0;
   }

   public double getSalary()		//getSalary方法
   {
      double baseSalary = super.getSalary();
      return baseSalary + bonus;
   }

   public void setBonus(double bonus)	//使用setBonus方法
   {
      this.bonus = bonus;
   }

   public boolean equals(Object otherObject)		//equals方法
   {
      if (!super.equals(otherObject)) return false;
      var other = (Manager) otherObject;			//强制类型转换
      // super.equals checked that this and other belong to the same class (检查这个和其余都同属于一个类)
      return bonus == other.bonus;
   }

   public int hashCode()		//hashCode方法
   {
      return java.util.Objects.hash(super.hashCode(), bonus);
   }

   public String toString()		//Manager类中的toString方法
   {
      return super.toString() + "[bonus=" + bonus + "]";
   }
}

代码运行结果以下:

实验2:编程练习

  定义抽象类Shape

  属性不可变常量double PI,值为3.14

  方法public double getPerimeter()public double getArea())

  RectangleCircle继承自Shape类。

  编写double sumAllArea方法输出形状数组中的面积和和double sumAllPerimeter方法输出形状数组中的周长和。

   main方法中

1输入整型值n,而后创建n个不一样的形状。若是输入rect,则再输入长和宽。若是输入cir,则再输入半径。
2 而后输出全部的形状的周长之和,面积之和。并将全部的形状信息以样例的格式输出。
3 最后输出每一个形状的类型与父类型使用相似shape.getClass()(得到类型)shape.getClass().getSuperclass()(得到父类型);

思考sumAllAreasumAllPerimeter方法放在哪一个类中更合适?

输入样例:

输出样例:

 程序代码:

shape.java

package shape;

public abstract class shape {
		double PI = 3.14;
		public abstract double getPerimeter();
		public abstract double getArea();
}

Rectangle.java

package shape;

public class Rectangle extends shape {
	private double width;
	private double length;
	public Rectangle(double w, double l)
	{
		this.width = w;
		this.length = l;
	}

	@Override
	public double getPerimeter() {
		// TODO Auto-generated method stub
		double Perimeter = (width+length)*2;
		return Perimeter;
	}

	@Override
	public double getArea() {
		// TODO Auto-generated method stub
		double Area = width*length;
		return Area;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return getClass().getName() + "[ width=" + width + "]" + "[length=" + length + "]";
	}

}

Circle.java

package shape;

public class Circle extends shape {

	private double radius;
	public Circle(double r)
	{
		radius = r;
	}

	@Override
	public double getPerimeter() {
		// TODO Auto-generated method stub
		double Perimeter = 2*PI*radius;
		return Perimeter;
	}

	@Override
	public double getArea() {
		// TODO Auto-generated method stub
		double Area = PI*radius*radius;
		return Area;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return getClass().getName() + "[radius=" + radius + "]";
	}
	
}

shapeTest.java

package shape;

import java.util.Scanner;

public class shapeTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		String rect = "rect";
		String cir = "cir";
		System.out.println("请输入形状个数:");
		int n = in.nextInt();
		shape[] score = new shape[n];
		for(int i = 0; i < n; i++)
			{
				System.out.println("(rect or cir):");
				String input = in.next();
			if(input.equals(rect))
				{
					double length = in.nextDouble();
					double width = in.nextDouble();
					System.out.println("Rectangle["+"length:"+length+"width:"+width+"]");
					score[i] = new Rectangle(width,length);
				}
			if(input.equals(cir))
				{
					double radius = in.nextDouble();
					System.out.println("Circle["+"radius:"+radius+"]");
					score[i] = new Circle(radius);
				}
			}
		shapeTest c = new shapeTest();
		System.out.println(c.sumAllPerimeter(score));
		System.out.println(c.sumAllArea(score));
		for(shape s:score)
			{
				System.out.println(s.getClass()+","+s.getClass().getSuperclass());
			}
		in.close();
	}

	private double sumAllArea(shape[] score) {
		// TODO Auto-generated method stub
		double sum = 0;
		for(int i = 0; i < score.length; i++)
			sum+= score[i].getArea();
		return sum;
	}

	private double sumAllPerimeter(shape[] score) {
		// TODO Auto-generated method stub
		double sum = 0;
		for(int i = 0; i < score.length; i++)
			sum+= score[i].getPerimeter();
		return sum;
	}
}

运行结果:

3. 实验总结

  本次学习理解了Java程序设计中类与对象的关系,理解OO程序设计的特征:继承和多态,并学会采用继承定义类设计程序,掌握利用了父类定义子类的语法规则及对象使用要求。在完成实验过程当中理解了继承的定义,掌握子类的定义要求,多态性的概念及用法,抽象类的定义及用途。本章知识比较多也比较重要,仍须要多多增强巩固,继续努力。

相关文章
相关标签/搜索