ITPub博客

首页 > 应用开发 > Java > JAVA基础学习- 接口与继承

JAVA基础学习- 接口与继承

Java 作者:喝水会长肉 时间:2021-12-10 15:53:47 0 删除 编辑

8.1 接口

在设计LOL的时候,进攻类英雄有两种,一种是进行物理系攻击,一种是进行魔法系攻击

这时候,就可以使用 接口来实现这个效果。

接口就像是一种约定,我们约定某些英雄是物理系英雄,那么他们就一定能够进行物理攻击。

  • 物理攻击接口

创建一个接口 AD ,声明一个方法 physicAttack 物理攻击,但是没有方法体,是一个“ 空”方法


package charactor
;


public interface AD {
        //物理伤害
    public void physicAttack ( ) ;
}
  • 设计一类英雄,能够使用物理攻击

设计一类英雄,能够使用物理攻击,这类英雄在LOL中被叫做AD类:ADHero 继承了Hero 类,所以继承了name,hp,armor等属性

实现某个接口,就相当于承诺了某种约定

所以, 实现了 AD这个接口,就 必须提供AD接口中声明的方法 physicAttack()  实现在语法上使用关键字  implements


package charactor
;


public class ADHero extends Hero implements AD {

   @Override
    public void physicAttack ( ) {
       System .out . println ( "进行物理攻击" ) ;
    }

}
  • 魔法攻击接口


package charactor
;


public class APHero extends Hero implements AP {

   @Override
    public void magicAttack ( ) {
       System .out . println ( "进行魔法攻击" ) ;
    }

}
  • 设计一类英雄,既能进行物理攻击,又能进行魔法攻击

一种英雄,能够同时进行物理攻击和魔法攻击 比如伊泽瑞尔,皮城女警凯特琳


package charactor
;

 
//同时能进行物理和魔法伤害的英雄
public class ADAPHero extends Hero implements AD , AP {
 
   @Override
    public void magicAttack ( ) {
       System .out . println ( "进行魔法攻击" ) ;
    }
 
   @Override
    public void physicAttack ( ) {
       System .out . println ( "进行物理攻击" ) ;
    }
 
}


  • 什么样的情况下该使用接口?

如上的例子,似乎要接口,不要接口,都一样的,那么接口的意义是什么呢

学习一个知识点,是由浅入深得进行的。 这里呢,只是引入了接口的概念,要真正理解接口的好处,需要更多的实践,以及在较为复杂的系统中进行大量运用之后,才能够真正理解,比如在学习了 多态之后就能进一步加深理解。

刚刚接触一个概念,就希望达到炉火纯青的学习效果,这样的学习目标是不科学的。

8.2 对象转型

  • 明确引用类型与对象类型的概念

首先,明确引用类型与对象类型的概念 在这个例子里,有一个对象 new ADHero(), 同时也有一个引用ad 对象是有类型的, 是ADHero 引用也是有类型的,是ADHero 通常情况下,引用类型和对象类型是一样的 接下来要讨论的类型转换的问题,指的是 引用类型和对象类型不一致的情况下的转换问题


package charactor
;


public class Hero {
public String name ;
protected float hp ;
public static void main ( String [ ] args ) {
ADHero ad = new ADHero ( ) ;
}
}


  • 子类转父类(向上转型)

所谓的转型,是指当 引用类型和 对象类型不一致的时候,才需要进行类型转换

父类指向子类对象是一定可以成功的。


package charactor
;


! [image .png ] (https : / /p1 -juejin .byteimg .com /tos -cn -i -k3u1fbpfcp / 0cd3df775bab463f83dacdbb53e8c5ec ~tplv -k3u1fbpfcp -watermark .image ? )
public class Hero {
public String name ;
protected float hp ;
public static void main ( String [ ] args ) {
Hero h = new Hero ( ) ;
ADHero ad = new ADHero ( ) ;
//类型转换指的是把一个引用所指向的对象的类型,转换为另一个引用的类型
//把ad引用所指向的对象的类型是ADHero
//h引用的类型是Hero
//把ADHero当做Hero使用,一定可以
h = ad ;
}
}


  • 父类转子类(向下转型)

父类转子类,有的时候行,有的时候不行,所以必须进行强制转换。 强制转换的意思就是 转换有风险,风险自担。


package charactor
;

import charactor1 .Support ;

public class Hero {
    public String name ;
    protected float hp ;
    public static void main ( String [ ] args ) {
       Hero h = new Hero ( ) ;
       ADHero ad = new ADHero ( ) ;
       Support s = new Support ( ) ;
       
       h = ad ;
       ad = (ADHero ) h ; //可以成功
       h = s ;
       ad = (ADHero )h ;   //指向失败
    }
}
  • 没有继承关系的两个类,互相转换

没有继承关系的两个类,互相转换,一定会失败。 虽然ADHero和APHero都继承了Hero,但是彼此没有互相继承关系。


package charactor
;

public class Hero {
public String name ;
protected float hp ;

public static void main ( String [ ] args ) {
ADHero ad = new ADHero ( ) ;
APHero ap = new APHero ( ) ;

// 没有继承关系的类型进行互相转换一定会失败,所以会出现编译错误
ad = (ADHero ) ap ;
}
}
  • 实现类转换成接口(向上转型)

ad指向的对象是ADHero类型,这个类型实现了AD接口。  实现AD接口的类ADHero一定可以转换为接口;

换句话说, 接口可以指向实现此接口的类。


package charactor
;

public class Hero {
    public String name ;
    protected float hp ;
     
    public static void main ( String [ ] args ) {
       ADHero ad = new ADHero ( ) ;
        AD adi = ad ;
    }
}


  • 接口转换成实现类(向下转型)

实现类指向接口不一定可以成功, 需要强制转换。

10行: ad引用指向ADHero, 而adi引用是接口类型:AD,实现类转换为接口,是向上转型,所以无需强制转换,并且一定能成功 12行: adi实际上是指向一个ADHero的,所以能够转换成功 14行: adi引用所指向的对象是一个ADHero,要转换为ADAPHero就会失败。

假设能够转换成功,那么就可以使用 magicAttack方法,而adi引用所指向的对象 ADHero是 没有magicAttack方法的。


package charactor
;

public class Hero {
    public String name ;
    protected float hp ;
       
    public static void main ( String [ ] args ) {
       ADHero ad = new ADHero ( ) ;
        AD adi = ad ;
       
       ADHero adHero = (ADHero ) adi ;
       ADAPHero adapHero = (ADAPHero ) adi ;
       adapHero . magicAttack ( ) ;
    }
}


  • instanceof Hero 判断一个引用所指向的对象,是否是Hero类型,或者Hero的子类

8.3 重写

子类可以继承父类的对象方法;在继承后,重复提供该方法,就叫做方法的重写。

又叫覆盖 override

  • 父类Item有一个方法,叫做effect


package property
;


public class Item {
   String name ;
   int price ;

    public void buy ( ) {
       System .out . println ( "购买" ) ;
    }
    public void effect ( ) {
       System .out . println ( "物品使用后,可以有效果" ) ;
    }

}
  • 子类LifePotion继承Item,同时也提供了方法effect


package property
;


public class LifePotion extends Item {
   
    public void effect ( ) {
       System .out . println ( "血瓶使用后,可以回-血" ) ;
    }
   
}
  • 调用重写的方法

调用就会执行重写的方法,而不是从父类的方法。 所以LifePotion的effect会打印: "血瓶使用后,可以回-血"


package property
;

public class Item {
   String name ;
   int price ;
   
    public void effect ( ) {
       System .out . println ( "物品使用后,可以有效果" ) ;
    }
   
    public static void main ( String [ ] args ) {
       Item i = new Item ( ) ;
       i . effect ( ) ;
       
       LifePotion lp = new LifePotion ( ) ;
       lp . effect ( ) ;
    }
}


  • 如果没有重写这样的机制怎么样?

如果没有重写这样的机制,也就是说LifePotion这个类,一旦继承了Item,所有方法都不能修改了。

但是LifePotion又希望提供一点不同的功能,为了达到这个目的,只能 放弃继承Item,重新编写所有的属性和方法,然后在编写effect的时候,做一点小改动.

这样就增加了开发时间和维护成本


package property
;


public class LifePotion {
   String name ;
   int price ;

    public void buy ( ) {
       System .out . println ( "购买" ) ;
    }
    //只能放弃继承Item
    public void effect ( ) {
       System .out . println ( "血瓶使用后,可以回-血" ) ;
    }

8.4 多态

  • 操作符的多态

同一个操作符在不同情境下,具备不同的作用 如果+号两侧都是整型,那么**+代表 数字相加** 如果+号两侧,任意一个是字符串,那么**+代表字符串**


package charactor
;

public class Hero {
    public String name ;
    protected float hp ;
    public static void main ( String [ ] args ) {
       
       int i = 5 ;
       int j = 6 ;
       int k = i +j ; //如果+号两侧都是整型,那么+代表 数字相加
       
       System .out . println (k ) ;
       
       int a = 5 ;
       String b = "5" ;
       
       String c = a +b ; //如果+号两侧,任意一个是字符串,那么+代表字符串连接
       System .out . println (c ) ;    
    }  
}
  • 观察类的多态现象

观察类的多态现象:

  1. i1和i2都是Item类型

  2. 都调用effect方法

  3. 输出不同的结果

多态: 都是同一个类型,调用同一个方法,却能呈现不同的状态

Item.java:


package property
;


public class Item {
   String name ;
   int price ;

    public void buy ( ) {
       System .out . println ( "购买" ) ;
    }
    public void effect ( ) {
       System .out . println ( "物品使用后,可以有效果 " ) ;
    }
    //java学习交流:737251827  进入可领取学习资源及对十年开发经验大佬提问,免费解答!
    public static void main ( String [ ] args ) {
        //父类引用指向子类实例
       Item i1 = new LifePotion ( ) ;
       Item i2 = new MagicPotion ( ) ;
       System .out . print ( "i1  是Item类型,执行effect打印:" ) ;
       i1 . effect ( ) ;
       System .out . print ( "i2也是Item类型,执行effect打印:" ) ;
       i2 . effect ( ) ;
    }

}


LifePotion.java


package property
;


public class LifePotion extends Item {
    public void effect ( ) {
       System .out . println ( "血瓶使用后,可以回-血" ) ;
    }
}


MagicPotion.java


package property
;


public class MagicPotion extends Item {
    public void effect ( ) {
       System .out . println ( "蓝瓶使用后,可以回魔法" ) ;
    }
}
  • 类的多态条件

要实现类的多态,需要如下条件

  1. 父类(接口)引用指向子类对象

  2. 调用的方法有 重写

那么多态有什么作用呢? 通过比较 不使用多态与 使用多态来进一步了解


package charactor
;


import property .LifePotion ;
import property .MagicPotion ;
 
public class Hero {
    public String name ;
    protected float hp ;

    public void useLifePotion ( LifePotion lp ) {
       lp . effect ( ) ;
    }
    public void useMagicPotion ( MagicPotion mp ) {
       mp . effect ( ) ;
    }

    public static void main ( String [ ] args ) {
       
       Hero garen =   new Hero ( ) ;
       garen .name = "盖伦" ;
   
       LifePotion lp = new LifePotion ( ) ;
       MagicPotion mp = new MagicPotion ( ) ;
       
       garen . useLifePotion (lp ) ;
       garen . useMagicPotion (mp ) ;
    }
}


如果不使用多态,假设英雄要使用血瓶和魔瓶,就需要为Hero设计两个方法. useLifePotion useMagicPotion

除了血瓶和魔瓶还有很多种物品,那么就需要设计很多很多个方法,比如 usePurityPotion 净化药水 useGuard 守卫 useInvisiblePotion 使用隐形药水 等等等等

  • 类的多态-使用多态

如果物品的种类特别多,那么就需要设计很多的方法 比如useArmor,useWeapon等等

这个时候采用多态来解决这个问题 设计一个方法叫做useItem,其参数类型是Item 如果是使用血瓶,调用该方法 如果是使用魔瓶,还是调用该方法 无论英雄要使用什么样的物品, 只需要一个方法即可


package charactor
;


import property .Item ;
import property .LifePotion ;
import property .MagicPotion ;
 
public class Hero {
    public String name ;
    protected float hp ;

    public void useItem ( Item i ) {
       i . effect ( ) ;
    }

    public static void main ( String [ ] args ) {
       
       Hero garen =   new Hero ( ) ;
       garen .name = "盖伦" ;
   
       LifePotion lp = new LifePotion ( ) ;
       MagicPotion mp = new MagicPotion ( ) ;
       
       garen . useItem (lp ) ;
       garen . useItem (mp ) ;    
       
    }
}


8.5 隐藏

与重写类似,方法的 重写是子类覆盖父类的 对象方法

隐藏,就是子类覆盖父类的 类方法

  • 父类

父类有一个类方法 :battleWin


package charactor
;

 
public class Hero {
    public String name ;
    protected float hp ;
 
    //类方法,静态方法
    //通过类就可以直接调用
    public static void battleWin ( ) {
       System .out . println ( "hero battle win" ) ;
    }
     
}


  • 子类隐藏父类的类方法


package charactor
;

 
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 ( ) ;
    }
}


8.6 super关键字

  • 准备一个显式提供无参构造方法的父类

在实例化Hero对象的时候,其构造方法会打印“Hero的构造方法 "。


package charactor
;

import property .Item ;

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 ( ) ;
    }  
}


  • 实例化子类,父类的构造方法一定会被调用

实例化一个ADHero(), 其构造方法会被调用:其 父类的构造方法也会被调用,并且是父类构造方法 先调用。子类构造方法会默认调用父类的 无参的构造方法。


package charactor
;

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 ( ) ;  
    }
}


  • 父类显式提供两个构造方法

分别是无参的构造方法和带一个参数的构造方法


package charactor
;

import property .Item ;

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 name ) {
       System .out . println ( "Hero的有一个参数的构造方法 " ) ;
        this .name = name ;
    }
    public static void main ( String [ ] args ) {
        new Hero ( ) ;
    }
}


  • 子类显式调用父类带参构造方法


package charactor
;

 
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 ( "德莱文" ) ;
    }
}


  • 调用父类属性


package charactor
;

 
public class ADHero extends Hero implements AD {
   int moveSpeed = 400 ; //移动速度
   @Override
    public void physicAttack ( ) {
       System .out . println ( "进行物理攻击" ) ;
    }
   
    public int getMoveSpeed ( ) {
        return this .moveSpeed ;
    }
    public int getMoveSpeed2 ( ) {
        return super .moveSpeed ;
    }
   
    public static void main ( String [ ] args ) {
       ADHero h = new ADHero ( ) ;
       System .out . println (h . getMoveSpeed ( ) ) ;
       System .out . println (h . getMoveSpeed2 ( ) ) ;  
    }
}


  • 调用父类方法

ADHero重写了useItem方法,并且在useItem中 通过super调用父类的useItem方法


package charactor
;


import property .Item ;
import property .LifePotion ;

public class ADHero extends Hero implements AD {
   int moveSpeed = 400 ; // 移动速度
   @Override
    public void physicAttack ( ) {
       System .out . println ( "进行物理攻击" ) ;
    }

    public int getMoveSpeed ( ) {
        return this .moveSpeed ;
    }
    public int getMoveSpeed2 ( ) {
        return super .moveSpeed ;
    }

    // 重写useItem,并在其中调用父类的userItem方法
    public void useItem ( Item i ) {
       System .out . println ( "adhero use item" ) ;
        super . useItem (i ) ;
    }

    public static void main ( String [ ] args ) {
       ADHero h = new ADHero ( ) ;
       LifePotion lp = new LifePotion ( ) ;
    }
}


8.7 Object类

Object类是所有类的父类

  • 声明一个类的时候,默认是继承了Object

  • toString()

Object类提供一个toString方法,所以所有的类都有toString方法。toString()的意思是返回当前对象的 字符串表达。 通过 System.out.println 打印对象就是打印该对象的toString()返回值


package charactor
;

 
public class Hero {
    public String name ;
    protected float hp ;
     
    public String toString ( ) {
        return name ;
    }
     
    public static void main ( String [ ] args ) {
       Hero h = new Hero ( ) ;
       h .name = "盖伦" ;
       System .out . println (h . toString ( ) ) ;
        //直接打印对象就是打印该对象的toString()返回值
       System .out . println (h ) ;
    }
}
  • finalize()

当一个对象没有任何引用指向的时候,它就满足垃圾回收的条件

当它被垃圾回收的时候,它的finalize() 方法就会被调用。

finalize() 不是开发人员主动调用的方法,而是由虚拟机JVM调用的。

  • equals()

equals() 用于判断两个对象的 内容是否相同

假设,当两个英雄的hp相同的时候,我们就认为这两个英雄相同

System
.out
.
println
(h1
.
equals
(h2
)
)
;

System .out . println (h1 . equals (h3 ) ) ;
  • ==

这不是Object的方法,但是用于判断两个对象是否相同  更准确的讲,用于判断两个引用,是否 指向了同一个对象

System
.out
.
println
(h1
==h2
)
;

System .out . println (h1 ==h3 ) ;

8.8 final

  • final修饰类

当Hero被修饰成final的时候,表示Hero不能够被继承;其子类会出现编译错误。


package charactor
;


public final class Hero extends Object {  
   String name ; //姓名
   float hp ; //血量  
}
  • final修饰方法

Hero的useItem方法被修饰成final,那么该方法在ADHero中,不能够被重写


package charactor
;


import property .Item ;

public class Hero extends Object {
    public final void useItem ( Item i ) {
       System .out . println ( "hero use item" ) ;
       i . effect ( ) ;
    }  

    public static void main ( String [ ] args ) {
        new Hero ( ) ;
    }
}
  • final修饰基本类型变量

final修饰基本类型变量,表示该变量只有一次赋值机会;

16行进行了赋值,17行就不可以再进行赋值了。


package charactor
;


public class Hero extends Object {
   float hp ; //血量

    public static void main ( String [ ] args ) {
       final int hp ;
       hp = 5 ;
       hp = 6 ;
    }
}
  • final修饰引用

final修饰引用:h引用被修饰成final,表示该引用只有 1次指向对象的机会。 所以17行会出现编译错误 但是,依然通过h引用修改对象的属性值hp,因为hp并没有final修饰


package charactor
;


public class Hero extends Object {
   String name ; //姓名
   float hp ; //血量
   float armor ; //护甲
   int moveSpeed ; //移动速度
   
    public static void main ( String [ ] args ) {
       final Hero h ;
       h   = new Hero ( ) ;
       h   = new Hero ( ) ;
       
       h .hp = 5 ;  
    }
}
  • 常量

常量指的是可以公开,直接访问,不会变化的值 比如 itemTotalNumber 物品栏的数量是6个


public 
static final int itemTotalNumber 
= 
6
;
//物品栏的数量

8.9 抽象类

在类中声明一个方法,这个方法没有实现体,是一个“空”方法

这样的方法就叫抽象方法,使用修饰符“abstract"

当一个类有抽象方法的时候,该类必须被声明为抽象类

  • 抽象类

为Hero增加一个 抽象方法 attack,并且把Hero声明为abstract的。 APHero,ADHero,ADAPHero是Hero的子类,继承了Hero的属性和方法。 但是各自的攻击手段是不一样的,所以继承Hero类后,这些 子类就必须提供不一样的attack方法实现。

Hero.java


package charactor
;


public abstract class Hero {
   String name ;
   float hp ;
   float armor ;
   int moveSpeed ;

    public static void main ( String [ ] args ) { }

    // 抽象方法attack
    // Hero的子类会被要求实现attack方法
    public abstract void attack ( ) ;
}


ADHero.java


package charactor
;

public class ADHero extends Hero implements AD {
    public void physicAttack ( ) {
       System .out . println ( "进行物理攻击" ) ;
    }

   @Override
    public void attack ( ) {
        physicAttack ( ) ;
    }
}
  • 抽象类可以没有抽象方法

Hero类可以在不提供抽象方法的前提下,声明为抽象类  一旦一个类被声明为抽象类,就不能够被直接实例化


package charactor
;

 
public abstract class Hero {
   String name ;
   float hp ;
   float armor ;
   int moveSpeed ;
     
    public static void main ( String [ ] args ) {
        //虽然没有抽象方法,但是一旦被声明为了抽象类,就不能够直接被实例化
       Hero h = new Hero ( ) ;
    }
}
  • 抽象类和接口的区别


package charactor
;

 
public interface AP {
 
    public static final int resistPhysic = 100 ;
   
    //resistMagic即便没有显式的声明为 public static final
    //但依然默认为public static final
   int resistMagic = 0 ;
   
    public void magicAttack ( ) ;
}


8.10 内部类

  • 非静态内部类

非静态内部类 BattleScore “战斗成绩”,非静态内部类可以直接在一个类里面定义。

比如:战斗成绩只有在一个英雄对象存在的时候才有意义;所以实例化BattleScore 的时候,必须建立在一个存在的英雄的基础上。 语法:  new 外部类().new 内部类() 作为Hero的非静态内部类,是可以直接访问外部类的 private实例属性name的

  • 静态内部类

在一个类里面声明一个静态内部类:比如敌方水晶,当敌方水晶没有血的时候,己方所有英雄都取得胜利,而不只是某一个具体的英雄取得胜利。

与非静态内部类不同, 静态内部类水晶类的实例化  不需要一个外部类的实例为基础,可以直接实例化。语法: new 外部类.静态内部类();

因为没有一个外部类的实例,所以在静态内部类里面 不可以访问外部类的实例属性和方法。除了可以访问外部类的 私有静态成员外,静态内部类和普通类没什么大的区别


package charactor
;

 
public class Hero {
    public String name ;
    protected float hp ;
    private static void battleWin ( ) {
       System .out . println ( "battle win" ) ;
    }
    //java学习交流:737251827  进入可领取学习资源及对十年开发经验大佬提问,免费解答!
    //敌方的水晶
    static class EnemyCrystal {
       int hp = 5000 ;
        //如果水晶的血量为0,则宣布胜利
        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 ( ) ;
    }
}
  • 匿名类

匿名类指的是在 声明一个类的同时实例化它,使代码更加简洁精练。通常情况下,要使用一个接口或者抽象类,都必须创建一个子类。

有的时候,为了快速使用,直接实例化一个抽象类,并“ 当场”实现其抽象方法。 既然实现了抽象方法,那么就是一个新的类,只是这个类,没有命名。 这样的类,叫做匿名类

  • 本地类

本地类可以理解为有名字的匿名类。 内部类与匿名类不一样的是,内部类必须声明在成员的位置,即与属性和方法平等的位置。 本地类和匿名类一样,直接声明在代码块里面,可以是主方法,for循环里等等地方。


package charactor
;

 
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 {
            public void attack ( ) {
               System .out . println ( name + " 新的进攻手段" ) ;
            }
        }
       
       SomeHero h   = new SomeHero ( ) ;
       h .name = "地卜师" ;
       h . attack ( ) ;
    }
     
}
  • 在匿名类中使用外部的局部变量

在匿名类中使用外部的局部变量,外部的局部变量必须修饰为final


package charactor
;

 
public abstract class Hero {
    public abstract void attack ( ) ;
    public static void main ( String [ ] args ) {
        //在匿名类中使用外部的局部变量damage 必须修饰为final
       int damage = 5 ;
        //这里使用本地类AnonymousHero来模拟匿名类的隐藏属性机制
       
        //事实上的匿名类,会在匿名类里声明一个damage属性,并且使用构造方法初始化该属性的值
        //在attack中使用的damage,真正使用的是这个内部damage,而非外部damage
       
        //假设外部属性不需要声明为final
        //那么在attack中修改damage的值,就会被暗示为修改了外部变量damage的值
       
        //但是他们俩是不同的变量,是不可能修改外部变量damage的
        //所以为了避免产生误导,外部的damage必须声明为final,"看上去"就不能修改了
        class AnonymousHero extends Hero {
           int damage ;
            public AnonymousHero ( int damage ) {
                this .damage = damage ;
            }
            public void attack ( ) {
               damage = 10 ;
               System .out . printf ( "新的进攻手段,造成%d点伤害" , this .damage ) ;
            }
        }
       Hero h = new AnonymousHero (damage ) ;
    }


8.11 默认方法

  • 什么是默认方法

默认方法是JDK8新特性,指的是接口也可以提供具体方法了,而不像以前,只能提供抽象方法

Mortal 这个接口,增加了一个 默认方法 revive,这个方法有实现体,并且被声明为了 default


package charactor
;


public interface Mortal {
    public void die ( ) ;

    default public void revive ( ) {
       System .out . println ( "本英雄复活了" ) ;
    }
}
  • 为什么会有默认方法

  • 假设没有默认方法这种机制,那么如果要为Mortal增加一个新的方法revive,那么所有实现了Mortal接口的类,都需要做改动。

    但是引入了默认方法后,原来的类,不需要做任何改动,并且还能 得到这个默认方法

    通过这种手段,就能够很好的扩展新的类,并且做到不影响原来的类




来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70010294/viewspace-2847046/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-11-19

  • 博文量
    199
  • 访问量
    86390