2013.07.11
上课内容:类的继承
说到类的继承,我们先来回顾一下类,类是具有一些相同或相似的物体的集合,是由属性和方法组成。
类的继承就是在我们先定义的类的基础上,定义一个类去继承原先类的属性和方法,并且可以新生成、改变原方法。
这样,我们就说原先的类为父类,新定义的类为主类。
继承的关键词:extends
用法:
public class 类名 extends 类名{
}
这里要注意一点,java里的类为单继承,即一个子类只允许有一个父类,但是一个父类可以有多个子类,每个子类可以用不同的方式重写父类的方法。
既然子类可以继承父类,我们下面来讨论一下子类可以继承到父类什么:
1、属性
2、方法
子类可以继承父类的所有属性和方法,但是要注意子类不能全部调用父类的属性和方法。
我们先来一个一个分析下访问修饰符的范围:
public 在类所在的java project内都可以调用
protected 在本类和其在同一个包下以及在不同包下的子类中都可以调用
默认(不加修饰符)在本包下可以调用
private 只能在本类中调用
明白了这些,我们就可以明白为什么子类不能全部调用父类的属性和方法,但是在重写时可以扩大父类的访问修饰符。
这样我们就要讲到方法的重写,这也是继承中很关键的以部分。
所谓类的重写,与方法重载类似,我们在父类中定义了一个方法,在子类中不仅可以继承其方法,也可以改变其方法
但是要注意在方法重写时,返回值数据类型,方法名,参数的个数,参数的类型,参数的顺序都要完全致。
还有就是要注意我们上面提到的重写时可以扩大访问修饰符而不能减小,否则会报错。
了解了方法重写,那么什么情况下才需要方法重写呢?
方法重写是在我们父类的方法不能满足我们现在的需求时,需要我们在父类的方法中进行一定的补充,这时我们就要用到方法的重写。
比如我们定义一个Student类,创建一个play方法玩的是LOL,但是我们想玩其他的游戏呢,就要新建一个子类继承父类,然后重载play方法,这样就ok啦!
要是我们想在子类的play方法中调用父类的play方法,就可以使用super.play();
知道了方法的重写,下面我们来看类型的转换,类型的转换前提是要求必须要有继承关系,而且一般是由小转大。
我们在第一节课中知道,当定义两个不同的数据类型时,小的可以向大的转换叫做向上转型,而大的则要强制向小的转化叫做向下转型。
举个例子:
byte a;
int b = a;
short c = (short)b;
类中的类型转换也是如此。
类型的转换的一般格式是
向上转型:父类名 对象名 = new 子类名();
向下转型:子类名 对象名 = (子类名)对象;
但是要注意一点,就是转换后的对象无法调用子类的方法,在调用父类的方法时若在子类的方法中重写,则会调用子类对应的方法。
至于无法调用子类方法的原因,主要是因为eclipse编译的机制问题,对象是属于父类,软件会在父类中找你调用的方法,一旦找不到就会报错。
知道了类的自动转型,那么它究竟有什么好处呢?我们举个例子:
一个大学英语老师可以教大学生、高中生、初中生、小学生英语,
那么对这个大学英语老师我们就要创建4个不同的方法,这显然不是我们希望看到的。
所以我们只需要创建一个方法为大学英语老师教学生。
这样就可以让大学生、高中生、初中生、小学生继承学生类,然后定义一个老师教学生的方法就可以了。
练习:回合制游戏:德玛(致命打击 勇气 审判 德玛西亚正义(技能名和攻击力))+卡牌(万能牌 选牌 卡牌骗术 命运(技能名和攻击力))要去战斗,直到一方的血量为0的时候结束战斗,输出谁胜利了。
德玛和德玛战斗
卡牌和卡牌战斗
大致思路是这样的:建立一个英雄类,拥有名字,技能,防御,血量的属性,拥有设置、获取各个属性的方法,还有的就是要使用的攻击方法。
然后分别定义Garen和Twisted两个类来继承英雄类,并且定义自己的攻击防御和血量,并初始化姓名。
定义一个技能类,技能拥有名字和攻击力两个属性,拥有设置、获取各个属性的方法。
下面我们就可以在主函数中调用我们定义的方法来实现回合制战斗啦~
附代码如下:
package cn.tth.pratice0711;
/**
* 总控制台
* @author TTH
*
*/
public class LOL {
public static void main(String[] args) {
//初始化两个人的技能对象
Skill[] gskill={new Skill("普通攻击",56),new Skill("致命一击",30),new Skill("勇气",40),
new Skill("审判",60),new Skill("德玛西亚正义",175) };
Skill[] tskill = {new Skill("普通攻击",46),new Skill("万能牌",60),new Skill("选牌",40),
new Skill("卡牌骗术",55),new Skill("命运",200)};
//初始化两个战斗对象
Garen garen = new Garen("Garen",gskill);
Twisted twisted = new Twisted("Tweisted",tskill);
//输出盖伦对卡牌
System.out.println(garen.getName()+" vs "+twisted.getName());
//进入回合制的循环
while(true){
//盖伦攻击卡牌
garen.Attack(twisted);
//如果卡牌的血量小于等于0,结束回合制游戏
if(twisted.getHp()<=0){
System.out.println(garen.getName()+"win!");
break;
}
//卡牌攻击盖伦
twisted.Attack(garen);
//如果盖伦的血量小于等于0,结束回合制游戏
if(garen.getHp()<=0){
System.out.println(twisted.getName()+"win!");
break;
}
}
//初始化盖伦对象
Heros garen1 = new Garen("Blue Garen",gskill);
Heros garen2 = new Garen("Purple Garen",gskill);
//输出蓝色方盖伦对紫色方盖伦
System.out.println(garen1.getName()+" vs "+garen2.getName());
//进入回合制的循环
while(true){
//蓝色方盖伦攻击紫色方盖伦
garen1.Attack(garen2);
//如果紫色方盖伦的血量小于等于0,结束回合制游戏
if(garen2.getHp()<=0){
System.out.println(garen1.getName()+"win!");
break;
}
//紫色方盖伦攻击蓝色方盖伦
garen2.Attack(garen1);
//如果蓝色方盖伦的血量小于等于0,结束回合制游戏
if(garen1.getHp()<=0){
System.out.println(garen2.getName()+"win!");
break;
}
}
//初始化卡牌对象
Heros twisted1 = new Twisted("Blue Twisted",tskill);
Heros twisted2 = new Twisted("Purple Twisted",gskill);
//输出蓝色卡牌伦对紫色方卡牌
System.out.println(twisted1.getName()+" vs "+twisted2.getName());
//进入回合制的循环
while(true){
//蓝色方卡牌攻击紫色方卡牌
twisted1.Attack(twisted2);
//如果紫色方卡牌的血量小于等于0,结束回合制游戏
if(twisted2.getHp()<=0){
System.out.println(twisted1.getName()+"win!");
break;
}
//紫色方卡牌攻击蓝色方卡牌
twisted2.Attack(twisted1);
if(twisted1.getHp()<=0){
System.out.println(twisted2.getName()+"win!");
break;
}
}
}
}
package cn.tth.pratice0711;
import java.util.Random;
/**
* 英雄类
* @author TTH
*
*/
public class Heros {
//定义姓名属性
private String name = new String();
//定义攻击属性
private int atk;
//定义防御属性
private double def;
//定义血量属性
private double hp;
//定义技能数组
private Skill[] skill;
//定义一个随机数
private Random ran = new Random();
//设置姓名的方法
public void setName(String name){
this.name=name;
}
//调用姓名的方法
public String getName(){
return name;
}
//设置攻击的方法
public int getAtk() {
return atk;
}
//调用攻击的方法
public void setAtk(int atk) {
this.atk = atk;
}
//设置防御的方法
public double getDef() {
return def;
}
//调用防御的方法
public void setDef(double def) {
this.def = def;
}
//设置血量的方法
public double getHp() {
return hp;
}
//调用血量的方法
public void setHp(double hp) {
this.hp = hp;
}
//设置血量
public void setSkill(Skill[] skill){
this.skill = skill;
}
//得到血量
public Skill[] getSkill(){
return skill;
}
//设置攻击方法
public void Attack(Heros hero){
//得到一个长度跟skill相同的随机数
int r=ran.nextInt(skill.length);
//设置攻击
hero.setHp(hero.getHp()-skill[r].getAtk()*(1-hero.getDef()/100.0));
//如果血量小于零,设置为0
if(hero.getHp()<=0){
hero.setHp(0);
}
//输出技能攻击后的血量
System.out.println(name+"释放技能"+skill[r].getName()+","+hero.getName()+"血量为"+(int)hero.getHp());
}
}
package cn.tth.pratice0711;
/**
* 技能类
* @author TTH
*
*/
public class Skill {
//技能名
private String name;
//技能攻击
private int atk;
//skill构造函数
public Skill (String name,int atk){
this.name = name;
this.atk = atk;
}
//获取技能名
public String getName() {
return name;
}
//设置技能名
public void setName(String name) {
this.name = name;
}
//获取技能攻击力
public int getAtk() {
return atk;
}
//设置技能攻击力
public void setAtk(int atk) {
this.atk = atk;
}
}
package cn.tth.pratice0711;
/**
* 盖伦类,继承英雄类
* @author TTH
*
*/
public class Garen extends Heros {
/**
* 构造函数
* @param name英雄名字
* @param skill英雄技能数组
*/
public Garen(String name,Skill[] skill){
this.setDef(19);
this.setHp(455);
this.setName(name);
this.setSkill(skill);
}
}
package cn.tth.pratice0711;
/**
* 崔斯特类,继承英雄类
* @author TTH
*
*/
public class Twisted extends Heros {
/**
* 构造函数
* @param name英雄名字
* @param skill英雄技能数组
*/
public Twisted(String name,Skill[] skill){
this.setDef(11.25);
this.setHp(384);
this.setName(name);
this.setSkill(skill);
}
}