JAVA面向对象5:final关键字、抽象类和接口

final关键字

1、final关键字修饰类

Java中的类被final关键字修饰后,该类将不可以被继承,也就是不能够派生子类。
案例1:

//使用final关键字修饰Animal类
final class Animal {
    //方法体为空
}
//Dog类继承Animal类
class Dog extends Animal {
    //方法体为空
}
//定义测试类
class Example1 {
    public static void main(String[] args) {
        Dog dog=new dog();           //创建Dog类的实例对象
    }
}

案例1中,由于Animal类被final关键字所修饰,因此,当Dog类继承Animal类时,编译出现了“无法从最终Animal进行继承”的错误。由此可见,被final关键字修饰的类为最终类,不能被其他类继承。


2、final关键字修饰方法

当一个类的方法被final关键字修饰后,这个类的子类将不能重写该方法。
案例2:

//定义Animal类
class Animal {
    //使用final关键字修饰shout()方法
    public final void shout() {
        //程序代码
    }
}
//定义Dog类继承Animal类
class Dog extends Animal {
    //重写Animal类的shout方法
    public void shout() {
        //程序代码
    }
}
//定义测试类
class Example2 {
    public static void main(String[] args) {
        Dog dog=new Dog();            //创建Dog对象的实例
    }
}

案例2中,Dog类重写父类Animal的shout()方法后,编译报错。这是因为Animal类的shout()方法被final修饰。由此可见,被final关键字修饰的方法为最终方法,子类不能对该方法进行重写。正是由于final的这种特性,当在父类中定义某个方法时,如果不希望被子类重写,就可以使用final关键字修饰该方法。


3、final关键字修饰变量

Java中被final修饰的变量为常量,他只能被赋值一次,也就是说final修饰的变量一旦被赋值,其值不能被改变。如果再次对该变量进行赋值,则程序会在编译时报错。
案例3:

public class Example3 {
    public static void main(String[] args) {
        final int num=2;           //第一次可以赋值
        num=4;                     //再次赋值会报错
    }
}

案例3中,当第4行对num赋值时,编译报错。原因在于变量num被final修饰。由此可见,被final修饰的变量为常量,它只能被赋值一次,其值不能被改变。
案例3中,被final关键字修饰的变量为局部变量。接下来通过一个案例来演示final修饰成员变量的情况。
案例4:

//定义Student类
class Studtent {
    final String name;                      //使用final关键字修饰name属性
    //定义introduce方法,打印学生信息
    public void introduce() {
        System.out.println("我是一个学生,我叫"+name);
    }
}
//定义测试类
public class Example4 {
    public static void main(String[] args) {
        Student stu=new Student();          //创建Student类的实例对象
        stu.introduce();                    //调用Student的introduce()方法
    }
}

案例4中,出现了编译错误,提示变量name没有初始化。这是因为使用final关键字修饰成员变量时,虚拟机不会对其进行初始化。因此使用final修饰成员变量时,需要在定义变量的同时赋予一个初始值

final String name="李芳"                    //为final关键字修饰的name属性赋值

抽象类和接口

1、抽象类

当定义一个类时,常常需要定义一些方法来描述该类的行为特征,但有时这些方法的实现方式是无法确定的。例如前面在定义Animal类时,shout()方法用于表示动物的叫声,但是针对不同的动物,叫声也是不同的,因此在shout()方法中无法准确描述动物的叫声。
针对上面描述的情况,Java允许在定义方法时不写方法体,不包含方法体的方法为抽象方法,抽象方法必须使用abstract关键字来修饰,具体示例如下:

abstract void shout();          //定义抽象发放shout()

当一个类中包含了抽象方法,该类必须使用abstract关键字来修饰,使用abstract关键字修饰的类为抽象类,具体示例如下:

//定义抽象类Animal
abstract class Animal {
    //定义抽象方法shout()
    abstract int shout();
}

在定义抽象类时需要注意,包含抽象方法的类必须声明为抽象类,但抽象类可以不包含任何抽象方法,只需使用abstract关键字来修饰即可。另外,抽象类是不可以被实例化的,因为抽象类中有可能包含抽象方法,抽象方法是没有方法体的,不可以被调用。如果想调用抽象类中定义的方法,则需要创建一个子类,在子类中将抽象类中的抽象方法进行实现。
案例5:

//定义抽象类Animal
abstract class Animal {
    //定义抽象方法shout()
    abstract void shout();
}
//定义Dog类继承抽象类Animal
class Dog extends Animal {
    //实现抽象方法shout()
    void shout() {
        System.out.println("汪汪……");
    }
}
//定义测试类
public class Example5 {
    public static void main(String[] args) {
        Dog dog=new Dog();           //创建Dog类的实例对象
        dog.shout();                 //调用Dog对象的shout()方法
    }
}

从运行结果看,子类实现了父类的抽象方法后,可以正常进行实例化,并通过实例化对象调用方法。


2、接口

如果一个抽象类中所有的方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口。在定义接口时,需要使用interface关键字来声明,具体示例如下:

interface Animal {
    int ID=1;               //定义全局常量
    void breathe();         //定义抽象方法
    void run();
}

上面的代码中,Animal即为一个接口。从示例中会发现抽象方法breathe()并没有使用abstract关键字来修饰,这是因为接口中定义的方法和变量都包含了一些默认的修饰符。接口中定义的方法默认使用“public abstract”来修饰,即抽象方法。接口中的变量默认使用“public static final”来修饰,即全局变量。
由于接口中的方法都是抽象方法,因此不能通过实例化对象的方式来调用接口中的方法。此时需要定一个类,并使用implements关键字实现接口中的所有方法。
案例6:

//定义了Animal接口
interface Animal {
    int ID=1;                  //定义全局常量
    void breathe();            //定义抽象方法breathe()
    void run();                //定义抽象方法run()
}
//Dog类实现了Animal接口
class Dog implements Animal {
    //实现breathe()方法
    public void breathe() {
        System.out.println("狗在呼吸");
    }
    //实现run()方法
    public void run() {
        System.out.println("狗在跑");
    }
}
//定义测试类
public class Example6 {
    public static void main(String[] args) {
        Dog dog=new Dog();     //创建Dog类的实例对象
        dog.breathe();         //调用Dog类的breathe()方法
        dog.run();             //调用Dog类的run()方法
    }
}

从运行结果看,类Dog在实现了Animal接口后是可以被实例化的。
案例6演示的是类与接口之间的实现关系,在程序中,还可以定义一个接口使用extends关键字去继承另一个接口,接下来对案例6稍加修改,演示接口之间的继承关系。
案例7:

//定义Animal类
interface Animal {
    int ID=1;                  //定义全局常量
    void breathe();            //定义抽象方法breathe()
    void run();                //定义抽象方法run()
}
//定义了LandAnimal接口,并继承了Animal接口
interface LandAnimal extends Animal {
    void liveOnland();         //定义抽象方法liveOnland()
}
//定义Dog类实现LandAnimal接口
public class Dog implements LandAnimal {
    //实现breathe()方法
    public void breathe() {
        System.out.println("狗在呼吸");
    }
    //实现run()方法
    public void run() {
        System.out.println("狗在跑");
    }
    //实现liveOnland()方法
    public void liveOnland() {
        System.out.println("狗生活在陆地");
    }
}
//定义测试类
public class Example7 {
    public static void main(String[] args) {
        Dog dog=new Dog();     //创建Dog类的实例对象
        dog.breathe();         //调用Dog类的breathe()方法
        dog.run();             //调用Dog类的run()方法
        dog.liveOnland();      //调用Dog类的liveOnland()方法
    }
}

案例7中,定义了两个接口,其中LandAnimal接口继承了Animal接口,因此LandAnimal接口包含了三个抽象方法。当Dog类实现了LandAnimal接口时,需要实现两个接口中定义的三个方法

总结如下:

  • 接口中的方法都是抽象的,不能实例化对象
  • 当一个类实现接口时,如果这个类是抽象类,则实现接口中的部分方法既可,否则需要实现接口中的所有方法
  • 一个类通过implements关键字实现接口时,可以实现多个接口,被实现的多个接口之间要用逗号隔开。
    具体示例如下:
interface Run {
    程序代码……
}
interface Fly {
    程序代码……
}
class Bird implements Run,Fly {
    程序代码……
}
  • 一个接口可以通过extends关键字继承多个接口,接口之间用逗号隔开。
    具体示例如下:
interface Running {
    程序代码……
}
interface Flying {
    程序代码……
}
interface Eating extends Running,Flying {
    程序代码……
}
  • 一个类在继承另一个类的同时还可以实现接口,此时extends关键字必须位于implements关键字之前。
    具体示例如下:
class Dog extends Canidae implements Animal {
    //先继承再实现
    程序代码……
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值