第3章 类的重用
第3章 类的重用
3.1 类继承的概念和语法、隐藏和覆盖
- Java只支持类的单继承,每个子类只能有一个直接超类;
超类是所有子类的公共属性及方法的几何,子类是超类的特殊化;
子类对象从外部来看:与超类相同的接口,可以有更多方法和数据成员;
子类内包含着超类的所有变量和方法; - 子类不能直接访问从超类中继承的私有属性及方法,可使用公有(及保护)方法进行访问;
- 属性的隐藏:
子类中声明了与超类相同的成员变量名;
子类拥有了两个相同名字的变量;
子类执行继承自超类的操作时,处理超类变量;
子类执行自己声明的方法时,处理自己的变量;
super.属性名:直接访问超类属性;
静态成员:仍只有一个; - 方法的覆盖:
子类不需从超类继承来的方法和功能,可以声明同名方法;
覆盖方法的返回类型、方法名称、参数个数和类型必须一致,访问权限不能更严格;
抽象方法必须覆盖,否则子类也成为了抽象类;
不能覆盖final方法、静态方法;
super.方法名:直接调用被覆盖的方法;
3.2 Object类
- Object类:所有类的直接或间接超类,类层次最高点;包含了所有Java类公共属性;
- Object类主要方法:getClass()、toString()、equals(Object obj)、clone()、hashCode()、finaliza();
- equals方法:
相等:两个对象类型相同、属性值相同;
同一:两个引用变量指向同一个对象;
同一肯定相等,相等不一定同一;
== 、equals判断的是两个引用是否同一; - hashCode方法:返回对象散列码;
在一个Java程序的一次执行过程中,如果对象“相等比较”所使用的信息没有被修改,同一对象执行hashCode方法每次都返回同一个整数,不同执行中返回值不必一致;
如果依靠equals方法两个对象是相等的,则应返回同样的整数结果;
如果依靠equals方法两个对象不相等,不要求返回值不同; - clone方法:复制对象;
clone在Object中被定义为protected,覆盖为public;
实现Cloneable接口,赋予一个对象被克隆的能力(cloneability); - finalize方法:对象被垃圾回收器回收前系统自动调用;
覆盖finalize方法的最后必须调用super.finalize; - getClass方法:final方法,返回一个Class对象;
通过Class对象,可以查询类的各种信息:名字、超类、实现接口的名字等; - notify、notifyAll、wait方法:final方法,主要用在多线程程序中;
3.3 终结类与终结方法、抽象类
- 终结类与终结方法:final修饰的类和方法;
终结类不能被继承;
终结方法不能被子类覆盖; - 抽象类前加abstract,可包含常规类任何成员,包括非抽象方法和抽象方法;
抽象方法:用abstract修饰,只有方法原型,没有方法实现;
抽象类没有具体实例,只能用作超类;
子类实现所有抽象方法后,才不是抽象类能产生实例,有抽象方法时仍为抽象类;
3.4 泛型、类的组合
- 泛型Type:类型可定制(类、方法、接口);
通配符?
有限制的泛型:在参数Type后面使用extends关键字并加上类名或接口名,表示参数所代表的类型必须是该类的子类或者实现了该接口(此处接口用extends而非implements); - 组合的语法:将已存在类的对象放到新类中;
继承——从属;
组合——包含;
编程练习题
1. 教师学生评分
题目
学校要进行年终总结,需要对教师和学生的评分结果进行统计。学生的统计数据有三个,教师的统计数据有四个。请你实现一个统计系统,对输入的数据进行整理。
请你实现一个Person类表示人员,并实现一些必要的方法,再实现Teacher类和Student类,通过类的继承机制完成这个任务。
输入格式:
首先输入一个数字N,表示输入统计的人数。
接下来是N行,每行是用空格隔开的一系列数字。
输出格式:
N行,每行是一个标识符加一个平均得分(向下取整的整数),用空格隔开。
学生的标识符是Student,教师的标识符是Teacher。
输入样例:
2
2 3 4
2 3 4 5
输出样例:
Student 3
Teacher 3
思路
类的设计按题目要求即可。
使用方法:str.split(“ ”) 切分字符串,Interger.valueOf(str) 将字符串转换为整形。
代码
import java.util.Scanner;
class Person {
private int[] score;
private int len;
Person(int score[], int len) {
this.len = len;
this.score = new int[len];
for (int i = 0; i < len; i++) {
this.score[i] = score[i];
}
}
protected int Ave() {
int sum = 0;
for (int i = 0; i < len; i++)
sum += score[i];
return sum/len;
}
}
class Student extends Person {
Student(int[] score) {
super(score, 3);
}
}
class Teacher extends Person {
Teacher(int[] score) {
super(score, 4);
}
}
public class homework3_1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int ans[] = new int[n];
String per[] = new String[n];
in.nextLine();
for (int i = 0; i < n; i++) {
String input = in.nextLine();
String[] inum = input.split(" ");
int len = inum.length;
int[] num = new int[len];
for (int j = 0; j < len; j++)
num[j] = Integer.valueOf(inum[j]);
if (len == 3) {
Student stu = new Student(num);
ans[i] = stu.Ave();
per[i] = "Student";
}
else {
Teacher tea = new Teacher(num);
ans[i] = tea.Ave();
per[i] = "Teacher";
}
}
in.close();
for (int i = 0; i < n; i++)
System.out.println(per[i] + " " + ans[i]);
}
}
2. 图形面积计算
题目
我们有一些图形的边长数据,这些图形包括三角形和矩形,请你编写一个程序求出它们的面积。
请你实现一个基础图形类Graph,然后实现三角形类Triangle和矩形类Rectangle,继承自Graph。根据输入的边数实现不同的对象,并计算面积。
输入格式:
一行,一个整数n,表示图形个数。
n行,每行是用空格隔开的整数。
输出格式:
n行,每行是一个图形的面积。
输入样例:
2
5 5
6 6 6
输出样例:
25
15
思路
与上题类似,参考编程题 2-3 的三角形面积公式。
代码
import java.util.Scanner;
abstract class Graph {
protected int[] side;
protected int num;
Graph(int side[], int num) {
this.num = num;
this.side = new int[num];
for (int i = 0; i < num; i++)
this.side[i] = side[i];
}
abstract int getArea();
}
class Rectangl extends Graph {
Rectangl(int[] side) {
super(side, 2);
}
int getArea() {
return side[0] * side[1];
}
}
class Triangle extends Graph {
public Triangle(int[] side) {
super(side, 3);
}
int getArea() {
double p = (double)(side[0] + side[1] + side[2]) / 2;
return (int)Math.sqrt(p * (p - side[0]) * (p - side[1]) * (p - side[2]));
}
}
public class homework3_2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int ans[] = new int[n];
in.nextLine();
for (int i = 0; i < n; i++) {
String input = in.nextLine();
String[] iside = input.split(" ");
int num = iside.length;
int[] side = new int[num];
for (int j = 0; j < num; j++)
side[j] = Integer.valueOf(iside[j]);
if (num == 2) {
Rectangl rec = new Rectangl(side);
ans[i] = rec.getArea();
}
else {
Triangle tri = new Triangle(side);
ans[i] = tri.getArea();
}
}
in.close();
for (int i = 0; i < n; i++)
System.out.println(ans[i]);
}
}
3.多类型排序
题目
我们现在有一些数据,是整数和字符串混杂的。现在需要你将他们分开,并且分别进行排序。
请你利用泛型实现一个数组类,并且实现排序函数,使得其既可以对Integer类型进行排序,又可以对String类型进行排序。然后利用你实现的这个类完成上面的任务。
输入格式:
一行,一个数字n,表示元素的个数。
n行,每行一个字符串整数,也可以是其他字符串。
输出格式:
n行,前面一部分为输入的整数字符串按从小到大排序输出,后面一部分为非整数字符串按照字典序从小到大输出。
输入样例:
5
12
ab
bd
23
t
输出样例:
12
23
ab
bd
t
思路
- 设计类时,通过实现Comparable接口,支持排序(无复杂度要求,用冒泡排序即可)。
- 实现Comparable接口的泛型变量数组创建方式:
this.object = (T[]) new Comparable[length];
因为必须是Comparable的子类,不能通过new Object创建(Object不是Comparable子类)。 - 通过字符串对应字符的ASCII码区分是数字还是其他字符串:
input.charAt(0) > 47 && input.charAt(0) < 58
代码
import java.util.Scanner;
class mArray<T extends Comparable<T>> { // Comparable:实现Comparable接口->支持排序
int length;
T[] object;
mArray(T[] object, int length) {
this.length = length;
// this.object = (T[]) new Object[length]; //Object不是Comparable子类
this.object = (T[]) new Comparable[length];
for (int i = 0; i < length; i++)
this.object[i] = object[i];
}
void mSort() {
for (int i = 0; i < length; i++) {
for (int j = i + 1; j < length; j++) {
int key = object[i].compareTo(object[j]);
if (key > 0) {
T tmp = object[i];
object[i] = object[j];
object[j] = tmp;
}
}
}
for (int i = 0; i < length; i++)
System.out.println(object[i]);
}
}
public class homework3_3 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
in.nextLine();
int strnum = 0, intnum = 0;
String[] str = new String[n];
Integer[] num = new Integer[n];
for (int i = 0; i < n; i++) {
String input = in.nextLine();
if (input.charAt(0) > 47 && input.charAt(0) < 58)
num[intnum++] = Integer.valueOf(input);
else
str[strnum++] = input;
}
in.close();
mArray<Integer> iArray = new mArray<Integer>(num, intnum);
iArray.mSort();
mArray<String> sArray = new mArray<String>(str, strnum);
sArray.mSort();
}
}