王颖奇 20171010129《面向对象程序设计(java)》第十周学习总结
阅读原文时间:2023年07月09日阅读:2

实验十 泛型程序设计技术

实验时间 2018-11-1

1、实验目的与要求

(1) 理解泛型概念;

(2) 掌握泛型类的定义与使用;

(3) 掌握泛型方法的声明与使用;

(4) 掌握泛型接口的定义与实现;

(5)了解泛型程序设计,理解其用途。

2、实验内容和步骤

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

测试程序1:

编辑、调试、运行教材311312 代码,结合程序运行结果理解程序;

在泛型类定义及使用代码处添加注释;

掌握泛型类的定义及使用。

代码:

package pair1;

/**
* @version 1.01 2012-01-26
* @author Cay Horstmann
*/
public class PairTest1
{
public static void main(String[] args)
{
String[] words = { "Mary", "had", "a", "little", "lamb" };
Pair mm = ArrayAlg.minmax(words);
System.out.println("min = " + mm.getFirst());
System.out.println("max = " + mm.getSecond());
}
}

class ArrayAlg
//泛型类
{
/**
* Gets the minimum and maximum of an array of strings.
* @param a an array of strings
* @return a pair with the min and max value, or null if a is null or empty
*/
public static Pair minmax(String[] a)
//使用泛型Pair类
{
if (a == null || a.length == 0) return null;
String min = a[0];
String max = a[0];
for (int i = 1; i < a.length; i++) { if (min.compareTo(a[i]) > 0) min = a[i];
if (max.compareTo(a[i]) < 0) max = a[i]; } return new Pair<>(min, max);
}
}

PairTest1

package pair1;

/**
* @version 1.00 2004-05-10
* @author Cay Horstmann
*/
public class Pair
//Pair类引入了一个类型变量T,用尖括号(<>)括起来,并放在类名的后面。
{
private T first;
private T second;

public Pair() { first = null; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second; }

public T getFirst() { return first; }
public T getSecond() { return second; }

public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}

Pair

运行结果:

测试程序2:

编辑、调试运行教材315 PairTest2,结合程序运行结果理解程序;

在泛型程序设计代码处添加相关注释;

掌握泛型方法、泛型变量限定的定义及用途。

代码:

package pair2;

import java.time.*;

/**
* @version 1.02 2015-06-21
* @author Cay Horstmann
*/
public class PairTest2
{
public static void main(String[] args)
{
LocalDate[] birthdays =
{
LocalDate.of(1906, 12, 9), // G. Hopper
LocalDate.of(1815, 12, 10), // A. Lovelace
LocalDate.of(1903, 12, 3), // J. von Neumann
LocalDate.of(1910, 6, 22), // K. Zuse
};
Pair mm = ArrayAlg.minmax(birthdays);
//在Pair中定义一个LocalDate类的birthdays数组
System.out.println("min = " + mm.getFirst());
System.out.println("max = " + mm.getSecond());
}
}

class ArrayAlg
//泛型类ArrayAlg
{
/**
Gets the minimum and maximum of an array of objects of type T.
@param a an array of objects of type T
@return a pair with the min and max value, or null if a is
null or empty
*/
public static Pair minmax(T[] a)
//使用extends关键字,定义泛型变量的上界,调用Comparable接口
{
if (a == null || a.length == 0) return null;
T min = a[0];
T max = a[0];
for (int i = 1; i < a.length; i++) { if (min.compareTo(a[i]) > 0) min = a[i];
if (max.compareTo(a[i]) < 0) max = a[i]; } return new Pair<>(min, max);
}
}

PairTest2

package pair2;

/**
* @version 1.00 2004-05-10
* @author Cay Horstmann
*/
public class Pair
{
private T first;
private T second;

public Pair() { first = null; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second; }

public T getFirst() { return first; }
public T getSecond() { return second; }

public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}

Pair

运行结果:

测试程序3:

用调试运行教材335 PairTest3,结合程序运行结果理解程序;

了解通配符类型的定义及用途

代码:

package pair3;

/**
* @version 1.01 2012-01-26
* @author Cay Horstmann
*/
public class PairTest3
{
public static void main(String[] args)
{
Manager ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15);
Manager cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15);
Pair buddies = new Pair<>(ceo, cfo);
printBuddies(buddies);

  ceo.setBonus(1000000);  
  cfo.setBonus(500000);  
  Manager\[\] managers = { ceo, cfo };

  Pair<Employee> result = new Pair<>();  
  minmaxBonus(managers, result);  
  System.out.println("first: " + result.getFirst().getName()  
     + ", second: " + result.getSecond().getName());  
  maxminBonus(managers, result);  
  System.out.println("first: " + result.getFirst().getName()  
     + ", second: " + result.getSecond().getName());  

}

public static void printBuddies(Pair p)
{
Employee first = p.getFirst();
Employee second = p.getSecond();
System.out.println(first.getName() + " and " + second.getName() + " are buddies.");
}

public static void minmaxBonus(Manager[] a, Pair result)
{
if (a.length == 0) return;
Manager min = a[0];
Manager max = a[0];
for (int i = 1; i < a.length; i++) { if (min.getBonus() > a[i].getBonus()) min = a[i];
if (max.getBonus() < a[i].getBonus()) max = a[i];
}
result.setFirst(min);
result.setSecond(max);
}

public static void maxminBonus(Manager[] a, Pair result)
{
minmaxBonus(a, result);
PairAlg.swapHelper(result); // OK--swapHelper captures wildcard type
}
// Can't write public static
}

class PairAlg
{
public static boolean hasNulls(Pair p)
{
return p.getFirst() == null || p.getSecond() == null;
}

public static void swap(Pair p) { swapHelper(p); }

public static void swapHelper(Pair p)
{
T t = p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(t);
}
}

PairTest3

package pair3;

/**
* @version 1.00 2004-05-10
* @author Cay Horstmann
*/
public class Pair
{
private T first;
private T second;

public Pair() { first = null; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second; }

public T getFirst() { return first; }
public T getSecond() { return second; }

public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}

Pair

package pair3;

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

Employee

package pair3;

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);
bonus = 0;
}

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

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

public double getBonus()
{
return bonus;
}
}

Manager

运行结果:

实验2编程练习:

编程练习1:实验九编程题总结

l 实验九编程练习1总结(从程序总体结构说明、模块说明,目前程序设计存在的困难与问题三个方面阐述)。

程序总体结构:

主类Main和子类Student

模块说明:

Main

1.文件读取模块

2.根据实验要求,选择具体操作的模块

3.对年龄数据进行相应的处理

具体模块解释如下:

package shen;

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 Main {
/**
* 1.文件读取模块 利用ArrayList构造studentlist存放文件内容2. 创建文件字符流,分类读取文件内容 3.try/catch语句捕获异常
*/
private static ArrayList studentlist;

public static void main(String\[\] args) {  
    studentlist = new ArrayList<>();  
    Scanner scanner = new Scanner(System.in);  
    File file = new File("C:\\\\Users\\\\ASUS\\\\Desktop\\\\新建文件夹\\\\身份证号.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();  
        // 加入的捕获异常代码  
    }  
    /\*  
     \* 1.根据实验要求,选择具体操作的模块 2.利用switch语句选择具体的操作  
     \*/  
    boolean isTrue = true;  
    while (isTrue) {  
        System.out.println("选择你的操作,输入正确格式的选项");  
        System.out.println("A.字典排序");  
        System.out.println("B.输出年龄最大和年龄最小的人");  
        System.out.println("C.寻找老乡");  
        System.out.println("D.寻找年龄相近的人");  
        System.out.println("F.退出");  
        String m = scanner.next();  
        switch (m) {  
        case "A":  
            Collections.sort(studentlist);  
            System.out.println(studentlist.toString());  
            break;  
        case "B":  
            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("年龄最大:" + studentlist.get(k1));  
            System.out.println("年龄最小:" + studentlist.get(k2));  
            break;  
        case "C":  
            System.out.println("老家?");  
            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("老乡" + studentlist.get(i));  
            }  
            break;

        case "D":  
            System.out.println("年龄:");  
            int yourage = scanner.nextInt();  
            int near = agenear(yourage);  
            int value = yourage - studentlist.get(near).getage();  
            System.out.println("" + studentlist.get(near));  
            break;  
        case "F":  
            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;  
}

}

Main

Student

对数据进行具体处理的模块

具体模块解释如下:

package shen;

/*
* 分类返回具体数据
*利用接口技术比较name的大小
*用toString方法返回数据
*/
public class Student implements Comparable {

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) {  
    // int a = Integer.parseInt(age);  
    this.age = age;  
}

public String getprovince() {  
    return province;  
}

public void setprovince(String province) {  
    this.province = province;  
}

public int compareTo(Student o) {  
    return this.name.compareTo(o.getName());  
}

public String toString() {  
    return name + "\\t" + sex + "\\t" + age + "\\t" + number + "\\t" + province + "\\n";  
}  

}

Student

目前程序设计存在的困难与问题:

路径设置不正确,无法读取身份证号.txt文件

l 实验九编程练习2总结(从程序总体结构说明、模块说明,目前程序设计存在的困难与问题三个方面阐述)。

程序总体结构说明:

主类demo和子类yunsuan

主类demo:main函数(主函数)

子类yusuan:计算四则运算结果并将结果返回

模块说明:

demo:

*文件输出模块

*四则运算生成模块

具体模块说明在代码中(如下):

package demo;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.Scanner;

public class demo {
public static void main(String[] args) {
/**
*文件输出模块
*1.调用构造函数counter
*2.创建文件字符流,将out中的内容设为空(null)
*3.将out结果输出到test.txt中
*4.try/catch模块捕获异常
*/
Scanner in = new Scanner(System.in);
yunsuan counter = new yunsuan();
PrintWriter out = null;
try {
out = new PrintWriter("text.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
*四则运算生成模块
*1.定义一个int型sum,计算成绩,并说明生成的运算类型
*2.for语句,将{}内的内容循环10次,从而生成10道题目
*3.随机生成int型a与b,范围在0到100以内;生成int型m,范围为1,2,3,4
*4.利用switch语句,根据生成m的值,随机生成加减乘除四则运算
*5.将循环结果输出到test.txt中
*/
int sum = 0;
System.out.println("随机生成的四则运算类型");
System.out.println("类型1:除法");
System.out.println("类型2:乘法");
System.out.println("类型3:加法");
System.out.println("类型4:减法");

    for (int i = 1; i <= 10; i++) {  
        int a = (int) Math.round(Math.random() \* 100);  
        int b = (int) Math.round(Math.random() \* 100);  
        int m;  
        Random rand = new Random();  
        m = (int) rand.nextInt(4) + 1;  
        System.out.println("随机生成的四则运算类型:"+m);

        switch (m) {  
        case 1:  
            System.out.println(i + ": " + a + "/" + b + "=");

            while (b == 0) {  
                b = (int) Math.round(Math.random() \* 100);  
            }

            double c0 = in.nextDouble();  
            out.println(a + "/" + b + "=" + c0);  
            if (c0 == counter.division(a, b)) {  
                sum += 10;  
                System.out.println("right!");  
            } else {  
                System.out.println("error!");  
            }

            break;

        case 2:  
            System.out.println(i + ": " + a + "\*" + b + "=");  
            int c = in.nextInt();  
            out.println(a + "\*" + b + "=" + c);  
            if (c == counter.multiplication(a, b)) {  
                sum += 10;  
                System.out.println("right!");  
            } else {  
                System.out.println("error!");  
            }  
            break;  
        case 3:  
            System.out.println(i + ": " + a + "+" + b + "=");  
            int c1 = in.nextInt();  
            out.println(a + "+" + b + "=" + c1);  
            if (c1 == counter.add(a, b)) {  
                sum += 10;  
                System.out.println("right!");  
            } else {  
                System.out.println("error!");  
            }  
            break;  
        case 4:  
            System.out.println(i + ": " + a + "-" + b + "=");  
            int c2 = in.nextInt();  
            out.println(a + "-" + b + "=" + c2);  
            if (c2 == counter.reduce(a, b)) {  
                sum += 10;  
                System.out.println("right!");  
            } else {  
                System.out.println("error!");  
            }  
            break;  
        }  
    }  
    System.out.println("成绩" + sum);  
    out.println("成绩:" + sum);  
    out.close();  
}  

}

demo

yunsuan:

*四则运算计算模块

package demo;

public class yunsuan {
private int a;
private int b;
public int add(int a,int b)
{
return a+b;
}
public int reduce(int a,int b)
{
return a-b;
}
public int multiplication(int a,int b)
{
return a*b;
}
public int division(int a,int b)
{
if(b!=0)
return a/b;
else
return 0;
}

}

yunsuan

目前程序设计存在的困难与问题:
1.生成的除法式子无法整除(不符合小学生四则运算的知识范围),并且在输入正确结果后,无法输出正确语句。
2.生成的减法式子,结果可能为负数(不符合小学生四则运算的知识范围)。
3.曾经的思路无法将四则运算的式子输出到test.txt文档中。

编程练习2:采用泛型程序设计技术改进实验九编程练习2,使之可处理实数四则运算,其他要求不变。

更改思路:

1.使用泛型技术进行改进

2.对于无法整除(除不尽,不满足小学生四则运算的知识范围)的问题,可以设置条件,使随机生成的a,b的值能够满足整除(a>b,a%b==0,(a/b)%1==0)

3.对于减法式子会出现结果为负数的问题(同上:不满足小学生四则运算的知识范围),可以设置条件,使随机生成的a>b

具体代码如下:

package demo;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.Scanner;

public class demo {
public static void main(String[] args) {
/**
*文件输出模块
*1.调用构造函数counter
*2.创建文件字符流,将out中的内容设为空(null)
*3.将out结果输出到test.txt中
*4.try/catch模块捕获异常
*/
Scanner in = new Scanner(System.in);
yunsuan counter = new yunsuan();
PrintWriter out = null;
try {
out = new PrintWriter("test.txt");
} catch (FileNotFoundException e) {
System.out.println("文件夹输出失败");
e.printStackTrace();
}
/**
*四则运算生成模块
*1.定义一个int型sum,计算成绩,并说明生成的运算类型
*2.for语句,将{}内的内容循环10次,从而生成10道题目
*3.随机生成int型a与b,范围在0到100以内;生成int型m,范围为1,2,3,4
*4.利用switch语句,根据生成m的值,随机生成加减乘除四则运算
*5.将循环结果输出到test.txt中
*/
int sum = 0;
System.out.println("随机生成的四则运算类型");
System.out.println("类型1:除法");
System.out.println("类型2:乘法");
System.out.println("类型3:加法");
System.out.println("类型4:减法");

    for (int i = 1; i <= 10; i++) {  
        int a = (int) Math.round(Math.random() \* 100);  
        int b = (int) Math.round(Math.random() \* 100);  
        int m;  
        Random rand = new Random();  
        m = (int) rand.nextInt(4) + 1;  
        System.out.println("随机生成的四则运算类型:" + m);

        switch (m) {  
        case 1:  
            a = b + (int) Math.round(Math.random() \* 100);  
            while(b == 0){  
                b = (int) Math.round(Math.random() \* 100);  
            }  
            while(a % b != 0){  
                a = (int) Math.round(Math.random() \* 100);

            }  
                            //若生成的除法式子必须能整除,且满足分母为0的条件,则a一定要大于b,且a模b的结果要为0。  
            System.out.println(i + ": " + a + "/" + b + "=");

            int c0 = in.nextInt();  
            out.println(a + "/" + b + "=" + c0);  
            if (c0 == counter.division(a, b)) {  
                sum += 10;  
                System.out.println("right!");  
            } else {  
                System.out.println("error!");  
            }

            break;

        case 2:  
            System.out.println(i + ": " + a + "\*" + b + "=");  
            int c = in.nextInt();  
            out.println(a + "\*" + b + "=" + c);  
            if (c == counter.multiplication(a, b)) {  
                sum += 10;  
                System.out.println("right!");  
            } else {  
                System.out.println("error!");  
            }  
            break;  
        case 3:  
            System.out.println(i + ": " + a + "+" + b + "=");  
            int c1 = in.nextInt();  
            out.println(a + "+" + b + "=" + c1);  
            if (c1 == counter.add(a, b)) {  
                sum += 10;  
                System.out.println("right!");  
            } else {  
                System.out.println("error!");  
            }  
            break;  
        case 4:  
            while (a < b) {  
                b = (int) Math.round(Math.random() \* 100);  
            }  
                            //因为不能产生运算结果为负数的减法式子,所以a一定要大于b。若a<b,则重新生成b。  
            System.out.println(i + ": " + a + "-" + b + "=");  
            int c2 = in.nextInt();  
            out.println(a + "-" + b + "=" + c2);  
            if (c2 == counter.reduce(a, b)) {  
                sum += 10;  
                System.out.println("right!");  
            } else {  
                System.out.println("error!");  
            }  
            break;  
        }  
    }  
    System.out.println("成绩" + sum);  
    out.println("成绩:" + sum);  
    out.close();  
}  

}

demo

package demo;

public class yunsuan {
private T a;
private T b;

public yunsuan() {  
    a = null;  
    b = null;  
}  
public yunsuan(T a, T b) {  
    this.a = a;  
    this.b = b;  
}

public int add(int a,int b) {  
    return a + b;  
}

public int reduce(int a, int b) {  
    return a - b;  
}

public int multiplication(int a, int b) {  
    return a \* b;  
}

public int division(int a, int b) {  
    if (b != 0 && a%b==0)  
        return a / b;  
    else  
        return 0;  
}  

}

yunsuan

运行结果:

学习总结:

泛型程序设计(技术):

泛型:也称参数化类型(parameterized type),就是在定义类、接口和方法时,通过类型参数指示将要处理的对象类型。(如ArrayList类)

泛型程序设计(Generic programming):编写___代码可以被很多不同类型的对象所重用。_

泛型类的定义:

一个泛型类(generic class)就是具有一个或多___个类型变量的类,即创建用类型作为参数的类。_

小结:

_1.某类引入了一个类型变量T,用尖括号(<>)括起来,并放在类名的后面。_

_2.________类定义中的类型变量用于指定方法的返回类型以__及域、局部变量的类型。_

泛型方法的声明:

泛型方法:

_– 除了泛型类外,还可以只单独定义一个方法作____________为泛型方法,用于指定方法参数或者返回值为___________泛型类型,留待方法调用时确__

– 泛型方法可以声明在泛型类中,也可以声明在普通类

泛型接口的定义

泛型变量的限定:

1.定义泛型变量的上界

extends关键字所声明的上界既可以是一个类,也可以是一个接口

2.定义泛型变量的下界

– 通过使用super关键字可以固定泛型参数的类型为某种_类型或者其超类_

– 当程序希望为一个方法的参数限定类型时,通常可以使_______用下限通配符_

泛型类的约束与局限性(_______*___________________)__

不能用基本类型实例化类型参数 运行时类型查询只适用于原始类型 不能抛出也不能捕获泛型类实例 参数化类型的数组不合法 不能实例化类型变量 泛型类的静态上下文中类型变量无效注意擦除后的

泛型类型的继承规则(*)

Java中的数组是协变的(covariant)。

通配符类型

通配符

– “?”符号表明参数的类型可以是任何一种类_型,它和参数T的含义是有区别的。T表示一种未知类型,而“?”表示任何一种类型。这种_通配符一般有以下三种用法:


– 单独的?,用于表示任何类型。 – ? extends type,表示带有上界。 – ? super type,表示带有下界。

学习小结

通过这个周的学习,我了解了泛型设计技术的概念,以及好处和限制,基本上会运用泛型技术设计程序,但是在通配符的运用方面仍然不太懂,望老师能够再次讲解。