一:继承的具体理解
就如同生活中的继承关系,儿子所具有的很多属性是继承其父亲,在java中这种基础关系为父类与子类,子类继承父类的某些属性与方法并且可以调用其中的属性和方法。
二:为何需要继承
先拿身边最常见的来举个例子,一个像英雄联盟类的moba类游戏,其中需要很多个英雄,所有英雄都会具有一些特定的属性,比如血量,蓝量,攻击力,普通攻击等等,不同的有技能和被动属性。试想我们如果我们假设10个英雄相互攻击,那我们需要在这十个英雄类的下面都要把所有属性特定方法代码全部写一遍,如果数量少还行,一旦数量增加,代码量就会成倍增加,这是一件很繁琐的事情,所以这时继承的作用就能展现出来了,此时我们建立一个父类叫做英雄类,把一些共有的特点写在里面,在创建子类的时候只需要调用其中的特性和方法就可以了。
三:继承的定义和使用
1:继承的定义及继承范围
关键字:extends
格式:子类 extends 父类 { }
子类继承父类的所以属性和方法,但不一定能够调用所有的属性和方法,要通过访问修饰符来确定。
java中一共有四种访问修饰符:
公共的 public
缺省的 (无)
私有的 private
受保护的 protected
在相同包下,除了父类中私有的方法和属性不可以被调用,其他三种都可以被子类调用。
在不同包下,父类中私有的和缺省的方法和属性不可以被调用,在子类的{ }内可以调用公共以及受保护的修饰的属性或方法。而在创建的子类对象中则只能调用公共的方法。
2:方法重写
回到我们前面的例子,如果很多个英雄对战,他们具有相同的特性和方法,然而他们也具有不同的方法和特点,比如有些英雄是没有蓝量的,他们的技能各不相同,这时我们就需要对方法进行重写,调整相应的变化。
条件:必须有继承关系
格式:访问修饰符 返回值类型 方法名 (参数类型 参数名) { }
重写之后,子类对象会优先调用子类重写的方法
1:倘若需要调用父类中的方法则可以加入super.方法来调用父类中的方法。
2:如果父类方法中的代码只有部分有用或者需要修改,也可以不写super.方法();将父类方法中的代码都复制过来进行修改和增加。
3:如果父类方法中的代码全部有用,并且子类需要在这个基础上扩展代码,使用super.方法(),然后增加扩展子类的代码。
3:自然转型
我们之前应该有听说过强制转型,既:(强制转换类型) 数据,
而怎么理解自然转型呢?
我们可以这样理解,我们可以把人这个大类分为学生和上班族等不同类别,学生中我们又可以分为大学生,中学生,小学生。
一个大学生他可以对别人说他是大学生,但他也轻而易举的可以转换为说我是一个学生,或者再往上说我是一个人,都是没有问题的,所以这就叫自然转型。
条件:两个类型之间具有继承关系。
我们还是拿英雄对战来举例子,每个英雄都会普通攻击,但在我们假设的相互对战中,每个人的攻击目标是不同的,倘若不用自然转型则需要把打每一个人的普通攻击代码都写一遍,而如果用了则只需调用并且转换参数即可攻击别的英雄。
若Hero是定义的父类,其下有一个普通攻击的方法 ack(参数类型 参数名);
如果我们把其参数类型和参数名写成 ack(Hero hero);
子类对象调用时只需将hero这个形参名改成任意的英雄,即可对其发出普通攻击。
4:实例讲解
下面我们来看这个实例代码。
这个是我们定义的父类
package day1227;
//父类
public class Hero {
//属性
public String name;
public int blood;
public int strength;
public int ap;
//方法
//普通攻击,所有英雄都具有
public void ack(Hero hero){
hero.blood=hero.blood-strength;
System.out.println(hero.name+"受到了"+strength+"伤害"+","+hero.name+"剩余血量为"+hero.blood);
}
}
第一个子类英雄,卡牌
package day1227;
//对父类的继承 extends Hero
public class Kapai extends Hero {
//q技能的描写,自然转型到父类,这样可以用它打任意子类英雄
public void Qskill(Hero hero){
hero.blood=(int) (hero.blood-(ap*0.2+this.strength));
System.out.println(hero.name+"受到了来自"+this.name+"Q技能伤害,剩余血量为"+hero.blood);
}
}
第二个子类英雄,天使
package day1227;
public class Tianshi extends Hero{
public void Qskill(Hero hero){
hero.blood=(int) (hero.blood-(ap*0.2+this.strength*0.5+this.strength));
System.out.println(hero.name+"受到了来自"+this.name+"Q技能伤害,剩余血量为"+hero.blood);
}
}
第三个子类英雄,亚索
package day1227;
public class Yasuo extends Hero{
public void Qskill(Hero hero){
hero.blood=(int) (hero.blood-(strength*0.8+this.strength));
System.out.println(hero.name+"受到了来自"+this.name+"Q技能伤害,剩余血量为"+hero.blood);
}
}
主函数
package day1227;
public class Mainer {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建英雄对象
Kapai kapai=new Kapai();
Yasuo yasuo=new Yasuo();
Tianshi tianshi=new Tianshi();
//赋予属性
kapai.blood=160;
kapai.name="卡牌";
kapai.strength=6;
kapai.ap=20;
yasuo.blood=200;
yasuo.name="亚索";
yasuo.strength=15;
yasuo.ap=0;
tianshi.blood=140;
tianshi.name="天使";
tianshi.strength=8;
tianshi.ap=15;
int overnum=0;
int skillnum1=0,skillnum2=0,skillnum3=0;
//大循环进行轮回攻击
while(true){
if(overnum==2)break;
if(tianshi.blood>=0){
kapai.ack(tianshi);
skillnum1++;
if(tianshi.blood>=0){
if(skillnum1%2==0)
kapai.Qskill(tianshi);
}
if(tianshi.blood<=0){
System.out.println(tianshi.name+"死亡");
overnum++;
}
}
if(overnum==2)break;
if(yasuo.blood>=0){
tianshi.ack(yasuo);
skillnum2++;
if(yasuo.blood>=0){
if(skillnum2%2==0)
tianshi.Qskill(yasuo);
}
if(yasuo.blood<=0){
System.out.println(yasuo.name+"死亡");
overnum++;
}
}
if(overnum==2)break;
if(kapai.blood>=0){
yasuo.ack(kapai);
skillnum3++;
if(kapai.blood>=0){
if(skillnum3%2==0)
yasuo.Qskill(kapai);
}
if(kapai.blood<=0){
System.out.println(kapai.name+"死亡");
overnum++;
}
}
// 死亡英雄大于等于而时结束战斗宣布胜利英雄
}
if(overnum>=2){
if(tianshi.blood>=0){
System.out.println(tianshi.name+"取得胜利");
}
else
if(kapai.blood>=0){
System.out.println(kapai.name+"取得胜利");
}
else
if(yasuo.blood>=0){
System.out.println(yasuo.name+"取得胜利");
}
}
}
}
五:继承的好处
总结出来主要有三点
提高代码的重用性
提升程序的结构性
让程序可以更好的扩展