博文正文开头格式:(2分)

项目

内容

《面向对象程序设计(java)》

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

这个作业的要求在哪里

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

作业学习目标

  1. 理解泛型概念;
  2. 掌握泛型类的定义与使用;
  3. 掌握泛型方法的声明与使用;
  4. 掌握泛型接口的定义与实现;
  5. 了解泛型程序设计,理解其用途。

随笔博文正文内容包括:

第一部分:总结第八章关于泛型程序设计理论知识(25分)

1、泛型程序设计概念

(1)JDK 5.0 中增加的泛型类型,是Java 语言中类型安全的一次重要改进。

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

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

2、泛型类的声明及实例化的方法

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

(2)如一个泛型类定义格式如下:class Generics<K,V>其中的K和V是类中的可变类型参数。

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

(4)泛型类可以有多个类型变量。例如:public class Pair<T, U> { … }

(5)类定义中的类型变量用于指定方法的返回类型以及域、局部变量的类型。

(6)泛型类的约束与局限性:

a)不能用基本类型实例化类型参数

b)运行时类型查询只适用于原始类型

c)不能抛出也不能捕获泛型类实例

d)参数化类型的数组不合法

e)不能实例化类型变量

f )泛型类的静态上下文中类型变量无效

g)注意擦除后的冲突

3、泛型方法的定义

(1)泛型方法:除了泛型类外,还可以只单独定义一个方法作为泛型方法,用于指定方法参数或者返回值为泛型类型,留待方法调用时确定。

(2)泛型方法可以声明在泛型类中,也可以声明在普通类中。

public class ArrayTool {
public static<E> void insert(E[] e, int i)
{
//请自己添加代码
}
public static<E> E valueAt(E[] e , int i)
{
//请自己添加代码
}
}

4、泛型接口的定义

 public interface IPool <T>
{
T get();
int add(T t);
}

(1)泛型变量的限定

a)定义泛型变量的上界

public class NumberGeneric< T extends Number>

b)定义泛型变量的下界

List<? superCashCard> cards = new ArrayList<T>();

5、泛型类型的继承规则

(1)Java中的数组是协变的(covariant),但这一原理不适用于泛型类型

(2)Java中泛型类不具协变性。

(3)泛型类可扩展或实现其它的泛型类。

6、通配符类型及使用方法

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

a)单独的?,用于表示任何类型

b)? extends type,表示带有上界。

c )? super type,表示带有下界。

(2)通配符的类型限定

a)Pair<? extends Employee>

b)  Pair<? super Manager>

c)  无限定通配符:Pair<?>。 Pair<?>与Pair的不同在于:可以用任意Object 对象调用原始的Pair类的setObject方法。

第二部分:实验部分

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

测试程序1:

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

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

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

程序代码如下:

PairTets1:

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<String> mm = ArrayAlg.minmax(words);
System.out.println("min = " + mm.getFirst());
System.out.println("max = " + mm.getSecond());
}
} class ArrayAlg
{
/**
* 获取字符串数组的最小值和最大值。.
* @param a an array of strings
* @return 一个具有最小值和最大值的对,如果A为空或空,则为null
*/
public static Pair<String> minmax(String[] a)//用具体的类型替换类型变量可以实例化泛型类型
{
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);
}
}

Pair:

package pair1;

/**
* @version 1.00 2004-05-10
* @author Cay Horstmann
*/
public class Pair<T> //定义了一个泛型类,该类引入了一个类型变量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类引入了一个类型变量T,用尖括号(<>)括起来,并放在类名的后面。泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:

public class Pair<T,U> {......} 

类定义中的类型变量指定方法的返回类型以及域和局部变量的类型。例如:private T first;  //uses the type variable

用具体的类型替换类型变量就可以实例化泛型类型,例如:Pair<String> 

测试程序2:

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

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

了解泛型方法、泛型变量限定的定义及用途。

程序代码如下:

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<LocalDate> mm = ArrayAlg.minmax(birthdays); //实例化对象mm
System.out.println("min = " + mm.getFirst());
System.out.println("max = " + mm.getSecond());
}
} class ArrayAlg
{
/**
获取T类型对象数组的最小值和最大值。
@param T类型的对象数组
@return 一个具有最小值和最大值的对,如果A为空或空,则为null
*/
public static <T extends Comparable> Pair<T> minmax(T[] a)
{
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);
}
} 

Pair:

package pair2;

/**
* @version 1.00 2004-05-10
* @author Cay Horstmann
*/
public class Pair<T> //定义了一个泛型类,该类引入了一个类型变量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; }
}  

程序运行结果如下:

泛型方法可以定义在普通类中,也可以定义在泛型类中,当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:String middle=ArrayAlg.<String>getMiddle("John","Q.","Public")

;在这种情况下,方法调用中可以省略<String>类型参数。

泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

为了让不同方法可以操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。

*extends E: 可以接收E类型或者E的子类型,上限。
*super E: 可以接收E类型或者E的父类型,下限。

测试程序3:

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

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

程序代码如下:

PairTest3:

package pair3;

/**
* @version 1.01 2012-01-26
* @author Cay Horstmann
*/
public class PairTest3
{
public static void main(String[] args)
{
var ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15);
var cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15);
var buddies = new Pair<Manager>(ceo, cfo);
printBuddies(buddies); ceo.setBonus(1000000);
cfo.setBonus(500000);
Manager[] managers = { ceo, cfo }; var result = new Pair<Employee>();
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<? extends Employee> 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<? super Manager> 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<? super Manager> result)
{
minmaxBonus(a, result);
PairAlg.swapHelper(result);// SavaHelp捕获通配符类型
}
// 无法写入公共静态<T超级管理器> ...
} 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 <T> void swapHelper(Pair<T> p)
{
T t = p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(t);
}
}

Pair:

package pair3;

/**
* @version 1.00 2004-05-10
* @author Cay Horstmann
*/
public class Pair<T> //定义了一个泛型类,该类引入了一个类型变量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; }
}

Employee:

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

Manager:

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

  程序运行结果如下:

当要使用泛型类的时候,应该为这个泛型类传入一个类型实参,如果没有传入类型实际参数的时候,编译器就会提出泛型警告。

关于通配符的使用:

在API中使用通配符比较需要技巧,但通配符可以使API代码灵活许多。

如果编写的是广泛使用的类库,一定要适当是使用通配符。通配符有一个原则,即:producer-extends,consumer-super(PECS).就是典型的生产者,消费者模型问题。

为了表示各种泛型 List 的父类,可以使用类型通配符(?),将问号作为类型实参传给 List 集合,写作:List<?>(意思是元素类型未知的 List),此问号的元素类型可以匹配任何类型。

实验2:结对编程练习(32分)

程序代码如下:

import java.util.ArrayList;
import java.util.Scanner; interface GeneralStack<T>{
public T push(T item); //如item为null,则不入栈直接返回null。
public T pop(); //出栈,如为栈为空,则返回null。
public T peek(); //获得栈顶元素,如为空,则返回null.
public boolean empty();//如为空返回true
public int size(); //返回栈中元素数量
}
class ArrayListGeneralStack implements GeneralStack{
ArrayList list=new ArrayList();
@Override
public String toString() {
return list.toString();
} @Override
public Object push(Object item) {
if (list.add(item)){
return item;
}else {
return false;
}
} @Override
public Object pop() {
if (list.size()==0){
return null;
}
return list.remove(list.size()-1);
} @Override
public Object peek() {
return list.get(list.size()-1);
} @Override
public boolean empty() {
if (list.size()==0){
return true;
}else {
return false;
}
} @Override
public int size() {
return list.size();
}
}
class Car{
private int id;
private String name; @Override
public String toString() {
return "Car [" +
"id=" + id +
", name=" + name +
']';
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Car(int id, String name) {
this.id = id;
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while (true){
String s=sc.nextLine();
if (s.equals("Double")){
System.out.println("Double Test");
int count=sc.nextInt();
int pop_time=sc.nextInt();
ArrayListGeneralStack arrayListGeneralStack = new ArrayListGeneralStack();
for (int i=0;i<count;i++){
System.out.println("push:"+arrayListGeneralStack.push(sc.nextDouble()));
}
for (int i=0;i<pop_time;i++){
System.out.println("pop:"+arrayListGeneralStack.pop());
}
System.out.println(arrayListGeneralStack.toString());
double sum=0;
int size=arrayListGeneralStack.size();
for (int i=0;i<size;i++){
sum+=(double)arrayListGeneralStack.pop();
}
System.out.println("sum="+sum);
System.out.println("interface GeneralStack");
}else if (s.equals("Integer")){
System.out.println("Integer Test");
int count=sc.nextInt();
int pop_time=sc.nextInt();
ArrayListGeneralStack arrayListGeneralStack = new ArrayListGeneralStack();
for (int i=0;i<count;i++){
System.out.println("push:"+arrayListGeneralStack.push(sc.nextInt()));
}
for (int i=0;i<pop_time;i++){
System.out.println("pop:"+arrayListGeneralStack.pop());
}
System.out.println(arrayListGeneralStack.toString());
int sum=0;
int size=arrayListGeneralStack.size();
for (int i=0;i<size;i++){
sum+=(int)arrayListGeneralStack.pop();
}
System.out.println("sum="+sum);
System.out.println("interface GeneralStack");
}else if (s.equals("Car")){
System.out.println("Car Test");
int count=sc.nextInt();
int pop_time=sc.nextInt();
ArrayListGeneralStack arrayListGeneralStack = new ArrayListGeneralStack();
for (int i=0;i<count;i++){
int id=sc.nextInt();
String name=sc.next();
Car car = new Car(id,name);
System.out.println("push:"+arrayListGeneralStack.push(car));
}
for (int i=0;i<pop_time;i++){
System.out.println("pop:"+arrayListGeneralStack.pop());
}
System.out.println(arrayListGeneralStack.toString());
if (arrayListGeneralStack.size()>0){
int size=arrayListGeneralStack.size();
for (int i=0;i<size;i++){
Car car=(Car) arrayListGeneralStack.pop();
System.out.println(car.getName());
}
}
System.out.println("interface GeneralStack");
}else if (s.equals("quit")){
break;
}
} }
}

  程序运行结果如下:

实验总结:(15分)

通过本周的学习,我了解了泛型程序设计,泛型类和泛型方法同时具备可重用性、类型安全和效率,泛型类不会强行对值类型进行装箱和拆箱,或对引用类型进行向下强制类型转换,所以是编程性能得到提高。我觉得泛型程序设计的优点是编写代码可以被很多不同类型的对象所重用。减少了代码量,而且增加了程序的可读性。在学习理论课时,听老师讲泛型类不算特别难,但在实验课上运行程序时,并不是太理解程序,在自己编程时,还是有很大问题。在之后的学习中,我会多练习程序去了解这些知识。

201871010116-祁英红《面向对象程序设计(java)》第十一周学习总结的更多相关文章

  1. 201771010134杨其菊《面向对象程序设计java》第九周学习总结

                                                                      第九周学习总结 第一部分:理论知识 异常.断言和调试.日志 1.捕获 ...

  2. 201871010132-张潇潇《面向对象程序设计(java)》第一周学习总结

    面向对象程序设计(Java) 博文正文开头 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cn ...

  3. 扎西平措 201571030332《面向对象程序设计 Java 》第一周学习总结

    <面向对象程序设计(java)>第一周学习总结 正文开头: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 ...

  4. 杨其菊201771010134《面向对象程序设计Java》第二周学习总结

    第三章 Java基本程序设计结构 第一部分:(理论知识部分) 本章主要学习:基本内容:数据类型:变量:运算符:类型转换,字符串,输入输出,控制流程,大数值以及数组. 1.基本概念: 1)标识符:由字母 ...

  5. 201871010124 王生涛《面向对象程序设计JAVA》第一周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://edu.cnblogs.com/campus/xbsf/ ...

  6. 201871010115——马北《面向对象程序设计JAVA》第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  7. 201777010217-金云馨《面向对象程序设计(Java)》第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  8. 201871010132——张潇潇《面向对象程序设计JAVA》第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  9. 201771010123汪慧和《面向对象程序设计Java》第二周学习总结

    一.理论知识部分 1.标识符由字母.下划线.美元符号和数字组成, 且第一个符号不能为数字.标识符可用作: 类名.变量名.方法名.数组名.文件名等.第二部分:理论知识学习部分 2.关键字就是Java语言 ...

  10. 20172325 2017-2018-2 《Java程序设计》第十一周学习总结

    20172325 2017-2018-2 <Java程序设计>第十一周学习总结 教材学习内容总结 Android简介 Android操作系统是一种多用户的Linux系统,每个应用程序作为单 ...

随机推荐

  1. 深入理解 ZK集群中通过Processor保证数据一致性

    入口 书接上篇博客中的ZK集群启动后完成数据的统一性恢复后,来到启动ZkServer的逻辑,接下来的重点工作就是启动不同角色的对应的不同的处理器Processor 如上图查看ZooKeeperServ ...

  2. Create a Report at Runtime 在运行时创建报表

    In this lesson, you will learn how to create reports at runtime. A report showing a list of Tasks wi ...

  3. DotNet Core中使用RabbitMQ

    上一篇随笔记录到RabbitMQ的安装,安装完成,我们就开始使用吧. RabbitMQ简介 AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协 ...

  4. 一文彻底搞清楚 Material Design

    一文彻底搞清楚 Material Design 首先声明以下介绍的关于 Material Design 的介绍,都是基于在 Android 环境下,其实 Material Design 是一种为了让 ...

  5. 表单生成器(Form Builder)之mongodb表单数据查询——返回分页数据和总条数

    上一篇笔记将开始定义的存储结构处理了一下,将FormItems数组中的表单项都拿到mongodb document的最外层,和以前的关系型数据类似,之不过好多列都是动态的,不固定,不过这并没有什么影响 ...

  6. Shell脚本监控CPU、内存和硬盘利用率

    1.监控CPU利用率(通过vmstat工具) #!/bin/bash #==================================================== # Author: l ...

  7. 使OrangePi Zero+支持U盘启动

    以下步骤均在Armbian系统中完成 一.无内存卡启动 1.使用armbian-config启动SPI 输入sudo armbian-config→选中System并回车→选中Hardware并回车→ ...

  8. 【python之路.一】基础

    数学操作符 数据类型 字符串复制(*复制次数int).连接(+) 该类操作只能同为字符串类型,否则需要强制转换类型 变量名规则 (驼峰式变量名&下划线式均可) # 注释 BIF(built-i ...

  9. 多个div的多文本部分展开显示+关键字自动标注

    效果: 源码: <%@ page language="java" contentType="text/html; charset=utf-8" pageE ...

  10. RN调试坑点总结(不定期更新)

    前言 我感觉,如果模拟器是个人的话,我已经想打死他了 大家不要催我学flutter啦,哈哈哈,学了后跟大家分享下 RN报错的终极解决办法 众所周知,RN经常遇到无可奈何的超级Bug, 那么对于这些问题 ...