java基础
前言
枚举是被限定了实例对象的类,泛型可以让我们写逻辑时不用事先确定数据类型。
1 枚举类型
1.1使用枚举类型设置常量
前面定义常量都是在类中或者接口中使用static和final关键字来进行定义,如:
interface seasonInterface {
//接口中定义的变量默认已经使用static和final修饰
//需要指定常量的类型,并且需要赋予初始值
int SPRING = 1, SUMMER = 2, AUTUMN = 3, WINTER = 4;
}
现在用枚举定义常量如下:
public enum SeasonEnum {
//不要求必须指定类型,初始值(可以指定),这些定义的变量自成一类
SPRING,
SUMMER,
AUTUMB,
WINTER,
}
使用枚举定义常量时,枚举自成一类,枚举对象唯一,没法“冒充“:
在接口或者类中定义的常量其本质不过是被final修饰的基础类型变量,那一些设定要接收这些常量作为参数的方法,其实可以不传入常量对象,而是传入其他同类型变量来”冒充“,而用枚举定义的常量是唯一的,不存在其他同类型变量可以冒充他。
1.2深入了解枚举类型
一个枚举类型可以看作一个类,继承于java.lang.Enum,一个枚举类的实例对象是有限且明确的(由定义的枚举常量决定),每个枚举常量有名称和值
枚举中可以定义方法,然后由枚举常量调用:
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday;
public boolean isWeekend() {
return this == Saturday || this == Sunday;
}
}
既然枚举中可以有方法,则也可以有构造方法:
enum Weekday {
//枚举开头定义的枚举常量决定了该枚举会有多少实例,并且在定义这些常量时还要决定这些枚举常量中各个成员属性的初始值
Monday("星期一"),
Tuesday("星期二"),
Wednesday("星期三"),
Thursday("星期四"),
Friday("星期五"),
Saturday("星期六"),
Sunday("星期日");
//上面的枚举常量定义时,为每个枚举常量传入了一个字符串初始值,则下面也要定义一个字符串成员变量在枚举中
//在定义完枚举常量后可以开始决定枚举中应该有些什么属性和方法
private String value;
private Weekday(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
因为继承自Enum类,所以也可以使用Enum类中的方法:
枚举类型名称.values():将所有枚举值以数组形式返回
枚举类型名称.valueof(String):获取传入字符串指定的枚举对象
枚举对象.compareTo(枚举对象):比较当前对象和传入对象的定义顺序
枚举对象.ordinal():放回当前对象在枚举中的索引值
同时枚举类也可以实现接口:
//定义Printable接口,并定义print方法
interface Printable {
void print();
}
//让枚举类实现Printable接口
enum Weekday implements Printable {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday;
//在枚举中重写接口中的print方法,这样所有枚举对象都实现了接口方法
@Override
public void print() {
System.out.println("Today is " + this.name());
}
}
下面演示一个枚举的使用案例:
定义角色枚举:
角色枚举有三种常量(即角色分三种职业):战士、法师、牧师
角色有名称、血量、攻击力、防御力四种属性
有构造方法初始化这四种属性
提供了get方法访问这些属性
public enum Role {
WARRIOR("战士", 100, 50, 30),
MAGE("法师", 80, 70, 20),
PRIEST("牧师", 60, 30, 50);
private String name; // 角色名称
private int hp; // 角色血量
private int attack; // 角色攻击力
private int defense; // 角色防御力
// 构造方法
private Role(String name, int hp, int attack, int defense) {
this.name = name;
this.hp = hp;
this.attack = attack;
this.defense = defense;
}
// getter方法
public String getName() {
return name;
}
public int getHp() {
return hp;
}
public int getAttack() {
return attack;
}
public int getDefense() {
return defense;
}
}
下面来使用角色枚举:
//创建玩家类
public class Player {
//创建枚举实例成员属性
private Role role; // 玩家角色
//构造方法初始化玩家属性
public Player(Role role) {
this.role = role;
}
//为玩家提供攻击方法,传入攻击对象作为参数
public void attack(Player target) {
//比较当前玩家攻击力和攻击对象防御力,计算伤害值
int damage = this.role.getAttack() - target.getRole().getDefense();
if (damage > 0) {
//在上一步计算的伤害值不为0的情况下,计算攻击对象扣减伤害后的新血量
int newHp = target.getRole().getHp() - damage;
//调用对象的setHp方法更新攻击对象血量
target.getRole().setHp(newHp);
}
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
下面进行测试:
public class GameTest {
public static void main(String[] args) {
//创建两名玩家
//玩家1传入Role.WARRIOR枚举常量,表示创建战士职业
Player player1 = new Player(Role.WARRIOR);
//玩家2传入Role.MAGE枚举常量.表示创建法师职业
Player player2 = new Player(Role.MAGE);
//打印两名玩家的职业选择信息
System.out.println("玩家1选择了" + player1.getRole().getName());
System.out.println("玩家2选择了" + player2.getRole().getName());
//玩家1选择攻击玩家2
player1.attack(player2);
//重新计算玩家2的血量
System.out.println("玩家2的血量为:" + player2.getRole().getHp());
}
}
上面的例子,把原本应该定义在玩家类中的职业名称、血量、防御力、攻击力属性和attack()方法定义在枚举类中
2.泛型
有些时候,某些方法是提供给多种不同类型的数据使用的,为了接收处理不同类型的参数,可以设置泛型
2.1回顾向上和向下转型
略
2.2定义泛型类
泛型定义语法如下:
类名<T>
其中T代表一种类型,在创建该类对象时需要根据实际情况指定,指定泛型的意义相当于:在未知真正需要处理的数据的类型时,使用泛型T来作为占位符执行方法逻辑
案例:
创建Book类并为其设置泛型
public class Book<T> {
private T bookinfo;
//使用泛型参与编写构造方法
public Book(T bookinfo) {
this.bookinfo = bookinfo;
}
//使用泛型参与编写get方法
public T getBookInfo() {
return bookInfo;
}
}
进行测试:
public static void main(String[] args){
//在实际要创建Book类的对象时,要根据传入数据类型,把原本的泛型位置指定填入明确的类型
//传入字符串数据,指定泛型为String
Book<String> bookName = new Book<String>("传入字符串");
//传入双精度浮点数据,指定泛型为Double
Book<Double> bookPrice= new Book<Double>(66.21);
//分别调用getBookInfo()方法
sout(bookName.getBookInfo());
sout(bookPrice.getBookInfo());
}
由案例看出,虽然在使用时传入的参数不同,但却可以使用同样的getBookInfo()方法,这就是泛型的作用
2.3泛型的常规用法
一次可以定义多个泛型:
class MyClass<T1,T2>{}
声明的泛型可以用于数组操作:
public class ArrayClass<T>{
private T[] array;
public T[] getArray(){
return array;
}
public void setArray(T[] array){
this.array=array;
}
pubic static void main(String[] args){
ArrayClass<Sting> demo=new ArrayClass<String>();
String value[]={"元素1","元素2","元素3"};
demo.setArray(value);
String array[] = demo.getArray();
for(int i=0;i<array.lenth;i++){
sout(array[i]);
}
}
}
2.4 泛型的高级用法
可以为泛型限定范围:
class 类名称<T extends anyclass>
anyclass是一个类型,上例写法要求在实现该类时候传入的泛型必须为anyclass类或者其子类
使用类型通配符:
类型通配符“?”可以替换原本的T,使用通配符后可以在不指定明确泛型的情况下先进行实例化,然后再指定泛型,如:
A<? extends List> = null;
a = new A<ArrayList>();
a= new A<LinkedList>();
继承带泛型的类:
例如:
class ExtendClass<T1>{}
class SubClass<T1,T2,T3> extend ExtendClass<T1>{}
在继承带泛型的类时,需要把父类的泛型也写上去,则子类泛型中的T1与父类的T1相同,如果继承语句写为:
extend ExtendClasss
省略了父类的泛型,则子类中的T1就与父类泛型无关,一般都要在继承时写明父类泛型.
`
总结
`本篇讲了java中的枚举和泛型。