201871010112-梁麗珍《面向對象程序設計(java)》第十一週學習總結

 

項目html

內容java

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

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

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

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

做業學習目標ide

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

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

什麼是泛型

什麼是泛型程序設計?
  ●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:

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

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

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

代碼:

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

 

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

2定義GeneralStackArrayListGeneralStack要求:

  類內使用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

輸入樣例

輸出樣例

 提交結果:

代碼:

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變量,而後再進行強行類型轉換的代碼具備更好的安全性和可讀性。經過此次對泛型類的學習,我基本掌握泛型程序設計的「泛型」到底指的是什麼,我但願在之後的學習過程中可以愈來愈好。

相關文章
相關標籤/搜索