项目 | 内容 |
这个作业属于哪个课程 | https://www.cnblogs.com/nwnu-daizh/ |
这个作业要求在哪里 |
https://www.cnblogs.com/nwnu-daizh/p/11605051.html |
作业的学习目标 |
|
第一部分:理论知识部分
第五章 继承(inheritance)
5.1 类、超类和子类
5.2 Object:所有类的超类
5.3 泛型数组列表
5.4 对象包装器和自动打包
5.5 参数变量可变的方法
5.6 枚举类
5.7 继承设计的技巧
5.1 类、超类和子类
继承的特点:具有层次结构;子类继承了父类的域和方法。
a)类继承的格式:
class 新类名 extends 已有类名
b)已有类称为:超类(superclass)、基类(base class) 或父类(parent class)
新类称作:子类(subclass)、派生类(derived class)或孩子类(child class)
c)一般来说,子类比超类拥有的功能更丰富。
d)super是一个指示编译器调用超类方法的特有关键字,它不是一个对象的引用,不能将super赋给另一个对象变量。
e) super关键字一般有两个用途:一是调用超类的方法(格式:super.方法名()),二是调用超类的构造器(格式:super() )。
f)从一个超类扩展而来的类集合称为继承层次(inheritance hierarchy)。在继承层次中,某个类到其祖先的路径被称为该类的继承链(inheritance chain)。
注意:Java不支持多继承
g)多态性:多态性泛指在程序中同一个符号在不同的情况下具有不同解释的现象。
java中,对象变量是多态的
h) 不允许继承的类称为final类,在类的定义中用final修饰符加以说明,String类是final类的一个例子。不能扩展该类。
I)抽象类:包含一个或多个抽象方法的类必须声明为抽象类
抽象方法充当着占位的角色,它们的具体实现在子类中。
抽象类不能被实例化,即不能创建对象,只能产生子类。
继承小结
1)封装、继承、多态是面向对象的主要特征。
2)继承可以提高代码重用性,用extends关键字来实现。除构造方法之外,父类的所有方法和属性都被子类继承。
3)继承建立了类与类间的关系,同时是多态特征的前提。
4)java只支持单继承,不直接支持多继承(避免两个父类出现同名方法的调用选择困难)
5)abstract修饰的抽象类不能实例化为对象,只能扩展子类;抽象类中的抽象方法充当着占位的角色,它们的具体实现在子类中。
6)final类不允许继承;类中final方法不允许被子类重写。
5.2 Object:所有类的超类
a)Object类是Java中所有类的祖先——每一个类都由它扩展而来。在不给出超类的情况下,Java会自动把Object 作为要定义类的超类。
b)可以使用类型为Object的变量指向任意类型的对象。但要对它们进行专门的操作都要进行类型转换。
c)Object类中的equals方法用于测试某个对象是否同另一个对象相等。它在Object类中的实现是判断两个对象是否具有相同的引用。如果两个对象具有相同的引用,它们一定是相等的。
d)定义子类的equals方法时,可调用超类的equals方法。
super.equals(otherObject)
e) Object类中的hashCode方法导出某个对象的散列码。散列码是任意整数,表示对象的存储地址。
两个相等对象的散列码相等。
f)Object类的toString方法返回一个代表该对象域值的字符串。定义子类的toString方法时,可先调用超类的toString方法。如:super.toString()
5.3 泛型数组列表
a) Java中,利用ArrayList类,可允许程序在运行时确定数组的大小。
b)ArryList是一个采用类型参数的泛型类。为指定数组列表保存元素的对象类型,需要用一对尖括号将数组元素的对象类名括起来加在后面。
ArryList<Employee> staff=new ArrayList<Employee>();
c)没有<>的ArrayList将被认为是一个删去了类型参数的“原始”类型。
d)a.ArrayList定义
>ArrayList <T> 对象 = new ArrayList<T>();
>API : ArrayList的构造器
ArrayList<T>()构造一个空数组列表
ArrayList<T>(int initialCapacity)构造一个具有指定容量的空数组列表
5.4 对象包装器和自动打包
a)所有基本数据类型都有着与之对应的预定义类,它们被称为对象包装器。
b)对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。且对象包装器类还是final,因此不能定义它们的子类。
c)使用对象包装器的好处:
- 基本类型转化为对象
- 定义了一些有用的基本方法(static方法)
d)在JavaSE5.0中,可以自动的将基本数据类型转换为包装器类的对象,将这种变换称为自动打包
e)相反的,当对一个包装器类的对象进行赋值或算法运算时,将会自动地拆包。
f)打包和拆包是编译器认可的。
5.5 参数变量可变的方法
a)在Java SE 5.0以前的版本中,每个Java方法都有固定数量的参数。然而,现在的版本提供了可以用可变的参数数量调用的方法(称为“可变参 ”方法)。
b 用户自己可以定义可变参数的方法,并将参数指定为任意类型,甚至是基本类型。
5.6 枚举类
a)声明枚举类
public enum Grade{A,B,C,D,E};
它包括一个关键字enum,一个新枚举类型的名字 Grade以及为Grade定义的一组值,这里的值既非整型,亦非字符型。
b)枚举类是一个类,它的隐含超类是java.lang.Enum。
c)枚举值并不是整数或其它类型,是被声明的枚举类的自身实例,例如A是Grade的一个实例
d)枚举类不能有public修饰的构造函数,构造函数都是隐含private,编译器自动处理。
e)枚举值隐含都是由public、static、final修饰的,无须自己添加这些修饰符。
f)在比较两个枚举类型的值时i,永远不需要调用equals方法,直接使用“==”进行相等比较。
5.7 继承设计的技巧
a) 将公共操作和域放在超类。
b)不要使用受保护的域。
c)使用继承实现“is-a”关系。
d)除非所有继承的方法都有意义,否则就不要使用继承。
e)在覆盖方法时,不要改变预期的行为。
f)使用多态,而非类型信息。
第二部分 :实验部分
1、实验目的与要求
(1) 理解继承的定义;
(2) 掌握子类的定义要求
(3) 掌握多态性的概念及用法;
(4) 掌握抽象类的定义及用途。
2、实验内容和步骤
实验1: 导入第5章示例程序,测试并进行代码注释。
测试程序1:
Ÿ 在elipse IDE中编辑、调试、运行程序5-1 —5-3(教材152页-153页) ;
Ÿ 掌握子类的定义及用法;
Ÿ 结合程序运行结果,理解并总结OO风格程序构造特点,理解Employee和Manager类的关系子类的用途,并在代码中添加注释;
Ÿ 删除程序中Manager类、ManagerTest类,背录删除类的程序代码,在代码录入中理解父类与子类的关系和使用特点。
代码如下:
ManagerTest.java
package texta;
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);
var staff = new Employee[3];
// fill the staff array with Manager and Employee objects
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
for (Employee e : staff)
System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
}
}
Manager.java
package texta;
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()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
public void setBonus(double b)
{
bonus = b;
}
}
Employee.java
package texta;
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()
{
return name;
}
public double getSalary()
{
return salary;
}
public LocalDate getHireDay()
{
return hireDay;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}
运行结果如下:
子类的定义及用法:一个父类可以有多个子类,但是一个子类只能有一个父类。子类可以通过extends关键字来继承父类。
OO风格程序构造特点:封装,继承,多态,抽象。
测试程序2:
Ÿ 编辑、编译、调试运行教材PersonTest程序(教材163页-165页);
Ÿ 掌握超类的定义及其使用要求;
Ÿ 掌握利用超类扩展子类的要求;
Ÿ 在程序中相关代码处添加新知识的注释;
Ÿ 删除程序中Person类、PersonTest类,背录删除类的程序代码,在代码录入中理解抽象类与子类的关系和使用特点。
代码如下:
Student.java
package PersonTest;
public class Student extends Person
//子类Student继承超类Person
{
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()
{
return "a student majoring in " + major;
}
}
PersonTest.java
package PersonTest;
/**
* 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];
// 抽象类的声明,但不能将抽象类实例化 ,实例化的是Person类的子类
// fill the people array with Student and Employee objects
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
for (Person p : people)
System.out.println(p.getName() + ", " + p.getDescription());
}
}
Person.java
package PersonTest;
public abstract class Person
{
//包含一个或多个抽象方法的类被称为抽象类,由abstract关键字修饰 //通用的作用域和方法也放到了这里,抽象类不能被实例化,但可以被声明
public abstract String getDescription();
private String name;
public Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
Employee.java
package PersonTest;
import java.time.*;
public class Employee extends Person
/子类Employee继承父类Person
{
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()
{
return salary;
}
public LocalDate getHireDay()
{
return hireDay;
}
public String getDescription()
{
return String.format("an employee with a salary of $%.2f", salary);
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}
运行结果如下:
抽象类与子类的关系及使用特点:
a)abstract方法只能声明,不能实现
b)包含一个或多个抽象方法的类本身必须被声明为抽象类
c)抽象方法充当着占位的角色,它们的具体实现在子类中
d)抽象类不能被实例化,即不能创建对象,只能产生子类。
测试程序3:
Ÿ 编辑、编译、调试运行教材程序5-8、5-9、5-10,结合程序运行结果理解程序(教材174页-177页);
Ÿ 掌握Object类的定义及用法;
Ÿ 在程序中相关代码处添加新知识的注释。
程序代码如下:
Employeea.java
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()
{
return name;
}
public double getSalary()
{
return salary;
}
public LocalDate getHireDay()
{
return hireDay;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
public boolean equals(Object otherObject)
{
// 快速检查对象是否相同 //这里获得一个对象参数,第一个if语句判断两个引用是否是同一个,如果是那么这两个对象肯定相等 if (this == otherObject) return true; // 如果显式参数为空,则必须返回false if (otherObject == null) return false; // getClass()方法是得到对象的类,如果两个对象的类不一样,那么就不相等 if (getClass() != otherObject.getClass()) return false; //现在我们知道另一个对象是非空雇员 //在以上判断完成,再将得到的参数对象强制转换为该对象,考虑到父类引用子类的对象的出现,然后再判断对象的属性是否相同 var other = (Employee) otherObject; //测试字段是否具有相同的值 return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
}
public int hashCode()
{
return Objects.hash(name, salary, hireDay);
}
public String toString()
{
return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay="
+ hireDay + "]";
}
}
EqualsTest.java
package equals;
/**
* This program demonstrates the equals method.
* @version 1.12 2012-01-26
* @author Cay Horstmann
*/
public class EqualsTest
{
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());
}
}
Manager.java
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()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
public void setBonus(double bonus)
{
this.bonus = bonus;
}
public boolean equals(Object otherObject)
{
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()
{
return java.util.Objects.hash(super.hashCode(), bonus);
}
public String toString()
{
return super.toString() + "[bonus=" + bonus + "]";
}
}
运行结果如下:
实验2:编程练习
Ÿ 定义抽象类Shape:
属性:不可变常量double PI,值为3.14;
方法:public double getPerimeter();public double getArea())。
Ÿ 让Rectangle与Circle继承自Shape类。
Ÿ 编写double sumAllArea方法输出形状数组中的面积和和double sumAllPerimeter方法输出形状数组中的周长和。
Ÿ main方法中
1)输入整型值n,然后建立n个不同的形状。如果输入rect,则再输入长和宽。如果输入cir,则再输入半径。
2) 然后输出所有的形状的周长之和,面积之和。并将所有的形状信息以样例的格式输出。
3) 最后输出每个形状的类型与父类型,使用类似shape.getClass()(获得类型),shape.getClass().getSuperclass()(获得父类型);
思考sumAllArea和sumAllPerimeter方法放在哪个类中更合适?
代码如下:
Main.java
package text1;
import java.util.Scanner;
public class Main {
@SuppressWarnings({ "resource" })
public static void main(String[] args) {
int n;
Scanner in = new Scanner(System.in);
String rect = "rect";
String cir = "cir";
n= in.nextInt();
double[] c = new double[n];
Shape[] shapes= new Shape[n];
for(int i=0;i<n;i++)
{
String in2 = in.next();
if(in2.equals(rect))
{
double length = in.nextDouble();
double width = in.nextDouble();
shapes[i] = new Rectangle(width,length);
c[i]=1;
}
if(in2.equals(cir))
{
double radius = in.nextDouble();
shapes[i] = new Circle(radius);
c[i]=2;
}
}
System.out.println(sumAllPerimeter(shapes));
System.out.println(sumAllArea(shapes));
System.out.printf("[");
for(int i=0;i<n;i++)
{
if(c[i]==1)
System.out.printf("Rectangle["+"length:"+Rectangle.length+" "+Rectangle.width+"]");
else
System.out.printf("Circle["+"radius:"+Circle.radius+"]");
if(n!=1&&i<n-1)
System.out.printf(",");
}
System.out.println("]");
for(Shape s:shapes)
{
System.out.println(s.getClass()+", "+s.getClass().getSuperclass());
}
}
private static double sumAllPerimeter(Shape shape2[]) {
double sum = 0;
for(int i = 0;i<shape2.length;i++)
sum+= shape2[i].getPerimeter();
return sum;
}
private static double sumAllArea(Shape shape1[]) {
double sum = 0;
for(int i = 0;i<shape1.length;i++)
sum+=shape1[i].getArea();
return sum;
}
}
Shape.java
package text1;
public abstract class Shape {
final double PI =3.14;
public abstract double getPerimeter();
public abstract double getArea();
public abstract double getName();
}
Rectangle.java
package text1;
public class Rectangle extends Shape {
static double width;
static double length;
public Rectangle(double w,double l)
{
width = w;
length = l;
}
public double getPerimeter()
{
double Perimeter = (width+length)*2;
return Perimeter;
}
public double getArea()
{
double Area = width*length;
return Area;
}
public String toString()
{
return getClass().getName() + "[ width=" + width + "]"+ "[length=" + length + "]";
}
public double getN()
{
double a=1;
return a;
}
@Override
public double getName() {
// TODO Auto-generated method stub
return 0;
}
}
Circle.java
package text1;
public class Circle extends Shape {
static double radius;
public Circle(double r)
{
radius = r;
}
public double getPerimeter()
{
double Perimeter = 2*PI*radius;
return Perimeter;
}
public double getArea()
{
double Area = PI*radius*radius;
return Area;
}
public String toString()
{
return getClass().getName() + "[radius=" + radius + "]";
}
@Override
public double getName() {
// TODO Auto-generated method stub
return 0;
}
}
运行结果如下:
第三部分:实验总结
本次学习理解了Java程序设计中类与对象的关系,理解OO程序设计的特征:继承和多态,并学会采用继承定义类设计程序,掌握利用了父类定义子类的语法规则及对象使用要求。在完成实验过程中理解了继承的定义,掌握子类的定义要求,多态性的概念及用法,抽象类的定义及用途。通过自己动手敲代码让我更加深刻的理解了本章的知识。但本章知识比较多也比较重要,仍需要多多加强巩固,继续努力。