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 {
//先继承再实现
程序代码……
}