https://www.nowcoder.com/tutorial/94/ae05554a3ad84e42b6f9fc4d52859dc4
https://how2j.cn/k/interface-inheritance/interface-inheritance-interface/289.html
设计英雄,能物理攻击 类:ADHero 继承 Hero 类,继承了 name, hp, armor 等属性
Hero:
package 第11个程序_接口与继承.a1接口.s1_物理攻击接口; public class Hero { String name; float hp; //血量 float armor; //护甲 int moveSprrd; //速度 public static void main(String[] args) { // 创建1个对象 new Hero(); // 引用h 指向这个对象 Hero h = new Hero(); } } package 第11个程序_接口与继承.a1接口.s1_物理攻击接口; public class ADHero extends Hero implements AD{ @Override public void physicAttack() { System.out.println("警醒物理攻击!"); } }治疗者接口:Healer 方法: heal() 设计 Support 类 - 辅助英雄,继承 Hero,实现接口 Healer
package 第11个程序_接口与继承.a1接口.练习; public interface Healer { public void heal(); } package 第11个程序_接口与继承.a1接口.练习; public class Support extends Hero implements Healer{ @Override public void heal() { System.out.println("治疗"); } }可一致,可不一致
一致: ADHero ad = new ADHero(); new ADHero() 是对象 ad 是引用 类型都是 ADHero
不一致: Hero h = new ADHero();
Hero h = new Hero(); ADHero ad = new ADHero(); h = ad;ADHero 是继承 Hero 可以说 ADHero 可当成 Hero 来用(子类转父类) 反之,Hero 不可当成 ADHero 来用!
2 种情况:转换成功、转换失败
成功案例:
Hero h =new Hero(); ADHero ad = new ADHero(); h = ad; ad = (ADHero) h;2 个失败案例:
Hero h =new Hero(); ADHero ad = new ADHero(); Support s =new Support(); h = s; ad = (ADHero)h; Hero h = new Hero(); ADHero ad = new ADHero(); ad = (ADHero)h;实现类可以转接口(反之不行!):
ADHero ad = new ADHero(); AD adi = ad;没有继承关系的两个类,相互转换 一定失败!
instanceof Hero 判断引用 是否是 Hero 类型,或 Hero 子类
//判断引用h1指向的对象,是否是ADHero类型 System.out.println(h1 instanceof ADHero);找错误:
package charactor; public class Hero { public String name; protected float hp; public static void main(String[] args) { ADHero ad = new ADHero(); Hero h = ad; AD adi = (AD) h; APHero ap = (APHero) adi; } } Hero h = ad; 这行没错 子转父 AD adi = (AD) h; h指向ADHero,强转 AD 也行 APHero ap = (APHero) adi; adi 指向 AD,不能强行转 APhero,所以这里有问题子类继承父类,实现同一个方法,就是 重写=覆盖(override)
设计类 MagicPotion 蓝瓶,继承Item, 重写 effect 方法 输出 “蓝瓶使用后,可以回魔法”
package 第11个程序_接口与继承.a3_重写覆盖; public class MagicPotion extends Item{ public void effect(){ System.out.println("蓝瓶使用后,可以回魔法!"); } } MagicPotion magicPotion = new MagicPotion(); magicPotion.effect();2 种: 操作符的多态 类的多态
继承 重写 父类引用指向子类对象
可替换 可扩充 接口性 灵活 - 提高效率 简化
1 设计接口 Mortal,有方法 die 2 实现接口 ADHero,APHero,ADAPHero 这 3 类,实现 Mortal 接口 不同类实现 die方法,打印出不同字符串 3 Hero 类添加方法,调用 m.die方法 public void kill(Mortal m) 4 在主方法中 实例化 Hero对象:盖伦 实例化 3 对象,分别是ADHero,APHero,ADAPHero 实例 让盖伦 kill 这3对象
1 设计接口 Mortal,有方法 die
package 第11个程序_接口与继承.a4_多态.练习; public interface Mortal { public void die(); }2 ADHero,APHero,ADAPHero 这 3 类,实现 Mortal 接口 不同类实现 die方法,打印出不同字符串 3 Hero 类添加方法,调用 m.die方法 public void kill(Mortal m)
public void kill(Mortal m){ m.die(); }4 在主方法中操作:
package 第11个程序_接口与继承.a4_多态.练习; public class Hero { String name; float hp; //血量 float armor; //护甲 int moveSprrd; //速度 public void kill(Mortal m){ m.die(); } public static void main(String[] args) { Hero h = new Hero(); h.name = "盖伦"; Mortal m1 = new ADHero(); Mortal m2 = new APHero(); Mortal m3 = new ADAPHero(); h.kill(m1); h.kill(m2); h.kill(m3); } }重写:子类覆盖父类的 对象方法 隐藏:子类覆盖父类的 类方法
this()、super() 必须是构造函数中的第1条语句!
构造函数: public 类名(类型 参数){}
普通函数: public 返回类型 函数名(类型 参数){} 区别就是 有无返回类型
1 LifePotion、MagicPotion
package 第11个程序_接口与继承.a5_super; public class LifePotion extends Item { public void effect(){ System.out.println("药品使用后,可以回血!"); } } package 第11个程序_接口与继承.a5_super; public class MagicPotion extends Item { public void effect(){ System.out.println("蓝瓶使用后,可以回魔法!"); } }2 Hero
package 第11个程序_接口与继承.a5_super; public class Hero { String name; //姓名 float hp; //血量 float armor; //护甲 int moveSpeed; //移动速度 public void useItem(Item i){ System.out.println("hero use item"); i.effect(); } public Hero(){ System.out.println("Hero的构造方法 "); } public static void main(String[] args) { new Hero(); } }3 ADHero
package 第11个程序_接口与继承.a5_super; public interface AD { public void physicAttack(); } package 第11个程序_接口与继承.a5_super; public class ADHero extends Hero implements AD { @Override public void physicAttack() { System.out.println("进行物理攻击!"); } public ADHero(){ System.out.println("AD Hero 构造方法"); } public static void main(String[] args) { new ADHero(); } }4 Hero
package 第11个程序_接口与继承.a5_super; public class Hero { String name; //姓名 float hp; //血量 float armor; //护甲 int moveSpeed; //移动速度 public void useItem(Item i){ System.out.println("hero use item"); i.effect(); } public Hero(){ System.out.println("Hero的无参构造方法 "); } public Hero(String string){ System.out.println("Hero 有1个参数的构造方法"); } public static void main(String[] args) { new Hero(); } }5 ADHero
package 第11个程序_接口与继承.a5_super; public class ADHero extends Hero implements AD { @Override public void physicAttack() { System.out.println("进行物理攻击!"); } public ADHero(String name){ super(name); System.out.println("AD Hero 构造方法"); } public static void main(String[] args) { new ADHero("德莱文"); } }super 调用父类 moveSpeed 属性 ADHero 提供属性 moveSpeed
package 第11个程序_接口与继承.a5_super; public class ADHero extends Hero implements AD { int moveSpeed = 400; @Override public void physicAttack() { System.out.println("进行物理攻击!"); } public ADHero(String name){ super(name); System.out.println("AD Hero 构造方法"); } public int getMoveSpeed(){ return this.moveSpeed; } public int getMoveSpeed2(){ return super.moveSpeed; } public static void main(String[] args) { ADHero adHero = new ADHero("德莱文"); System.out.println(adHero.getMoveSpeed()); System.out.println(adHero.getMoveSpeed2()); } }ADHero 重写 useItem 方法, 在 useItem 中通过 super 调用父类的 useItem 方法
package 第11个程序_接口与继承.a5_super; public class ADHero extends Hero implements AD { int moveSpeed = 400; @Override public void physicAttack() { System.out.println("进行物理攻击!"); } public ADHero(String name){ super(name); System.out.println("AD Hero 构造方法"); } public int getMoveSpeed(){ return this.moveSpeed; } public int getMoveSpeed2(){ return super.moveSpeed; } public void useItem(Item item){ System.out.println("ADHero use item"); super.useItem(item); } public static void main(String[] args) { ADHero adHero = new ADHero("德莱文"); Item item = new Item(); adHero.useItem(item); // System.out.println(adHero.getMoveSpeed()); // System.out.println(adHero.getMoveSpeed2()); } }Object 类是所有类的父类
任何类默认继承 Object public class Hero 等价于 public class Hero extends Object
Object 类有 toString 方法,→ 所有的类都有 toString 方法 toString():返回当前对象的字符串表达
对象没有任何引用指向时,满足垃圾回收的条件 finalize() 方法会被调用
equals():
Hero h1= new Hero(); Hero h2= new Hero(); h1.equals(h2);==: 不是 Object 方法, 可用于判断 两个引用,是否指向同一个对象
hashCode:返回一个对象的哈希值 线程同步:wait()、notify()、notifyAll() getClass():返回对象的类对象
重写 Item的 toString(),finalize(),equals() 方法 toString() 返回 Item 的 name + price finalize() 输出当前对象正在被回收 equals(Object o) 首先判断 o 是否是 Item 类型 然后比较两个 Item 的 price 是否相同
package 第11个程序_接口与继承.a6_Object.练习; public class Item extends Object{ String name; int price; @Override public String toString() { return this.name; } @Override protected void finalize() throws Throwable { System.out.println(this.getClass() + "正在回收..."); } @Override public boolean equals(Object obj) { if(obj instanceof Item){ Item item = (Item) obj; return this.price == item.price; }else { return false; } } public static void main(String[] args) throws Throwable { Item item1 = new Item(); Item item2 = new Item(); item1.price = 100; item2.price = 100; System.out.println("item2.equals(item2) = " + item2.equals(item2)); System.out.println(item1.toString()); item1.finalize(); } }修饰 类: public final class Hero{} 该类不能被继承
修饰 方法: public final void useItem(Item i){} 该方法不能被重写
修饰 基本变量: final int hp; 该变量室友一次赋值机会,赋值后不能再赋值
修饰 引用: final Hero h; 该引用只有1次指向对象的机会 指向后,不能更新指向
修饰 常量: public static final int itemTotalNumber = 6;
类中声明一个方法,这个方法没有实现体,是“空”方法 用 abstract 修饰
1 Hero:
package 第11个程序_接口与继承.a7_抽象类.s1_简单例子; public abstract class Hero { String name; float hp; float armor; int moveSpeed; public static void main(String[] args) { } public abstract void attack(); }2 ADHero :
package 第11个程序_接口与继承.a7_抽象类.s1_简单例子; public interface AD { public void physicAttack(); } package 第11个程序_接口与继承.a7_抽象类.s1_简单例子; public class ADHero extends Hero implements AD{ @Override public void physicAttack() { System.out.println("进行物理攻击!"); } @Override public void attack() { physicAttack(); } }3 APHero:
package 第11个程序_接口与继承.a7_抽象类.s1_简单例子; public interface AP { public void magicAttack(); } package 第11个程序_接口与继承.a7_抽象类.s1_简单例子; public class APHero extends Hero implements AP{ @Override public void magicAttack() { System.out.println("进行魔法攻击!"); } @Override public void attack() { magicAttack(); } }4 ADAPHero:
package 第11个程序_接口与继承.a7_抽象类.s1_简单例子; public class ADAPHero extends Hero implements AD, AP{ @Override public void physicAttack() { System.out.println("既能物理攻击,也能魔法攻击!"); } @Override public void magicAttack() { System.out.println("进行魔法攻击!"); } @Override public void attack() { System.out.println("进行物理攻击!"); } }类被声明为抽象类,就不能够被直接实例化 错误例子:
package charactor; public abstract class Hero { public static void main(String[] args) { Hero h= new Hero(); // 错误! 抽象类不能实例化! } }1 子类只能继承1个抽象类,不能继承多个 子类可以实现多个接口
2 抽象类可定义 public, protected, package, private 静态、非静态属性 final、非final属性
接口中声明的属性,只能是 public 静态 final
3 抽象类、接口都可以有实体方法 接口中的实体方法,叫做默认方法
Item 类设计抽象方法 public abstract boolean disposable() 不同子类,实现 disposable 后,返回不同值
比如 LifePotion 返回 true Weapon, Armor 返回 false
1 Item:
package 第11个程序_接口与继承.a7_抽象类.练习; public abstract class Item { String xueping; String wuqi; public abstract boolean disposable(); public static void main(String[] args) { System.out.println(); } }2 LifePotion:
package 第11个程序_接口与继承.a7_抽象类.练习; public class LifePotion extends Item{ @Override public boolean disposable() { super.xueping = "已使用血瓶"; return true; } public static void main(String[] args) { LifePotion lifePotion = new LifePotion(); System.out.println(lifePotion.disposable() + lifePotion.xueping); } }3 Weapon:
package 第11个程序_接口与继承.a7_抽象类.练习; public class Weapon extends Item{ @Override public boolean disposable() { super.wuqi = "子弹已耗尽!"; return false; } public static void main(String[] args) { Weapon weapon = new Weapon(); System.out.println(weapon.disposable() + weapon.wuqi); } }有为4种: 非静态内部类 静态内部类 匿名类 本地类
静态内部类 不能直接访问外部类的对象属性
package 第11个程序_接口与继承.a8_内部类.s2_静态内部类; public class Hero { public String name; protected float hp; public static void battleWin() { System.out.println("battle win!"); } static class EnemyCrystal{ int hp = 500; public void checkIfVictory(){ if(hp == 0){ Hero.battleWin(); //静态内部类不能直接访问外部类的对象属性 // System.out.println(name + " win this game"); 错误! } } } public static void main(String[] args) { Hero.EnemyCrystal crystal = new Hero.EnemyCrystal(); crystal.checkIfVictory(); } }匿名类:声明一个类的同时,实例化它
package 第11个程序_接口与继承.a8_内部类.s3_匿名类; public interface AD { public void physicAttack(); } package 第11个程序_接口与继承.a8_内部类.s3_匿名类; public class ADHero extends Hero implements AD { @Override public void physicAttack() { System.out.println("进行物理攻击!"); } @Override public void attack() { physicAttack(); } } package 第11个程序_接口与继承.a8_内部类.s3_匿名类; public abstract class Hero { String name; //姓名 float hp; //血量 float armor; //护甲 int moveSpeed; //移动速度 public abstract void attack(); public static void main(String[] args) { ADHero adHero = new ADHero(); adHero.attack(); System.out.println(adHero); Hero hero = new Hero() { @Override public void attack() { System.out.println("新的进攻手段!"); } }; hero.attack(); System.out.println(hero); } }法 1: 外部局部变量必须是 final
package 第11个程序_接口与继承.a8_内部类.s3_匿名类.使用外部局部变量; public abstract class Hero { public abstract void attack(); public static void main(String[] args) { final int damage = 5; Hero hero = new Hero() { @Override public void attack() { System.out.printf("新的进攻手段,造成 %d 的伤害\n", damage); } }; hero.attack(); } }等价于 法2:
package 第11个程序_接口与继承.a8_内部类.s3_匿名类.使用外部局部变量; public abstract class Hero1 { public abstract void attack(); public static void main(String[] args) { int damage = 5; class AnnoymousHero extends Hero1{ int damage; public AnnoymousHero(int damage){ this.damage = damage; } public void attack(){ damage = 10; System.out.printf("新的进攻手段,造成 %d 的伤害!", this.damage); } } Hero1 hero1 = new AnnoymousHero(damage); hero1.attack(); } }本地类:有名字的匿名类
package 第11个程序_接口与继承.a8_内部类.s4_本地类; public abstract class Hero { String name; //姓名 float hp; //血量 float armor; //护甲 int moveSpeed; //移动速度 public abstract void attack(); public static void main(String[] args) { class SomeHero extends Hero{ @Override public void attack() { System.out.println(name + " 新的进攻手段!"); } } SomeHero someHero = new SomeHero(); someHero.name = "寒冰射手"; someHero.attack(); } }创建匿名类 Item 抽象方法 disposable()
package 第11个程序_接口与继承.a8_内部类.练习; public abstract class Item { String name; int price; public abstract boolean disposable(); public static void main(String[] args) { Item item = new Item() { @Override public boolean disposable() { name = "血瓶"; System.out.println(name + " 是一次性的吗?"); return true; } }; System.out.println(item.disposable()); } }接口也可以提供具体方法了
为什么要有这个功能? 答案:要为某个接口新加一个方法,则所有继承该接口的类都需要修改,很麻烦!
public interface Mortal { public void die(); default public void revive() { System.out.println("本英雄复活了"); } }为AD接口,加默认方法 attack() 为AP接口,加默认方法 attack() 问: ADAPHero 同时实现 AD, AP 接口,那么 ADAPHero 对象调用 attack() 时,调用哪个接口的 attack()?
答案: 实现多个接口同时,这些接口中实现了同样的默认方法, 那实现的子类必须要实现这个默认方法, 因为不知道要选择哪个方法
而要默认方法只有一个,那就可以不用实现 如AP实现了默认方法,AD没实现,那么两个都实现的子类也不用实现 或只实现一个接口,那么子类也不用实现