项目html |
内容java |
这个做业属于哪一个课程编程 |
|
这个做业的要求在哪里安全 |
https://www.cnblogs.com/nwnu-daizh/p/11815810.htmldom |
做业学习目标ide |
|
第一部分:总结第八章关于泛型程序设计理论知识学习
什么是泛型程序设计?
●JDK 5.0中增长的泛型类型,是Java语言中类型安全的一次重要改进。测试
泛型:也称参数化类型(parameterized type),就是在定义类、接口和方法时,经过类型参数指示将要处理的对象类型。( 如ArrayList类)ui
●泛型程序设计(Generic programming) :编写代码能够被不少不一样类型的对象所重用。
Java泛型设计原则:只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常.
泛型:把类型明确的工做推迟到建立对象或调用方法的时候才去明确的特殊的类型
参数化类型:
<数据类型>
只能是引用类型相关术语:
ArrayList<E>
中的E称为类型参数变量ArrayList<Integer>
中的Integer称为实际类型参数ArrayList<E>
泛型类型ArrayList<Integer>
称为参数化的类型ParameterizedType泛型类的定义
●一个泛型类(generic class) 就是具备一个或多个类型变量的类,即建立用类型做为参数的类。
如一个泛型类定义格式以下: class Generics< K,V>
其中K和V是类的可变类型参数。
泛型类的最基本写法:
例子:
Pair类引入了一个类型变量T,用尖括号(<>)括起来,并放在类名的后面。
泛型类能够有多个类型变量。例如:
public class Pair<T, U> {…}
类的类型变量用于指定方法的返回类型以及域、局部变量的类型。
泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型
泛型方法的声明
泛型方法
除了泛型类外,还能够只单独定义一一个方法做为泛型方法,用于指定方法参数或者返回值为泛型类型,留待方法调用时肯定。
泛型方法能够声明在泛型类中,也能够声明在普通类中。
泛型方法的基本用法例子:
/** * 首先在public与返回值之间的<T>必不可少,这代表这是一个泛型方法,而且声明了一个泛型T * 这个T能够出如今这个泛型方法的任意位置. * 泛型的数量也能够为任意多个 * 如:public <T,K> K showKeyName(Generic<T> container){ * ... * } */ public class 泛型方法 { @Test public void test() { test1(); test2(new Integer(2)); test3(new int[3],new Object()); //打印结果 // null // 2 // [I@3d8c7aca // java.lang.Object@5ebec15 } //该方法使用泛型T public <T> void test1() { T t = null; System.out.println(t); } //该方法使用泛型T //而且参数和返回值都是T类型 public <T> T test2(T t) { System.out.println(t); return t; } //该方法使用泛型T,E //参数包括T,E public <T, E> void test3(T t, E e) { System.out.println(t); System.out.println(e); } }
泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各类类的生产器中,例子:
当实现泛型接口的类,未传入泛型实参时:
/** * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一块儿加到类中 * 即:class FruitGenerator<T> implements Generator<T>{ * 若是不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class" */ class FruitGenerator<T> implements Generator<T>{ @Override public T next() { return null; } }
当实现泛型接口的类,传入泛型实参时:
/** * 传入泛型实参时: * 定义一个生产器实现这个接口,虽然咱们只建立了一个泛型接口Generator<T> * 可是咱们能够为T传入无数个实参,造成无数种类型的Generator接口。 * 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则全部使用泛型的地方都要替换成传入的实参类型 * 即:Generator<T>,public T next();中的的T都要替换成传入的String类型。 */ public class FruitGenerator implements Generator<String> { private String[] fruits = new String[]{"Apple", "Banana", "Pear"}; @Override public String next() { Random rand = new Random(); return fruits[rand.nextInt(3)]; } }
1)定义泛型变量的上界
public class NumberGeneric< T extends Number>
2)泛型变量上界的说明
上述声明规定了NumberGeneric类所能处理的泛型变量类型需和Number有继承关系;
3)extends 关键字所声明的上界既能够是一个类,也能够是一个接口;
4)<T extends Bounding Type>表示T应该是绑定类型的子类型。
5)一个类型变量或通配符能够有多个限定,限定类型用“&”分割。例如:
< T extends Comparable & Serializable >
6)定义泛型变量的下界
List<? super CashCard> cards = new ArrayList<T>();
7)泛型变量下界的说明
经过使用super关键字能够固定泛型参数的类型为某种类型的超类
当但愿为一个方法的参数限定类型时,一般可使用下限通配符
public static <T> void sort(T[] a,Comparator<? super T> c)
{ ……
}
通配符:
“?”代表参数类型能够是任何一种类型,通配符通常有如下三种用法:
1)单独的?,用于表示任何类型。
2)? extends type, 表示带有上界。
3)?supertype,表示带有下界。
通配符的类型限定
Pair<? extends Employee>
Pair<? super Manager>
Pair<?>
●不能用基本类型实例化类型参数
●运行时类型查询只适用于原始类型
●不能抛出也不能捕获泛型类实例
●参数化类型的数组不合法
●不能实例化类型变量
●泛型类的静态上下文中类型变量无效
●注意擦除后的冲突
1)Java中的数组是协变的( covariant)。
例如: Integer扩 展了Number,那么在要求Number[]的地方彻底能够传递或者赋予IntegerD,Number[]也是Integer[]的超类型。
Employee是Manager的超类,所以能够将一个Manager[]数组赋给一个 类型为Employee[]的变量:
Manager[] managerBuddies = {ceo, cfo};
Employee[] employeeBuddies = managerBuddies;
2)但这一原理不适用于泛型类型。
例如:
Pair<Manager> managerBuddies = new Pair<Manager>(ceo, cfo);
Pair<Employee> employeeBuddies = managerBuddies; /illgal
employeeBuddies.setFirst(lowlyEmployee); .
3)不容许这样作的理由:避免破坏要提供类型的安全泛型。
4)Java中泛型类不具协变性。若是可以将List<Integer>赋给List<Number>。那么下面的代码就容许将非Integer的内容放入List<Integer>:
List<Integer> li = new ArrayList<Integer>();
List<Number> In = li; // illegal
In.add(new Float(3.1415));
5)泛型类可扩展或实现其它的泛型类。例如,
ArrayList<T>类实现List<T>接口。这意味着,- 一个
ArrayList<Manager>能够被转换为个List<Manager>。
1)定义一个泛型类时,在<>”内定义形式类型参数,例如:“class TestGeneric<K, V>”,其中“K",“V”不表明值,而是表示类型。
2)实例化泛型对象的时候,必定要在类名后面指定类型参数的值(类型),一共要有两次书写。例如:
TestGeneric <String, String> t = new TestGeneric < String, String> ();
3)泛型中<T extends Object> ,extends并不表明继承,它是类型范围限制。
4)泛型类不是协变的。
2、实验内容和步骤
实验1: 导入第8章示例程序,测试程序并进行代码注释。
测试程序1:
编辑、调试、运行教材311、312页代码,结合程序运行结果理解程序;
在泛型类定义及使用代码处添加注释;
掌握泛型类的定义及使用。
代码:
package pair1; /** * @version 1.00 2004-05-10 * @author Cay Horstmann */ public class Pair<T> //Pair类引用一个类型变量T,(T:泛型标识) { //实例化泛型类时,指定T的具体类型(类型变量能够指定方法的返回类型以及类变量和局部变量的类型) //泛型类型的继承(能够参数化类型转换为原始类型)(如:Pair<Manager >是原始类型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() { //getFirst方法 return first; } public T getSecond() { //getSecond方法 return second; } public void setFirst(T newValue) { //setFirst方法 first = newValue; } public void setSecond(T newValue) { //setSecond方法 second = newValue; } }
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 { //泛型类 /** * Gets the minimum and maximum of an array of strings. * @param a an array of strings * @return a pair with the min and max values, or null if a is null or empty */ public static Pair<String> 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];//若比较结果大于0,则代表此时的min不是最小的,将新的字符串存进min if (max.compareTo(a[i]) < 0) max = a[i];//和上面min的 比较方法同样 } return new Pair<>(min, max);//返回新的Pair类对象 } }
运行结果:
测试程序2:
编辑、调试运行教材315页 PairTest2,结合程序运行结果理解程序;
在泛型程序设计代码处添加相关注释;
了解泛型方法、泛型变量限定的定义及用途。
代码:
package pair2; /** * @version 1.00 2004-05-10 * @author Cay Horstmann */ //Pair泛型类 public class Pair<T> //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; } }
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); //在Pair类中定义对象mm和一个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 values, or null if a is null or empty */ public static <T extends Comparable> Pair<T> minmax(T[] a) //将T限制为 实现了Comparable接口的类,则泛型的minmax方法只能被实现了Comparable接口的类的数组调用 //使用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];//若比较结果大于0,则代表此时的min不是最小的,将新的字符串存进min if (max.compareTo(a[i]) < 0) max = a[i];//和上面min的 比较方法同样 } return new Pair<>(min, max);//返回新的Pair类对象 } }
运行结果:
测试程序3:
用调试运行教材335页 PairTest3,结合程序运行结果理解程序;
了解通配符类型的定义及用途。
代码:
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() //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; } }
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; } }
package pair3; /** * @version 1.00 2004-05-10 * @author Cay Horstmann */ public class Pair<T> //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; } }
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的任何一种类型 { 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) //?是通配符,代表参数的类型是下界为manager的任何一种类型 { 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); // OK--swapHelper captures wildcard type } // can't write public static <T super manager> . . . } 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); } }
运行结果:
实验2:结对编程练习,将程序提交到PTA(2019面向对象程序设计基础知识测试题
(1) 编写一个泛型接口GeneralStack,要求类中方法对任何引用类型数据都适用。GeneralStack接口中方法以下:
(2)定义GeneralStack的子类ArrayListGeneralStack,要求:
类内使用ArrayList对象存储堆栈数据,名为list;
方法: public String toString()//代码为return list.toString();
代码中不要出现类型不安全的强制转换。
(3)定义Car类,类的属性有:
private int id;
private String name;
方法:Eclipse自动生成setter/getter,toString方法。
4)main方法要求
输入选项,有quit, Integer, Double, Car 4个选项。若是输入quit,程序直接退出。不然,输入整数m与n。m表明入栈个数,n表明出栈个数。而后声明栈变量stack。
输入Integer,打印Integer Test。创建能够存放Integer类型的ArrayListGeneralStack。入栈m次,出栈n次。打印栈的toString方法。最后将栈中剩余元素出栈并累加输出。
输入Double ,打印Double Test。剩下的与输入Integer同样。
输入Car,打印Car Test。其余操做与Integer、Double基本同样。只不过最后将栈中元素出栈,并将其name依次输出。
特别注意:若是栈为空,继续出栈,返回null
输入样例
输出样例
提交结果:
代码:
package F2; import java.util.Scanner; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Scanner ss=new Scanner(System.in); while(true) { String c=ss.nextLine(); if(c.equals("Integer")) { System.out.println("Integer Test"); int pushStack=ss.nextInt(); int popStack=ss.nextInt(); ArrayListGeneralStack Stack = new ArrayListGeneralStack(); for(int i=0;i<pushStack;i++) { System.out.print("push:"+Stack.push(ss.nextInt())); Stack.push(ss.nextInt()); } for(int i=0;i<popStack;i++) { System.out.println("pop:"+Stack.pop()); } System.out.println(Stack.toString()); int sum=0; int size=Stack.size(); for(int k=0;k<size;k++) { sum+=(int)Stack.pop(); } System.out.println("sum="+sum); System.out.println("interface GeneralStack"); } else if(c.equals("Double")) { System.out.println("Double Test"); int pushStack=ss.nextInt(); int popStack=ss.nextInt(); ArrayListGeneralStack Stack = new ArrayListGeneralStack(); for(int i=0;i<pushStack;i++) { System.out.print("push:"+Stack.push(ss.nextDouble())); Stack.push(ss.nextDouble()); } for(int i=0;i<popStack;i++) { System.out.println("pop:"+Stack.pop()); } System.out.println(Stack.toString()); double sum=0; int size=Stack.size(); for(int k=0;k<size;k++) { sum+=(double)Stack.pop(); } System.out.println("sum="+sum); System.out.println("interface GeneralStack"); } else if(c.equals("Car")) { System.out.println("Car Test"); int pushStack=ss.nextInt(); int popStack=ss.nextInt(); ArrayListGeneralStack Stack = new ArrayListGeneralStack(); for(int i=0;i<pushStack;i++) { int id=ss.nextInt(); String name=ss.next(); Car car=new Car(id,name); System.out.println("push:"+Stack.push(car)); } for(int i=0;i<popStack;i++) { System.out.println("pop:"+Stack.pop()); } System.out.println(Stack.toString()); int size=Stack.size(); for(int k=0;k<size;k++) { Car car=(Car)Stack.pop(); System.out.println(car.getName()); } System.out.println("interface GeneralStack"); } else if(c.equals("quit")){ System.out.println("程序终止"); break; } } ss.close(); } }
package F2; import java.util.ArrayList; class ArrayListGeneralStack implements GeneralStack<Object>{ ArrayList<Object> list=new ArrayList<>(); @Override public Object push(Object item) { if(item!=null) { list.add(item); return item; }else { return null; } } @Override public Object pop() { if(list.size()==0) { return null; }else { return list.remove(list.size()-1); } } @Override public Object peek() { if(list.size()==0) { return null; }else { 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(); } public String toString() { return list.toString(); } }
package F2; public class Car { private int id; private String name; public Car(int id, String name) { this.id = id; this.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; } @Override public String toString() { return "Car [id=" + id + ", name=" + name + "]"; } }
package F2; 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(); //返回栈中元素数量 }
实验总结:(15分)
理解掌握了泛型类的定义与使用,泛型方法的声明与使用;泛型接口的定义与实现;使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,而后再进行强行类型转换的代码具备更好的安全性和可读性。经过此次对泛型类的学习,我基本掌握泛型程序设计的“泛型”到底指的是什么,我但愿在之后的学习过程中可以愈来愈好。