201871010114-李巖鬆《面向對象程序設計(java)》第十一週學習總結

項目html

內容java

這個做業屬於哪一個課程編程

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

這個做業的要求在哪裏安全

https://www.cnblogs.com/nwnu-daizh/p/11435127.htmlide

做業學習目標學習

  1. 理解泛型概念;
  2. 掌握泛型類的定義與使用;
  3. 掌握泛型方法的聲明與使用;
  4. 掌握泛型接口的定義與實現;
  5. 瞭解泛型程序設計,理解其用途。

第一部分:總結第八章關於泛型程序設計理論知測試

  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:

編輯、調試、運行教材3十一、312頁代碼,結合程序運行結果理解程序;

在泛型類定義及使用代碼處添加註釋;

掌握泛型類的定義及使用。

/**
 * @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:

編輯、調試運行教材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對象數組
      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:

用調試運行教材335 PairTest3,結合程序運行結果理解程序;

瞭解通配符類型的定義及用途。

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結對編程練習,將程序提交到PTA2019面向對象程序設計基礎知識測試題(2))

1編寫一個泛型接口GeneralStack,要求類中方法對任何引用類型數據都適用。GeneralStack接口中方法以下:

push(item);            //itemnull,則不入棧直接返回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方法。

4main方法要求

ü  輸入選項,有quit, Integer, Double, Car 4個選項。若是輸入quit,程序直接退出。不然,輸入整數mnm表明入棧個數,n表明出棧個數。而後聲明棧變量stack

ü  輸入Integer,打印Integer Test。創建能夠存放Integer類型的ArrayListGeneralStack。入棧m次,出棧n次。打印棧的toString方法。最後將棧中剩餘元素出棧並累加輸出。

ü  輸入Double ,打印Double Test。剩下的與輸入Integer同樣。

ü  輸入Car,打印Car Test。其餘操做與IntegerDouble基本同樣。只不過最後將棧中元素出棧,並將其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>表明下邊界限定通配符。

感覺:

經過本週的學習,掌握了泛型類的定義,以及泛型方法的聲明,還有泛型接口的定義,以及對泛型變量的限定。

在本週結對編程訓練時,仍是有很大問題,這樣的分工合做確實效率很大程度上增長,可是因爲語法掌握還不是很牢靠,仍舊須要大量適度練習,在以後的學習中,我會多練習程序去了解這些知識,爭取可以獨立完整的去編寫程序。

相關文章
相關標籤/搜索