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();
        }
    }
} 

在这里插入图片描述

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