2020/4/7學習筆記day34

java-day34

泛型的回顧

泛型參數聲明的位置:

在類上面聲明:泛型類

在接口上面聲明:泛型接口

在方法上面聲明:泛型方法

使用<>就可以聲明泛型參數:

  public class Point<T>{}

  public interface Action<T>{}

  public <T> void test(T t);

確定泛型形參的具體類型:

public class Point<T>{}
main:
    Point<Integer> p;

public interface Action<T>{}
main:
	Action<String> a;

public <T> void test(T t);
main:
	t.test(1);
	t.test("hello");

public <T> T test();
main:
	int    a = t.test();
	String s = t.test();

public <T> T test(T t);
main:
	int a    = t.test(1);
	String s = t.test("hello");

泛型的作用:

泛型是對代碼中的類型進行參數化。本來在代碼中寫死的類型,可以通過泛型變的更加靈活,將來在使用代碼的時候,通過傳參數的方式,再來確定代碼中到底使用的是什麼類型。

 public class Point{
    private int x;
    private int y;
  }

  main:
    Point p = new Point();

  

  public class Point<T>{
    private T x;
    private T y;
  }
  main:
    Point<Integer> p = new Point<>();
    Point<String> p  = new Point<>();

泛型雖然可以讓之前代碼中寫死的類型變化起來,但是泛型也增加了類型的複雜度:

  public class Point{
    private int x;
    private int y;
  }

這個類無論如何使用,Point只有一種類型,就是Point

 public class Point<T>{
    private T x;
    private T y;
  }

無法使用多態

這個帶泛型的類型,通過傳不同的泛型參數的類型,在編譯期間會產生很多不同的Point類型
例如:Point Point Point 等等,並且這些類型之間都是不兼容的,這就意味着無法使用多態。

//編譯報錯
Point<Object> p = new Point<String>();

?號通配符

爲了使用多態,那麼必須找出一個可以和其他泛型類型都兼容的類型,那麼這時候可以使用?號通配符

//編譯通過
Point<?> p = new Point<任意類型>();

但是使用通配符之後,也會產生一些限制,由於使用了?號通配符,那麼編譯器就無法確定這個泛型的類型到底是什麼,如果這時候我們數去操作這個參數數據的時候,編譯器就會報錯了,因爲編譯器無法確定這個參數數據的類型和?號通配符將來代表的類型是否一致。但是如果調用的方法沒有參數,或者參數的類型並不是用泛型類型所表示的,那麼編譯器就不管了。

public class Point<T>{
    private T x;
    public void setX(T x){
        this.x = x;
    }

    public String toString(){
        return x;
    }

    public void say(String name){
        //...
    }
}

Point<?> p = new Point<String>();
p.setX(1);

通配符?號結合extends和super

通配符?號表示的類型範圍太大,可以結合extends和super來進一步限制通配符所表示的類型方法:

//表示很大的一個類型方法
List<?> list = new ArrayList<任意類型>();

//限制通配符可以表示的類型範圍(上限)
List<? extends Number> list = new ArrayList<Number類型>();
List<? extends Number> list = new ArrayList<Number的子類型>();

//限制通配符可以表示的類型範圍(下限)
List<? super Number> list = new ArrayList<Number類型>();
List<? super Number> list = new ArrayList<Number的父類型>();

泛型擦除:

泛型只能在編譯的時候起作用,編譯後代碼中的泛型信息就被擦除掉了。List List List 等等這些類型在編譯的時候是不兼容的類型,但是編譯之後,它們都是同一種類型,因爲編譯之後泛型的類型在代碼中會被擦除掉。

代碼中和泛型相關的有倆個地方:
1.類上面、接口上面、方法上面聲明的泛型信息
2.在代碼中,使用泛型類、泛型接口、泛型方法時,所傳的實際的泛型參數信息。

編譯後泛型信息的擦除,指的是第二種情況,也就是實際在使用泛型的時候所傳的泛型類型參數會被擦除。

編譯前的源碼

package com.zzb.day34;

public class Point<T> {
	
	

	private T x;
	public void setX(T x){
		this.x = x;
	}
	public T getX(){
		return x;
	}

	public String toString(){
		return "x="+x;
	}
} 

class PointTest{
	public static void main(String[] args){
		Point<Integer> p = new Point<>();
		p.setX(1);
		System.out.println(p);
		
	}
}

反編譯後的源碼

在這裏插入圖片描述
在這裏插入圖片描述

枚舉enum

1、簡單的使用一下

public enum Gender{
	MALE,FEMALE;
}

Gender就是一個枚舉類型,美劇類型也是一種類(class),是一種特殊的類,枚舉類型中所列出的元素,就是枚舉類型的對象,默認用public static final修飾的,所以這些對象的名字全字母大寫。

2、枚舉的意義

java中的類很多都是可以創建無數對象(從語法形式上來講),但是從實際意義上只需要個別對象就可以了,如果創建多個對象就會佔用多餘內存空間也沒有什麼實際意義。枚舉類型的對象是有限的個數甚至是固定的對象個數。

如果java中,有一種類,它的對象個數和名字都是固定不變的,那麼就可以使用枚舉類表示。
例如Gender類型,表示性別:一個MALE,另一個FEMALE。

3、枚舉類型中,可以提前固定該類型的個數和名字

public enum Gender{
	MALE,FEMALE;
}

除此之外,我們不能再創建這個類型的其他新的對象。(構造器是私有的)

public class GenderTest {
	
	public static void main(String[] args){
		Gender g;

		g = Gender.MALE;
		System.out.println(g);
		
		g = Gender.FEMALE;
		System.out.println(g);
	}
} 

在這裏插入圖片描述

枚舉類型和類之間的關係

使用javap命令把Gender.class文件進行反向解析:

在這裏插入圖片描述
在這裏插入圖片描述

得到結論:

1、枚舉類型是一個類,同時還是一個final修飾的類

2、枚舉類型都會默認繼承java.lang.Enum,並且還是一個泛型類

3、枚舉中所定義的對象其實就是類裏面的公共的靜態常量(public static final),並且常量在靜態代碼塊中做初始化。

4、枚舉類型中還有一個默認的私有構造器

5、枚舉類型中還有給默認添加進來的方法:

values()方法:返回枚舉對象的所有對象,返回類型是數組

valueOf(String str)方法:通過一個字符串可以返回枚舉對象,這個字符串參數就是枚舉對象的名字。

6、從父類繼承過來的方法:

String name() : 返回這個枚舉對象的名字

int ordinal() :返回這個枚舉對象的編號,默認從0開始

在這裏插入圖片描述

獲得枚舉類型的指定名字的對象(3種)

方式一:

//只能獲取到Gender中的指定對象MALE
//因爲沒有可以變化的地方(字符串)
Gender g = Gender.MALE;

方式二:

//能獲取到Gender中的任意-一個對象
//因爲name是字符串類型的變量,可以任意變化
String name = "MALE";
Gender g = Gender.valueOf("MALE");

方式三:

//通過字符串確定是哪一個枚舉類型
Class c = class.forName("com.zzb.day34.Gender");
//通過字符串確定是哪一個名字的枚舉對象
String name = "FEMALE";
//可以通過改變字符串,獲取到Java中任意一個指定名字的枚舉對象
Enum g = Enum.valueOf(Gender.class,"FEMALE");

枚舉類型中定義方法

public enum Gender {
    MALE,FEMALE;

    public void test(){
        System.out.println("Gender test...");
    }

    public static void print(String name){
        System.out.println("hello "+name);
    }
} 
main:
Gender g = Gender.MALE;
g.test();
Gender.print("zzb");

在這裏插入圖片描述

枚舉類型中定義自己的屬性

public enum Gender {
    MALE,FEMALE;

    private String name;

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
} 

main:
Gender g = Gender.MALE;
g.setName("男生");
System.out.println(g.getName());

在這裏插入圖片描述

枚舉類型中定義自己的構造器

public enum Gender {
	MALE,FEMALE;

	private String name;

	public void setName(String name){
		this.name = name;
	}

	public String getName(){
		return name;
	}
	
	private Gender(){}
    
	private Gender(String name){
		this.name = name;
	}
} 

枚舉中的構造器只能用private修飾,不寫也是默認爲private,同時可以定義多個不同參數列表的構造器。這些構造器在枚舉類型的外部是不能使用的,只能在枚舉類型中列出對象的時候,去指定哪個構造器來創建這個對象。

枚舉類型中構造器的調用

1、調用無參構造器
public enum Gender {
	MALE(),FEMALE();
	private Gender(){
		System.out.println("無參構造器被調用");	
	}
} 
main:
Gender g = Gender.MALE;

在這裏插入圖片描述
注意,這裏的枚舉類型中倆個對象MALE、FEMALE都默認是調用了無參構造器創建而成,我們可以指明調用了無參構造器

2、調用有參構造器
public enum Gender {
	MALE("男生"),FEMALE("女生");

	private String name;

	public void setName(String name){
		this.name = name;
	}

	public String getName(){
		return name;
	}
	
	private Gender(){
		System.out.println("無參構造器被調用");
		
	}
	private Gender(String name){
		this.name = name;
		System.out.println("有參構造器被調用,參數name:"+name);
	}
} 

main:
Gender g = Gender.MALE;   

在這裏插入圖片描述
注意,枚舉類型的對象,是在這個枚舉類型進行類加載的時候,完成的對象初始化工作,因爲這些對象都是public static final修飾的。枚舉中有一個靜態代碼塊,在這裏面做初始化工作,在裏面創建構造器。

枚舉類類型中定義抽象方法

public enum Gender {
    MALE(){
        public void test(){
            System.out.println("男生測試");
        }
    },
    FEMALE(){
        public void test(){
            System.out.println("女生測試");
        }
    };
    public abstract void test();
} 

main:
Gender g = null;

g = Gender.MALE;
g.test();

g = Gender.FEMALE;
g.test();

在這裏插入圖片描述

注意,在枚舉類型中定義的抽象方法,需要在聲明枚舉類型對象的時候進行實現。

枚舉類型實現接口

枚舉類型有默認的父類型java.lang.Enum類,所以就不能給一個枚舉類型指定其他父類型了,但是可以讓這個枚舉類型去實現其他接口。

//在枚舉類型中,對接口中的方法進行統--實現
public enum Gender implements Action {
    MALE,FEMALE;
    public void doSomething(){
        System.out.println("接口中抽象方法的統一實現");
    }
} 

interface Action{
    void doSomething();
}

main:
Gender g = null;
g = Gender.MALE;
g.doSomething();

g = Gender.FEMALE;
g.doSomething();    

在這裏插入圖片描述

//在每個對象中,分別對這個接口中的抽象方法進行實現
public enum Gender implements Action {
	MALE(){
		public void doSomething(){
			System.out.println("MALE方法的單獨實現");
		}
	},
	FEMALE(){
		public void doSomething(){
			System.out.println("FEMALE方法的單獨實現");
		}
	};	
} 

interface Action{
	void doSomething();
}

main:
Gender g = null;
g = Gender.MALE;
g.doSomething();

g = Gender.FEMALE;
g.doSomething();

在這裏插入圖片描述

枚舉類型就是提前在類中定義好了對象的名稱和個數的java類

枚舉例子

public class EnumTest {
	
	public static void main(String[] args){
		
		int mode = (int)(Math.random()*4);//0 1 2 3

		EnumTest x = new EnumTest();

		x.start(mode);
		
	}
	
	private enum Mode{
		MODE_0("模式0","點火"),
		MODE_1("模式1","一檔"),
		MODE_2("模式2","二檔"),
		MODE_3("模式3","三檔");
		private String name;//名字
		private String msg;//信息

		private Mode(String name,String msg){
			this.name = name;
			this.msg = msg;
		}
		public String toString(){
			return name + ":" + msg;
		}
	}
	public void start(int mode){
		Mode m = Mode.valueOf("MODE_"+mode);
		System.out.println(m);
	}
} 

在這裏插入圖片描述

發紙牌案例

Card.java
package com.zzb.day34;

import java.util.*;
public class Card {
	
	public enum Rank{
	   DEUCE,THREE,FOUR,FIVE,
       SIX,SEVEN,EIGHT,NINE,TEN,
	   JACK,QUEEN,KING,ACE;
	}

	public enum Suit{
		CLUBS,DIAMONDS,HEARTS,SPADES;
	}
	private final Rank rank;
	private final Suit suit;
    
	private static final List<Card> protoDect = new ArrayList<Card>();

	static{
		for(Suit suit:Suit.values()){
			for(Rank rank:Rank.values()){
				protoDect.add(new Card(rank,suit));
			}
		}
	}

	public Card(Rank rank,Suit suit){
		this.rank = rank;
		this.suit = suit;
	}

	public Rank rank(){
		return rank;
	}

	public Suit suit(){
		return suit;
	}

	public String toString(){
		return rank + " of " + suit;
	}
	
	public static List<Card> newDeck(){
		//把原始的牌複製一份作爲一副新牌再返回
		List<Card> list = new ArrayList<>(protoDect);
		return list;
	}
} 

Deal.java
package com.zzb.day34;

import java.util.*;

public class Deal {
	
	public static void main(String[] args){
		
		int numHands = 3;//三個人

		int cardsPerHand = 5;//一人五張牌
		
		List<Card> list = Card.newDeck();

		

		//洗牌
		Collections.shuffle(list);
		for(int i=0;i<numHands;i++){
			List<Card> hand = deal(list,cardsPerHand);
			System.out.println(hand);
		}
		//System.out.println(list);
		System.out.println("發牌結束,還剩:"+list.size()+"張沒發");
		
	}

	private static List<Card> deal(List<Card> list,int n){
		int size = list.size();
		List<Card> handView = list.subList(size-n,size);

		List<Card> hand = new ArrayList<>(handView);
		handView.clear();
		return hand;
	}
} 

在這裏插入圖片描述

交通燈案例

public enum TrafficLight implements java.io.Serializable {

    RED(30){
        public TrafficLight next(){
            return GREEN;
        }	
    },
    YELLOW(5){
        public TrafficLight next(){
            return RED;
        }	
    },
    GREEN(40){
        public TrafficLight next(){
            return YELLOW;
        }	
    };

    private final int duration;
    private TrafficLight(int duration){
        this.duration = duration;//時間間隔
    }

    public int getDuration(){
        return duration;
    }

    public abstract TrafficLight next();

    public static void main(String[] args){
        for(TrafficLight light : TrafficLight.values()){
            System.out.println("當前的燈爲:"+light+"燈");
            System.out.println("\t持續時間爲"+light.getDuration()+"秒,
                               等一下是:"+light.next().name()+"燈");
            System.out.println();
        }
    }
} 

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章