Java-类与类之间的关系
继承
继承的概述
继承是面向对象三大特征中的核心特征,是实现代码复用的重要方式,是类与类之间的一种关系。父类抽取了共性的内容,子类可以在父类的基础上进行拓展新的属性和行为。
注:所有的类都直接或者间接Object
继承的代码格式
继承使用extends关键字
格式
class 子类 extends 父类{
}
//动物类
public class Animal {
private String name;
private int age;
public Animal(String name, int age) { this.name = name;this.age = age; }
public Animal() { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public void eat(){
System.out.println(this.getName()+"吃东西");
}
}
//老虎类,继承了动物类
public class Tiger extends Animal {
public Tiger(String name, int age) { super(name, age);}
public Tiger() {}
public void hunting(){ System.out.println(this.getName()+"在捕猎"); }
}
//测试类
public class Test {
public static void main(String[] args) {
Tiger t = new Tiger("东北虎",1);
t.hunting();
t.eat();
}
}
从上类案例中可以看出,发生了继承关系之后,子类汇会继承父类中除构造方法和静态方法,静态变量之外的东西,并且可以调用非private修饰的内容和定义新的内容。
子类访问父类成员的方法
在父类中,被private修饰的成员需要提供公开的get和set放法,子类可以通过继承来的这些方法对属性进行访问。
注:属性是可以被继承的,继承发生后,子类对继承来的属性拥有自己的内存空间。
继承的特点
1、Java只支持单继承
2、Java支持多层继承
3、父类定义了继承树中共性内容,子类定义了该类个性内容。
4、在结合多态后,能使用父类时尽量使用父类,提高程序扩展性。
方法重写与继承内存图解
方法重写的概念与格式
子类继承父类后,可以继承父类中非private修饰的方法,若子类发现父类提供的某一个方法不够用的时候,可以自己通过重写来实现属于自己的逻辑,这样,当子类对象再次调用方法的时候,调用的就是重写后的方法。
格式:
定义一个与父类方法声明完全相同的方法,方法体重写
子类在重写父类中的方法时,需要在方法的上一行加上@Override注解,表明这是重写父类中的方法。
发生继承关系后创建对象的内存图:
方法重写注意事项
1、方法重写发生在继承关系中
2、重写的方法,方法名要相同
3、参数列表要相同
4、返回值类型:基本数据类型要一致,引用数据类型:子类<=父类
5、权限:子类>=父类
6、抛出异常:子类<=父类
继承后创建对象构造方法的调用顺序
public class Animal {
private String name;
private int age;
public Animal(String name, int age) { this.name = name;this.age = age; }
public Animal() {
System.out.println("这是父类的无惨构造方法");
}
}
public class Tiger extends Animal {
public Tiger(String name, int age) { super(name, age);}
public Tiger() {
System.out.println("这是子类的无参构造方法");
}
}
public class Test {
public static void main(String[] args) {
Tiger t = new Tiger();
}
}
/**
* 这是父类的无惨构造方法
* 这是子类的无参构造方法
*/
通过上述案例可以看出,发生继承后,当创建子类对象的时候,系统均会先初始化父类的内容,在初始化子类本身。目的在于子类对象中包含了其对应的父类存储空间,便可以包含了其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。
代码体现在子类的构造方法调用时,一定先调用父类的构造方法。
this与super
调用普通成员:
this.成员变量 可以访问本类对象的成员变量
super.成员变量 可以访问父类的成员变量
this.成员方法() 可以访问本类对象的成员方法
super.成员方法() 可以访问父类的成员方法
子类方法中
访问子类自身的成员用this.
访问父类的成员super.
就近原则:
局部 > 本类成员 > 父类成员
super 关键字
- 1.调用执行父类的成员,但是super并不是父类的对象
- 2.默认提供super(),调用执行父类中的无参构造方法
- super(name, age); 调用执行父类中的有参构造方法
- super()默认存在在子类构造方法的第一行
- 3.super调用父类的成员方法,调用父类的成员变量
this
- 1.当前正在创建的对象,当前正在使用的对象
- 2.this() 调用本类中无参的构造方法
- this(name,age) 调用本类中有参的构造方法 ,但是两者不能互相调用
- 3.this调用本类的成员方法,调用本类的成员变量
关联和依赖关系
继承:is-a
关联:has-a
依赖:use-a
关联关系的概述
当在类A中需要使用到类B的某些方法时,可以将类B作为类A的成员,从而产生关联
/**
* @ClassName: Pet
* @Description: Pet宠物类
*
* 宠物姓名,宠物颜色,宠物种类三个成员变量
*/
public class Pet {
/**
* @Fields name : 宠物姓名
*/
private String name;
/**
* @Fields color : 宠物颜色
*/
private String color;
/**
* @Fields kind : 宠物种类
*/
private String kind;
/**
* @Title: Pet
*/
public Pet() {
}
/**
* @Title: Pet
* @param name
* @param color
* @param kind
*/
public Pet(String name, String color, String kind) {
this.name = name;
this.color = color;
this.kind = kind;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the color
*/
public String getColor() {
return color;
}
/**
* @param color the color to set
*/
public void setColor(String color) {
this.color = color;
}
/**
* @return the kind
*/
public String getKind() {
return kind;
}
/**
* @param kind the kind to set
*/
public void setKind(String kind) {
this.kind = kind;
}
}
/**
* @ClassName: Person
* @Description: Person类
*
* 姓名,年龄,宠物三个成员变量
* 有showInfo(显示信息)的方法
*
* 当Pet作为Person的成员变量时,两个数据类型的关系为关联
*/
public class Person {
/**
* @Fields name : 姓名
*/
private String name;
/**
* @Fields age : 年龄
*/
private int age;
/**
* @Fields pet : 宠物
*/
private Pet pet;
/**
* @Title: Person
*/
public Person() {
}
/**
* @Title: Person
* @param name
* @param age
* @param pet
*/
public Person(String name, int age, Pet pet) {
this.name = name;
this.age = age;
this.pet = pet;
}
/**
* @Title: showInfo
* @Description: 显示个人信息
*/
public void showInfo() {
System.out.println("我的名字是:" + this.name + ",我的年龄是:" + this.age);
System.out.println("我的宠物是"+pet.getColor()+"色的"+pet.getKind()+",它叫"+pet.getName());
}
}
依赖关系的概述
指一个类A中的某个方法需要使用到另一个类B。依赖关系的特性:这种关系是具有偶然性的、临时性的、非常弱的,但是类B的变化会影响到类A。
表现形式:B作为A的某个方法的形式参数
案例:
游戏需求:
1、定义一个英雄类Hero,可以通过这个类创建英雄角色
属性:
游戏角色拥有昵称name,等级level,血量blood,攻击力power,防御力defence,种族kind,
装备Equip(只能装3个装备,初始没有装备)。
方法:
游戏角色拥有基本攻击方法(拥有一定几率打出暴击)attack(Monster m),死亡判定方法isDead(),添加装备的方法addEquip(Equip e),获取角色信息的方法show()。
2、定义一个怪兽类Monster,可以通过这个类创建怪兽角色
属性:
怪兽拥有名称name,等级level,血量blood,攻击力power,防御力defence,种族kind。
方法:
怪兽拥有基本攻击方法attack(Hero h),死亡判定方法isDead(),获取怪兽信息的方法show()。
3、定义装备类Equip,可以通过这个类创建各种装备
属性:
装备拥有名称name,级别level,颜色color,类别kind,攻击力power,防御力defence。
方法:
装备拥有获取装备信息的方法show()。
4、测试类
创建一个游戏角色:英雄类Hero、装备Equip、怪兽Monster,英雄类Hero装上装备,双方使用回合制的形式进行攻击(一人打一下,角色英雄类Hero先攻击,失血量=攻击-防御 ,攻击<防御,不产生攻击),直到一方死亡,游戏结束。
其中:
暴击>某个值
失血量=(攻击+暴击)-防御
package com.cautious.xin.game;
/**
* @Description 角色类
* @Author Cautious-Xin
* @Date 2020/10/29 14:38
*/
public abstract class Role {
private String name;
private int level;
private int blood;
private int attack;
private int defence;
private String kind;
public Role() { }
public Role(String name, int level, int blood, int attack, int defence, String kind) {
this.name = name;
this.level = level;
this.blood = blood;
this.attack = attack;
this.defence = defence;
this.kind = kind;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public int getBlood() {
return blood;
}
public void setBlood(int blood) {
this.blood = blood;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefence() {
return defence;
}
public void setDefence(int defence) {
this.defence = defence;
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public void show(){
System.out.println("昵称:"+this.getName()+" 等级:"+this.getLevel()+" 血量:"+this.getBlood()+" 攻击力:"
+this.getAttack()+" 防御力:"+this.getDefence()+" 种族:"+this.getKind());
}
public abstract void attack(Role role);
public boolean isDead(){
if(this.getBlood()<=0){
return false;
}
return true;
}
}
package com.cautious.xin.game;
/**
* @Description 怪兽类
* @Author Cautious-Xin
* @Date 2020/10/29 14:57
*/
public class Monster extends Role{
public Monster() { }
public Monster(String name, int level, int blood, int attack, int defence, String kind) {
super(name, level, blood, attack, defence, kind); }
@Override
public void attack(Role role) {
if(this.getAttack()>=role.getDefence()){//攻击大于防御,计算失血量
int loseBlood = this.getAttack()-role.getDefence();//计算出本次攻击对方损失了多少血
int hasBlood = role.getBlood()-loseBlood;//计算对方在遭受攻击后还剩余多少血
//更新血量
role.setBlood(hasBlood);
System.out.println("怪兽"+this.getName()+"攻击力英雄"+role.getName()+",使得英雄损失了"+loseBlood+"的血量");
}else {
System.out.println("怪兽此次攻击无效");
}
}
}
package com.cautious.xin.game;
/**
* @Description 英雄类
* @Author Cautious-Xin
* @Date 2020/10/29 14:43
*/
public class Hero extends Role{
private Equip []equip = new Equip[3];
int index = 0;
public void addEquip(Equip e){
if(equip[index]==null&&index<equip.length){
equip[index++]=e;
//计算加上装备的防御力和攻击力
int attack = this.getAttack()+e.getAttack();
this.setAttack(attack);
int defance = this.getDefence()+e.getDefence();
this.setDefence(defance);
/*this.setAttack(this.getAttack()+e.getAttack());*/
}
}
@Override
public void attack(Role role) {//英雄的攻击方法
int attack = this.getAttack();//获取当前攻击力
int critRate = (int) (Math.random()*10+1);//暴击率
if(critRate>5){
attack+=10*critRate;//说明产生了暴击
}
if(attack>=role.getDefence()){
int loseBlood = attack-role.getDefence();//计算出本次攻击对方损失了多少血
int hasBlood = role.getBlood()-loseBlood;//计算对方在遭受攻击后还剩余多少血
//更新血量
role.setBlood(hasBlood);
System.out.println("英雄"+this.getName()+"攻击了怪兽"+role.getName()+",使得怪兽损失了"+loseBlood+"的血量");
}else {
System.out.println("英雄此次攻击无效");
}
}
public Hero() {
}
public Hero(String name, int level, int blood, int attack, int defence, String kind, Equip[] equip) {
super(name, level, blood, attack, defence, kind);
this.equip = equip;
}
public Equip[] getEquip() {
return equip;
}
public void setEquip(Equip[] equip) {
this.equip = equip;
}
@Override
public void show() {
super.show();
if(this.getEquip()!=null) {
System.out.println(this.getName() + "的装备有:");
for (Equip equip1 : equip) {
if(equip1!=null) {
equip1.show();
}
}
}
}
}
package com.cautious.xin.game;
/**
* @Description 装备类
* @Author Cautious-Xin
* @Date 2020/10/29 14:44
*/
public class Equip {
private String name;
private int level;
private String color;
private String kind;
private int attack;
private int defence;
public Equip(String name, int level, String color, String kind, int attack, int defence) {
this.name = name;
this.level = level;
this.color = color;
this.kind = kind;
this.attack = attack;
this.defence = defence;
}
public Equip() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefence() {
return defence;
}
public void setDefence(int defence) {
this.defence = defence;
}
public void show(){
System.out.println("装备名称:"+name+" 级别:"+level+" 颜色:"+color+" 类别:"+kind+" 攻击力:"+attack+" 防御力:"+defence);
}
}
package com.cautious.xin.game;
/**
* @Description TODO
* @Author Cautious-Xin
* @Date 2020/10/29 15:19
*/
public class GameTest {
public static void main(String[] args) throws InterruptedException {
Role h = new Hero("迪迦",45,500,90,40,"奥特曼",new Equip[3]);
Equip e = new Equip("屠龙宝刀",40,"银色","刀",10,5);
System.out.println("添加装备前:");
h.show();
if(h instanceof Hero){
Hero h1 = (Hero) h;
h1.addEquip(e);
}
System.out.println("添加装备后:");
h.show();
System.out.println();
Role m = new Monster("哥斯拉",45,550,120,60,"怪兽");
while (true){
h.attack(m);
if(!m.isDead()){
System.out.println("怪兽死了");
break;
}
Thread.sleep(1000);
m.attack(h);
if(!h.isDead()){
System.out.println("英雄死了");
break;
}
Thread.sleep(1000);
System.out.println("此回合结束,双方的信息如下");
h.show();
m.show();
System.out.println("-------------------------------");
}
}
}