項目html |
內容java |
這個做業屬於哪一個課程編程 |
https://www.cnblogs.com/nwnu-daizh/數組 |
這個做業的要求在哪裏安全 |
https://www.cnblogs.com/nwnu-daizh/p/11435127.htmlide |
做業學習目標學習 |
|
第一部分:總結第八章關於泛型程序設計理論知測試
1.1 泛型概述
在前面學習集合時,咱們都知道集合中是能夠存聽任意對象的,只要把對象存儲集合後,那麼這時他們都會被提高成Object類型。當咱們在取出每個對象,而且進行相應的操做,這時必須採用類型轉換。
你們觀察下面代碼:
~~~java
public class GenericDemo {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("abc");
coll.add("itcast");
coll.add(5);//因爲集合沒有作任何限定,任何類型均可以給其中存放
Iterator it = coll.iterator();
while(it.hasNext()){
//須要打印每一個字符串的長度,就要把迭代出來的對象轉成String類型
String str = (String) it.next();
System.out.println(str.length());
}
}
}
~~~
程序在運行時發生了問題**java.lang.ClassCastException**。 爲何會發生類型轉換異常呢? 咱們來分析下:因爲集合中什麼類型的元素均可以存儲。致使取出時強轉引起運行時 ClassCastException。 怎麼來解決這個問題呢? Collection雖然能夠存儲各類對象,但實際上一般Collection只存儲同一類型對象。例如都是存儲字符串對象。所以在JDK5以後,新增了**泛型**(**Generic**)語法,讓你在設計API時能夠指定類或方法支持泛型,這樣咱們使用API的時候也變得更爲簡潔,並獲得了編譯時期的語法檢查。
* **泛型**:能夠在類或方法中預支地使用未知的類型。
> tips:通常在建立對象時,將未知的類型肯定具體的類型。當沒有指定泛型時,默認類型爲Object類型。
1.2 使用泛型的好處
上一節只是講解了泛型的引入,那麼泛型帶來了哪些好處呢?
* 將運行時期的ClassCastException,轉移到了編譯時期變成了編譯失敗。
* 避免了類型強轉的麻煩。
經過咱們以下代碼體驗一下:
~~~java
public class GenericDemo2 {
public static void main(String[] args) {
Collection<String> list = new ArrayList<String>();
list.add("abc");
list.add("itcast");
// list.add(5);//當集合明確類型後,存放類型不一致就會編譯報錯
// 集合已經明確具體存放的元素類型,那麼在使用迭代器的時候,迭代器也一樣會知道具體遍歷元素類型
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
//當使用Iterator<String>控制元素類型後,就不須要強轉了。獲取到的元素直接就是String類型
System.out.println(str.length());
}
}
}
~~~
> tips:泛型是數據類型的一部分,咱們將類名與泛型合併一塊兒看作數據類型。
1.3 泛型的定義與使用
咱們在集合中會大量使用到泛型,這裏來完整地學習泛型知識。
泛型,用來靈活地將數據類型應用到不一樣的類、方法、接口當中。將數據類型做爲參數進行傳遞。
定義和使用含有泛型的類
定義格式:
~~~
修飾符 class 類名<表明泛型的變量> { }
~~~
例如,API中的ArrayList集合:
~~~java
class ArrayList<E>{
public boolean add(E e){ }
public E get(int index){ }
....
}
~~~
使用泛型: 即何時肯定泛型。
**在建立對象的時候肯定泛型**
例如,`ArrayList<String> list = new ArrayList<String>();`
此時,變量E的值就是String類型,那麼咱們的類型就能夠理解爲:
~~~java
class ArrayList<String>{
public boolean add(String e){ }
public String get(int index){ }
...
}
~~~
再例如,`ArrayList<Integer> list = new ArrayList<Integer>();`
此時,變量E的值就是Integer類型,那麼咱們的類型就能夠理解爲:
~~~java
class ArrayList<Integer> {
public boolean add(Integer e) { }
public Integer get(int index) { }
...
}
~~~
舉例自定義泛型類
~~~java
public class MyGenericClass<MVP> {
//沒有MVP類型,在這裏表明 未知的一種數據類型 將來傳遞什麼就是什麼類型
private MVP mvp;
public void setMVP(MVP mvp) {
this.mvp = mvp;
}
public MVP getMVP() {
return mvp;
}
}
~~~
使用:
~~~java
public class GenericClassDemo {
public static void main(String[] args) {
// 建立一個泛型爲String的類
MyGenericClass<String> my = new MyGenericClass<String>();
// 調用setMVP
my.setMVP("大鬍子登登");
// 調用getMVP
String mvp = my.getMVP();
System.out.println(mvp);
//建立一個泛型爲Integer的類
MyGenericClass<Integer> my2 = new MyGenericClass<Integer>();
my2.setMVP(123);
Integer mvp2 = my2.getMVP();
}
}
~~~
含有泛型的方法
定義格式:
~~~
修飾符 <表明泛型的變量> 返回值類型 方法名(參數){ }
~~~
例如,
~~~java
public class MyGenericMethod {
public <MVP> void show(MVP mvp) {
System.out.println(mvp.getClass());
}
public <MVP> MVP show2(MVP mvp) {
return mvp;
}
}
~~~
使用格式:**調用方法時,肯定泛型的類型**
~~~java
public class GenericMethodDemo {
public static void main(String[] args) {
// 建立對象
MyGenericMethod mm = new MyGenericMethod();
// 演示看方法提示
mm.show("aaa");
mm.show(123);
mm.show(12.45);
}
}
~~~
### 含有泛型的接口
定義格式:
~~~
修飾符 interface接口名<表明泛型的變量> { }
~~~
例如,
~~~java
public interface MyGenericInterface<E>{
public abstract void add(E e);
public abstract E getE();
}
~~~
使用格式:
**一、定義類時肯定泛型的類型**
例如
~~~java
public class MyImp1 implements MyGenericInterface<String> {
@Override
public void add(String e) {
// 省略...
}
@Override
public String getE() {
return null;
}
}
~~~
此時,泛型E的值就是String類型。
**二、始終不肯定泛型的類型,直到建立對象時,肯定泛型的類型**
例如
~~~java
public class MyImp2<E> implements MyGenericInterface<E> {
@Override
public void add(E e) {
// 省略...
}
@Override
public E getE() {
return null;
}
}
~~~
肯定泛型:
~~~java
/*
* 使用
*/
public class GenericInterface {
public static void main(String[] args) {
MyImp2<String> my = new MyImp2<String>();
my.add("aa");
}
}
~~~
1.4 泛型通配符
當使用泛型類或者接口時,傳遞的數據中,泛型類型不肯定,能夠經過通配符<?>表示。可是一旦使用泛型的通配符後,只能使用Object類中的共性方法,集合中元素自身方法沒法使用。
通配符基本使用
泛型的通配符:**不知道使用什麼類型來接收的時候,此時可使用?,?表示未知通配符。**
此時只能接受數據,不能往該集合中存儲數據。
舉個例子你們理解使用便可:
~~~java
public static void main(String[] args) {
Collection<Intger> list1 = new ArrayList<Integer>();
getElement(list1);
Collection<String> list2 = new ArrayList<String>();
getElement(list2);
}
public static void getElement(Collection<?> coll){}
//?表明能夠接收任意類型
~~~
> tips:泛型不存在繼承關係 Collection<Object> list = new ArrayList<String>();這種是錯誤的。
#### 通配符高級使用----受限泛型
以前設置泛型的時候,其實是能夠任意設置的,只要是類就能夠設置。可是在JAVA的泛型中能夠指定一個泛型的**上限**和**下限**。
**泛型的上限**:
* **格式**: `類型名稱 <? extends 類 > 對象名稱`
* **意義**: `只能接收該類型及其子類`
**泛型的下限**:
- **格式**: `類型名稱 <? super 類 > 對象名稱`
- **意義**: `只能接收該類型及其父類型`
好比:現已知Object類,String 類,Number類,Integer類,其中Number是Integer的父類
~~~java
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElement(list1);
getElement(list2);//報錯
getElement(list3);
getElement(list4);//報錯
getElement2(list1);//報錯
getElement2(list2);//報錯
getElement2(list3);
getElement2(list4);
}
// 泛型的上限:此時的泛型?,必須是Number類型或者Number類型的子類
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此時的泛型?,必須是Number類型或者Number類型的父類
public static void getElement2(Collection<? super Number> coll){}
~~~ui
第二部分:實驗部分this
實驗1: 導入第8章示例程序,測試程序並進行代碼註釋。
測試程序1:
l 編輯、調試、運行教材3十一、312頁代碼,結合程序運行結果理解程序;
l 在泛型類定義及使用代碼處添加註釋;
l 掌握泛型類的定義及使用。
/** * @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" };//初始化String對象數組 Pair<String> mm = ArrayAlg.minmax(words);//經過類名調用minmax方法 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<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];//字符串對象比較, if (max.compareTo(a[i]) < 0) max = a[i]; } return new Pair<>(min, max);//泛型類做爲返回值 }
package pair1; /** * @version 1.00 2004-05-10 * @author Cay Horstmann */ public class 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; } }
運行結果:
測試程序2:
l 編輯、調試運行教材315頁 PairTest2,結合程序運行結果理解程序;
l 在泛型程序設計代碼處添加相關注釋;
l 瞭解泛型方法、泛型變量限定的定義及用途。
package pair2; import java.time.*; /** * @version 1.02 2015-06-21 * @author Cay Horstmann */ public class PairTest2 { public static void main(String[] args) { //初始化LocalDate對象數組 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);//經過類名調用minmax方法 System.out.println("min = " + mm.getFirst()); System.out.println("max = " + mm.getSecond()); } } class 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 <T extends Comparable> Pair<T> minmax(T[] a)//經過extends關鍵字增長上界約束的泛型方法 { 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);//範型類做爲返回值 } }
運行結果:
測試程序3:
l 用調試運行教材335頁 PairTest3,結合程序運行結果理解程序;
l 瞭解通配符類型的定義及用途。
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<Manager> 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<? extends Employee> p)//通配符類型(帶有上界)extends關鍵字所聲明的上界既能夠是一個類,也能夠是一個接口。 { 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); //swapHelper捕獲通配符類型 } //沒法編寫公共靜態< T超級管理器> } class PairAlg { public static boolean hasNulls(Pair<?> p)//經過將hasNulls轉換成泛型方法,避免使用通配符類型 { return p.getFirst() == null || p.getSecond() == null; } public static void swap(Pair<?> p) { swapHelper(p); } public static <T> void swapHelper(Pair<T> p)//使用輔助方法swapHelper(泛型方法),以在交換時臨時保存第一個元素 { T t = p.getFirst(); p.setFirst(p.getSecond()); p.setSecond(t); }
public class Pair<T> { private T first; private T second; //T是未知類型,不表明值 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; } }
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; } }
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; } }
運行結果:
實驗2:結對編程練習
實驗2:結對編程練習,將程序提交到PTA(2019面向對象程序設計基礎知識測試題(2))
(1)編寫一個泛型接口GeneralStack,要求類中方法對任何引用類型數據都適用。GeneralStack接口中方法以下:
push(item); //如item爲null,則不入棧直接返回null。
pop(); //出棧,如爲棧爲空,則返回null。
peek(); //得到棧頂元素,如爲空,則返回null.
public boolean empty();//如爲空返回true
public int size(); //返回棧中元素數量
(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
輸入樣例
Integer
5
2
1 2 3 4 5
Double
5
3
1.1 2.0 4.9 5.7 7.2
Car
3
2
1 Ford
2 Cherry
3 BYD
quit
輸出樣例
Integer Test
push:1
push:2
push:3
push:4
push:5
pop:5
pop:4
[1, 2, 3]
sum=6
interface GeneralStack
Double Test
push:1.1
push:2.0
push:4.9
push:5.7
push:7.2
pop:7.2
pop:5.7
pop:4.9
[1.1, 2.0]
sum=3.1
interface GeneralStack
Car Test
push:Car [id=1, name=Ford]
push:Car [id=2, name=Cherry]
push:Car [id=3, name=BYD]
pop:Car [id=3, name=BYD]
pop:Car [id=2, name=Cherry]
[Car [id=1, name=Ford]]
Ford
interface GeneralStack
結對編程合做對象胡歡歡
結對編程實驗代碼:
GeneralStack接口:
package week111; public interface GeneralStack<T> { public T push(T item);//判斷棧是否爲空 public T pop();//出棧,若是棧爲空則返回null public T peek();//得到棧頂元素,若是爲空,則返回null public boolean empty();//如爲空返回true public int size(); //返回棧中元素數量 }
/*car類*/
package week111; public class Car { private int id; private String name; public String toString() { return "Car ["+"id="+id+",name="+name+']'; } public int getId() { return id; } public void setId() { 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; } }
/*ArrayListGeneralStack類*/
package week111; import java.util.ArrayList; public class ArrayListGeneralStack<E> implements GeneralStack { ArrayList list=new ArrayList<E>(); public String toString() { return list.toString(); } @Override public Object push(Object item) { // TODO Auto-generated method stub if(list.add(item)) { return item; } else { return false; } } @Override public Object pop() { // TODO Auto-generated method stub if(list.size()==0) { return null; } return list.remove(list.size()-1); } @Override public Object peek() { // TODO Auto-generated method stub return list.get(list.size()-1); } @Override public boolean empty() { // TODO Auto-generated method stub if(list.size()==0) { return true; }else { return false; } } @Override public int size() { // TODO Auto-generated method stub return list.size(); } }
/*Main類*/
package week111; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc=new Scanner(System.in); while(true) { String s=sc.next(); if(s.equals("Double")) { System.out.println("Double Test"); int count=sc.nextInt(); int pop_time=sc.nextInt(); ArrayListGeneralStack generalStack=new ArrayListGeneralStack(); for(int i=0;i<count;i++) { System.out.println("push:"+generalStack.push(sc.nextDouble())); } for(int j=0;j<pop_time;j++) { System.out.println("pop:"+generalStack.pop()); } System.out.println(generalStack.toString()); double sum=0; int size=generalStack.size(); for(int i=0;i<size;i++) { sum+=(double)generalStack.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 generalStack=new ArrayListGeneralStack(); for(int i=0;i<count;i++) { System.out.println("push:"+generalStack.push(sc.nextInt())); } for(int j=0;j<pop_time;j++) { System.out.println("pop:"+generalStack.pop()); } System.out.println(generalStack.toString()); int sum=0; int size=generalStack.size(); for(int i=0;i<size;i++) { sum+=(int)generalStack.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 generalStack = 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:"+generalStack.push(car)); } for (int i=0;i<pop_time;i++){ System.out.println("pop:"+generalStack.pop()); } System.out.println(generalStack.toString()); if (generalStack.size()>0){ int size=generalStack.size(); for (int i=0;i<size;i++){ Car car=(Car) generalStack.pop(); System.out.println(car.getName()); } } System.out.println("interface GeneralStack"); }else if (s.equals("quit")){ break; } } } }
運行結果:
實驗總結:
1 泛型的概念定義:
i.引入了參數化類型(Parameterized Type)的概念,改造了全部的Java集合,使之都實現泛型,容許程序在建立集合時就能夠指定集合元素的類型,好比List<String>就表名這是一個只能存放String類型的List;
ii. 泛型(Generic):就是指參數化類型,上面的List<String>就是參數化類型,所以就是泛型,而String就是該List<String>泛型的類型參數;
3) 泛型的好處:
i. 使集合能夠記住元素類型,即取出元素的時候無需進行強制類型轉化了,能夠直接用原類型的引用接收;
ii. 一旦指定了性參數那麼集合中元素的類型就肯定了,不能添加其餘類型的元素,不然會直接編譯保存,這就能夠避免了「不當心放入其餘類型元素」的可能;
2,通配符
1.)在實例化對象的時候,不肯定泛型參數的具體類型時,可使用通配符進行對象定義。
2)<? extends Object>表明上邊界限定通配符
3) <? super Object>表明下邊界限定通配符。
感覺:
經過本週的學習,掌握了泛型類的定義,以及泛型方法的聲明,還有泛型接口的定義,以及對泛型變量的限定。
在本週結對編程訓練時,仍是有很大問題,這樣的分工合做確實效率很大程度上增長,可是因爲語法掌握還不是很牢靠,仍舊須要大量適度練習,在以後的學習中,我會多練習程序去了解這些知識,爭取可以獨立完整的去編寫程序。