https://www.nowcoder.com/tutorial/94/ae05554a3ad84e42b6f9fc4d52859dc4
https://how2j.cn/k/interface-inheritance/interface-inheritance-interface/289.html
1 接口
物理攻击接口
package 第11个程序_接口与继承.a1接口.s1_物理攻击接口;
public interface AD {
public void physicAttack();
}
继承英雄,实现物理攻击接口
设计英雄,能物理攻击
类: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("警醒物理攻击!");
}
}
魔法攻击接口
package 第11个程序_接口与继承.a1接口.s1_物理攻击接口;
public interface AP {
public void magicAttack();
}
继承英雄,实现魔法攻击接口
package 第11个程序_接口与继承.a1接口.s1_物理攻击接口;
public class APHero extends Hero implements AP{
@Override
public void magicAttack() {
System.out.println("进行魔法攻击!");
}
}
实现物理、魔法攻击接口
package 第11个程序_接口与继承.a1接口.s1_物理攻击接口;
public class ADAPHero extends Hero implements AD,AP {
@Override
public void physicAttack() {
System.out.println("进行物理攻击!");
}
@Override
public void magicAttack() {
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("治疗");
}
}
2 对象转型
2.1 引用类型、对象类型
可一致,可不一致
一致:
ADHero ad = new ADHero();
new ADHero() 是对象
ad 是引用
类型都是 ADHero
2.2 子类转父类
不一致:
Hero h = new ADHero();
Hero h = new Hero();
ADHero ad = new ADHero();
h = ad;
ADHero 是继承 Hero
可以说 ADHero 可当成 Hero 来用(子类转父类)
反之,Hero 不可当成 ADHero 来用!
2.3 父类转子类
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;
2.4 其他
实现类可以转接口(反之不行!):
ADHero ad = new ADHero();
AD adi = ad;
没有继承关系的两个类,相互转换 一定失败!
2.5 instanceof
instanceof Hero 判断引用 是否是 Hero 类型,或 Hero 子类
//判断引用h1指向的对象,是否是ADHero类型
System.out.println(h1 instanceof ADHero);
2.6 练习
找错误:
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,所以这里有问题
3 重写 = 覆盖
子类继承父类,实现同一个方法,就是 重写=覆盖(override)
父类 Item
package 第11个程序_接口与继承.a3_重写覆盖;
public class Item {
String name;
int price;
public void buy(){
System.out.println("购买");
}
public void effect(){
System.out.println("物品使用后,有效果!");
}
}
子类 LifePotion
package 第11个程序_接口与继承.a3_重写覆盖;
public class LifePotion extends Item{
public void effect(){
System.out.println("药品使用后,可以回血!");
}
}
public static void main(String[] args) {
Item item = new Item();
item.effect();
LifePotion lifePotion = new LifePotion();
lifePotion.effect();
}
练习
设计类 MagicPotion 蓝瓶,继承Item, 重写 effect 方法
输出 “蓝瓶使用后,可以回魔法”
package 第11个程序_接口与继承.a3_重写覆盖;
public class MagicPotion extends Item{
public void effect(){
System.out.println("蓝瓶使用后,可以回魔法!");
}
}
MagicPotion magicPotion = new MagicPotion();
magicPotion.effect();
4 多态
2 种:
操作符的多态
类的多态
4.1 操作符的多态
int k = i+j;
//如果+号两侧都是整型,那么+代表 数字相加
String c = a+b;
//如果+号两侧,任意一个是字符串,那么+代表字符串连接
4.2 类的多态
package 第11个程序_接口与继承.a4_多态.类的多态;
public class Item {
String name;
int price;
public void buy(){
System.out.println("购买");
}
public void effect(){
System.out.println("物品使用后,有效果!");
}
public static void main(String[] args) {
Item item = new Item();
Item lifePotion = new LifePotion();
Item magicPotion = new MagicPotion();
item.effect();
lifePotion.effect();
magicPotion.effect();
}
}
4.3 三要素
继承
重写
父类引用指向子类对象
4.4 好处
可替换
可扩充
接口性
灵活 - 提高效率
简化
4.5 练习
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);
}
}
5 隐藏
重写:子类覆盖父类的 对象方法
隐藏:子类覆盖父类的 类方法
5.1 父类 类方法
public class Hero {
public String name;
protected float hp;
//类方法,静态方法
//通过类就可以直接调用,类方法
public static void battleWin(){
System.out.println("hero battle win");
}
}
5.2 隐藏
public class ADHero extends Hero implements AD{
@Override
public void physicAttack() {
System.out.println("进行物理攻击");
}
//隐藏父类的battleWin方法
public static void battleWin(){
System.out.println("ad hero battle win");
}
public static void main(String[] args) {
Hero.battleWin();
ADHero.battleWin();
}
}
5.3 练习
Hero h =new ADHero();
h.battleWin();
/*battleWin 是类方法
h是父类类型的引用
但是指向一个子类对象*/
h.battleWin();
会调用父类的方法、子类的方法?
Hero中的方法是静态的,不可以被重写
所以会打印父类中的方法
把static去掉,则打印子类中重写的方法
6 super
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();
}
}
6.1 子类调用父类带参构造方法
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("德莱文");
}
}
6.2 调用父类属性
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());
}
}
6.3 调用父类方法
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());
}
}
7 Object类
Object 类是所有类的父类
任何类默认继承 Object
public class Hero
等价于
public class Hero extends Object
7.1 toString()
Object 类有 toString 方法,→ 所有的类都有 toString 方法
toString():返回当前对象的字符串表达
7.2 finalize()
对象没有任何引用指向时,满足垃圾回收的条件
finalize() 方法会被调用
7.3 equals(),==
equals():
Hero h1= new Hero();
Hero h2= new Hero();
h1.equals(h2);
==:
不是 Object 方法,
可用于判断 两个引用,是否指向同一个对象
7.4 其他
hashCode:返回一个对象的哈希值
线程同步:wait()、notify()、notifyAll()
getClass():返回对象的类对象
7.5 练习
重写 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();
}
}
8 final
修饰 类:
public final class Hero{}
该类不能被继承
修饰 方法:
public final void useItem(Item i){}
该方法不能被重写
修饰 基本变量:
final int hp;
该变量室友一次赋值机会,赋值后不能再赋值
修饰 引用:
final Hero h;
该引用只有1次指向对象的机会
指向后,不能更新指向
修饰 常量:
public static final int itemTotalNumber = 6;
9 抽象类
类中声明一个方法,这个方法没有实现体,是“空”方法
用 abstract 修饰
9.1 简单例子
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("进行物理攻击!");
}
}
9.2 注意
类被声明为抽象类,就不能够被直接实例化
错误例子:
package charactor;
public abstract class Hero {
public static void main(String[] args) {
Hero h= new Hero();
// 错误! 抽象类不能实例化!
}
}
9.3 与接口的区别
1
子类只能继承1个抽象类,不能继承多个
子类可以实现多个接口
2
抽象类可定义
public, protected, package, private
静态、非静态属性
final、非final属性
接口中声明的属性,只能是
public
静态
final
3
抽象类、接口都可以有实体方法
接口中的实体方法,叫做默认方法
9.4 练习
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);
}
}
10 内部类
有为4种:
非静态内部类
静态内部类
匿名类
本地类
10.1 非静态内部类
package 第11个程序_接口与继承.a8_内部类.s1_简单例子;
public class Hero {
private String name;
float hp;
float armor;
int moveSpeed;
class BattleScore{
int kill;
int die;
int assit;
public void legendary(){
if(kill > 8)
System.out.println(name + "超神!");
else
System.out.println(name + "尚未超神!");
}
}
public static void main(String[] args) {
Hero hero = new Hero();
hero.name = "盖伦";
BattleScore score = hero.new BattleScore();
score.kill = 9;
score.legendary();
}
}
10.2 静态内部类
静态内部类 不能直接访问外部类的对象属性
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();
}
}
10.3 匿名类
匿名类:声明一个类的同时,实例化它
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);
}
}
10.3.1 使用外部局部变量
法 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();
}
}
10.4 本地类
本地类:有名字的匿名类
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();
}
}
10.5 练习
创建匿名类 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());
}
}
11 默认方法
接口也可以提供具体方法了
为什么要有这个功能?
答案:要为某个接口新加一个方法,则所有继承该接口的类都需要修改,很麻烦!
public interface Mortal {
public void die();
default public void revive() {
System.out.println("本英雄复活了");
}
}
11.1 练习
为AD接口,加默认方法 attack()
为AP接口,加默认方法 attack()
问:
ADAPHero 同时实现 AD, AP 接口,那么 ADAPHero 对象调用 attack() 时,调用哪个接口的 attack()?
答案:
实现多个接口同时,这些接口中实现了同样的默认方法,
那实现的子类必须要实现这个默认方法,
因为不知道要选择哪个方法
而要默认方法只有一个,那就可以不用实现
如AP实现了默认方法,AD没实现,那么两个都实现的子类也不用实现
或只实现一个接口,那么子类也不用实现
12 综合练习
Animal
package 第11个程序_接口与继承.a9_综合练习;
public abstract class Animal {
public int legs;
public Animal(){
System.out.println("创建了没有腿的动物!");
}
public Animal(int legs){
this.legs = legs;
System.out.println("创建了 " + legs + " 条腿的动物");
}
public abstract void eat();
public void walk(){
System.out.println("该动物是用" + this.legs + "条腿走路的");
}
}
Pet
package 第11个程序_接口与继承.a9_综合练习;
public interface Pet {
public String getName();
public void setName(String name);
public void paly();
}
Spider
package 第11个程序_接口与继承.a9_综合练习;
public class Spider extends Animal{
public Spider(){
super(8);
System.out.println("每个蜘蛛都是8条腿");
}
@Override
public void eat() {
System.out.println("蜘蛛在吃虫");
}
}
Cat
package 第11个程序_接口与继承.a9_综合练习;
public class Cat extends Animal implements Pet{
private String name;
public Cat(){
this(null);
System.out.println("该猫没有名字");
}
public Cat(String name){
super(4);
this.name = name;
}
@Override
public void eat() {
System.out.println(this.name + "在吃鱼");
}
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void paly() {
System.out.println(this.name + "在玩耍");
}
}
Fish
package 第11个程序_接口与继承.a9_综合练习;
public class Fish extends Animal implements Pet{
private String name;
public Fish(){
}
@Override
public void eat() {
System.out.println(this.name + "在吃更小的鱼");
}
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void paly() {
System.out.println(this.name + "在玩耍");
}
}
测试
package 第11个程序_接口与继承.a9_综合练习;
public class test {
public static void main(String[] args) {
Cat cat = new Cat("猫a");
Spider spider = new Spider();
Fish fish = new Fish();
cat.eat();
cat.getName();
cat.paly();
spider.eat();
fish.getName();
fish.paly();
}
}