Bootstrap

Java final 关键字

目录

1.1 final 关键字

1.1.1 final关键字修饰类

1.1.2 final关键字修饰方法

1.1.3 final关键字修饰变量

1.2 抽象类和接口

1.2.1 抽象类

1.2.2 接口

2.1 总结

2.1.1 final 关键字总结

2.2.1 抽象类总结

2.2.2 接口总结


1.1 final 关键字

        final 的英文意思是“最终”。在 Java 中,可以使用nal 关键字声明类、属性、方法,在声明时需要注意以下几点。
        (1)使用 final 修饰的类不能有子类。
        (2)使用 final 修饰的方法不能被子类重写
        (3)使用  final 修饰的变量(成员变量和局部变量)是常量,常量不可修改
        下面将对 fnal 的用法逐一进行讲解。

1.1.1 final关键字修饰类

        Java 中的类被 final 关键字修饰后,该类将不可以被继承,即不能派生子类。下面通过一个案例进行验证,如下代码所示。

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

        编译上面代码,编译器报错,如下图所示。 

        上面代码中,第 2 行代码定义了 Animal 类并使用 final 关键字修饰,第 5~6 行代码定义了 Dog 类并继承Animal类。

        如上图所示,当 Dog 类继承使用 final 关键字修饰的 Animal类时,编译器报“无法从最终cn.itcast.Animal进行继承”错误,即不能继承使用 fnal 修饰的 Animal 类。由此可见,被 final 关键字修饰的类为最终类,不能被其他类继承。

1.1.2 final关键字修饰方法

        当一个类的方法被 final 关键字修饰后,这个类的子类将不能重写该方法。下面通过一个案例进行验证如下代码所示。

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

        编译以上代码,编译器报错,如下图所示。

        在上面代码中,第10行代码在 Dog 类中重写了父类 Animal 中的 shout ( )方法,编译报错。这是因为Animal类的 shout ( )方法被 final 修饰,而被 final 关键字修饰的方法为最终方法,子类不能对该方法进行写。因此,当在父类中定义某个方法时,如果不希望被子类重写,就可以使用 final 关键字修饰该方法。

1.1.3 final关键字修饰变量

        Java 中被 final 修饰的变量为常量,常量只能在声明时被赋值一次,在后面的程序中,其值不能被改变。如果再次对该常量赋值,则程序会在编译时报错。下面通过一个案例进行验证,如下代码 所示。

public class Example09{
    public static void main (String[]args) {
        final int AGE = 18;     //第一次可以赋值
        AGE = 20;               //再次赋值会报错
       }
}

        编译上面代码,编译器报错,如下图所示。

        在上面代码中,当第4行代码对 AGE 进行第二次赋值时,编译器报错。原因在于使用 final定义的常量本身不可被修改。 

注意:
        在使用 final 声明变量时,要求全部的字母大写。如果一个程序中的变量使用 public static final 声明,则此变量将成为全局常量,如下面代码所示。

public static final String NAME ="哈士奇";

1.2 抽象类和接口

1.2.1 抽象类

        当定义一个类时,常常需要定义一些成员方法描述类的行为特征,但有时这些方法的实现方式是无法确定的。例如,前面在定义 Animal 类时,shout ( )方法用于描述动物的叫声,但是不同动物的叫声是不同的,因此在 shout() 方法中无法准确地描述动物的叫声。
针对上面描述的情况,Java 提供了抽象方法来满足这种需求。抽象方法是使用 abstract 关键字修饰的成员方法,抽象方法在定义时不需要实现方法体。抽象方法的定义格式如下:

abstract 返回值类型 方法名称 (参数);

        当一个类包含了抽象方法,该类必须是抽象类。抽象类和抽象方法一样,必须使用 abstract 关键字进行修饰。

        抽象类的定义格式如下:

abstract class 抽象类名称{
    属性;
    访问权限 返回值类型 方法名称(参数){       //普通方法
        return [返回值];
    }
    访问权限 abstract 返回值类型 抽象方法名称(参数);    //抽象方法,无方法体
}

        从以上格式可以发现,抽象类的定义比普通类多了一些抽象方法,其他地方与普通类的组成基本上相同。
        抽象类的定义规则如下。
        (1)包含抽象方法的类必须是抽象类。
        (2)抽象类和抽象方法都要使用 abstract 关键字声明。
        (3)抽象方法只需声明而不需要实现。
        (4)如果一个非抽象类继承了抽象类,那么该子类必须实现抽象类中的全部抽象方法。

        下面通过一个案例学习抽象类的使用,如下代码所示。

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

        上面代码的运行结果如下图所示。

        在上面代码中,第 2~5 行代码是声明了一个抽象类Animal,并在 Animal 类中声明了一个抽象方法 shout ();第9~11行代码在子类 Dog 中实现父类 Animal 的抽象方法shout ( );第 17 行代码通过子类的实例化对象用 shout () 方法。

注意:
        使用 abstract 关键字修饰的抽象方法不能使用 private 修饰,因为抽象方法必须被子类实现,如果使用private 声明,则子类无法实现该方法。

1.2.2 接口

        如果一个抽象类的所有方法都是抽象的,则可以将这个类定义接口。接口是 Java 中最重要的概念之在JDK8 中,接口中除了可以包括抽象方法外,还可以包括默认方法和静态方法(也叫类方法 ,默认方使用 default 修饰,静态方法使用 static 修饰,且这两种方法都允许有方法体。
接口使用interface 关键字声明,语法格式如下:

public interface 接口名 extends 接口1,接口2...{
    public static final 数据类型 常量名 = 常量值;
    public abstract 返回值类型 抽象方法名称(参数列表);
}

        在上述语法中,“extends 接口 1,接口 2..”表示一个接口可以有多个父接口,父接口之间用逗号分隔。Java 使用接口的目的是克服单继承的限制,因为一个类只能有一个父类,而一个接口可以同时继承多个父口。接口中的变量默认使用“public static final”进行修饰,即全局常量。接口中定义的方法默认使用“public abstract”进行修饰,即抽象方法。如果接口声明为 public,则接口中的常量和方法全部为 public。

注意:
        在很多Java 程序中,经常看到编写接口中的方法时省略了 public,有很多读者认为它的访问权限是 default 这实际上是错误的。不管写不写访问权限,接口中方法的访问权限永远是 public。与此类似,在接口中定》常量时,可以省略前面的“public static final”,此时,接口会默认为常量添加“public static final”

        从接口定义的语法格式可以看出,接口中可以包含三类方法,分别是抽象方法、默认方法、静态方法,其中静态方法可以通过“接口名方法名”的形式来调用,而抽象方法和默认方法只能通过接口实现类的对象来调用。接口实现类的定义方式比较简单,只需要定义一个类,该类使用implements 关键字实现接口,并实现了接口中的所有抽象方法。需要注意的是,一个类可以在继承另一个类的同时实现多个接口,并目多个接口之间需要使用英文逗号 (,)分隔。
定义接口的实现类,语法格式如下:

修饰符 class 类名 implements 接口1,接口2,...{
    ...
}

        下面通过一个案例学习接口的使用,如下面代码所示。

// 定义接口Animal
interface Animal {
    int ID = 1;                        //定义全局常量
    string NAME ="牧羊犬";
    void shout();                      //定义抽象方法 shout ()
    static int getID() {
        return Animal.ID;
    }
    public void info();                //定义抽象方法 info ()
}
interface Action {
    public void eat ();                //定义抽象方法 eat ()
}
//定义 Dog 类实现 Animal 接口和 Action 接口
class Dog implements Animal,Action {
    //重写 Action 接口中的抽象方法eat ()
    public void eat () {
        System.out.printn ("喜欢吃骨头");
    }
    //重写 Animal 接口中的抽象方法 shout ()
    public void shout () {
    System.out.println ("汪汪......");
    }
    //重写 Animal 接口中的抽象方法 info ()
    public void info() {
        System.out.printIn ("名称:"+NAME);
    }
}
//定义测试类
class Example11 {
    public static void main (String[] args) {
        System.out.println ("编号"+Animal.getID ());
        Dog dog = new Dog ();                        //创建 Dog 类的实例对象
        dog.info ();
        dog.shout ();                                // 调用 Dog 类中重写的 shout() 方法
        dog.eat ();                                  // 调用 Dog 类中重写的 eat() 方法
    }
}

        上面代码的运行结果如下图所示。

        在上面代码中第2~10行代码定义了一个Animal接口,在Animal接口中定义了全局常量ID和NAME、抽象方法 shout ( )、info()和静态方法 getID ( )。第11~13 行代码定义了一个 Action 接口,在 Action 接口中定义了一个抽象方法 eat ( )。第 15~28 行代码定义了一个 Dog 类,Dog 类通过 implements 关键字实现了Animal 接口和 Action 接口,并重写了这两个接口中的抽象方法。第32行代码使用 Animal 接口名直接访问了Animal 接口中的静态方法 getID ( )。第 33~36行代码创建并实例化了 Dog 类对象 dog,通过 dog 对象访问了 Animal 接口和 Action 接口中的常量以及 Dog类重写的抽象方法。

        从上图中的运行结果可以看出,Dog 类的实例化对象可以访问接口中的常量、重写的接口方法和本类内部的方法,而接口中的静态方法则可以直接使用接口名调用。需要注意的是,接口的实现类,必须实现接口中的所有方法,否则程序编译报错。
        上面代码演示的是类与接口之间的实现关系,如果在开发中一个类既要实现接口,又要继承抽象类则可以按照以下格式定义类。

修饰符 class 类名 extends 父类名 implements 接口1,接口2,...{
    ...
}

        下面对上面的代码稍加修改,演示一个类既实现接口,又继承抽象类的情况。修改后的代码如下所示。

//定义接口Animal
interface Animal {
    public String NAME="牧羊犬";
    public void shout();                //定义抽象方法 shout()
    public void info();                 //定义抽象方法 info()
}
abstract class Action {
    public abstract void eat();         //定义抽象方法 eat()
}
//定义 Dog 类继承 Action 抽象类并实现 Animal 接口
class Dog extends Action implements Animal {
    //重写 Action 抽象类中的抽象方法eat ()
    public void eat() {
        System.out.println("喜欢吃骨头");
    }
    //重写 Anima1 接口中的抽象方法 shout()
    public void shout() {
        System.out.println("汪汪...");
    }
    //重写 Animal 接口中的抽象方法 info()
    public void info() {
        System.out.printIn("名称:"+NAME);
    }
}
//定义测试类
public class Example12 {
    public static void main(String[] args) {
        Dog dog = new Dog();             //创建 Dog类的对象
        dog.info();                      //调用 Dog类中重写的 info()方法
        dog.shout();                     //调用 Dog类中重写的 shout ()方法
        dog.eat();                       //调用 Dog类中重写的 eat()方法
    }
}                    

        在上面代码中,Dog 类通过 extends 关键字继承了 Action 抽象类,同时通过 implements 实现了 Animal 接口。因为 Animal 接口和 Action 抽象类本身都有抽象方法,所以 Dog 类中必须重写Animal 接口和 Action 抽象类中的抽象方法。
在 Java 中,接口是不允许继承抽象类的,但是允许一个接口继承多个接口。下面通过一个案例讲解接口的继承,如下面代码所示。

//定义接口 Animal
interface Animal {
    public String NAME = "牧羊犬";
    public void info () ;                        //定义抽象方法 info()
}
interface Color {
    public void black ();                        //定义抽象方法 black()
}
interface Action extends Animal,Color {
    public void shout ();                        //定义抽象方法 shout()
}
//定义 Dog 类实现 Action 接口
class Dog implements Action {
    //重写 Animal 接口中的抽象方法 info()
    public void info () {
        System.out.printIn ("名称: "+NAME);
    }
    //重写 Color 接口中的抽象方法 black()
    public void black () {
        System.out.println ("黑色");
    }
    //重写 Action 接口中的抽象方法 shout()
    public void shout () {
        System.out.println ("汪汗......");
    }
}
//定义测试类
class Example13 {
    public static void main (String[] args) {
        Dog dog = new Dog ();                    //创建 Dog 类的实例对象
        dog.info ();                             //调用 Dog 类中重写的 info() 方法
        dog.shout ();                            //调用 Dog 类中重写的 shout() 方法
        dog.black ();                            //调用 Dog 类中重写的 eat() 方法
    }
}

        上面代码的运行结果如下图 所示。

        从上面的代码可以发现第9~11代码定义了接口 Action 并继承接口 Animal 和 Color。这样接口  Action 中就同时拥有 Animal 接口中的 info() 方法和 Color 接口中的 black () 方法,以及本类中的 shout () 方法。在第13~26行代码定义了一个 Dog 类并实现了 Action 接口,这样 Dog 类就必须重写这 3 个抽象方法。

2.1 总结

2.1.1 final 关键字总结

  1. 不可继承:通过使用final关键字修饰类,可以阻止其他类对该类的继承。final类是最终的类,不允许其他类继承它。

  2. 安全性:final类可以提供更高的安全性,因为它不能被其他类继承和修改。这在一些情况下是非常有用的,特别是当你想确保类的行为和实现不会被修改时。

  3. 性能优化:final类对编译器来说是已知的,它可以进行一些额外的优化,例如内联方法调用等。这可能导致更好的性能。

  4. 设计意图:通过将类声明为final,可以清楚地表明这个类的设计意图是不可继承的。这有助于提高代码的可读性和可维护性,其他开发人员在使用该类时,能够更好地理解和遵循设计意图。

2.2.1 抽象类总结

  1. 无法实例化:抽象类不能直接创建对象,因为它存在抽象方法。只能通过继承抽象类来使用它,子类必须实现抽象类中的所有抽象方法才能被实例化。

  2. 包含抽象方法:抽象类中可以包含抽象方法,这些方法没有具体的实现,只有方法签名。子类必须实现抽象方法,提供具体的实现逻辑。

  3. 可以包含非抽象方法:抽象类不仅可以包含抽象方法,还可以包含非抽象方法,这些方法有具体的实现。子类可以继承这些非抽象方法,也可以重写它们。

  4. 提供了继承的模板:抽象类提供了一个继承的模板,可以定义一些通用的属性和方法,子类可以继承这些通用的部分,并在此基础上进行扩展和定制。

  5. 部分实现、部分延迟到子类:抽象类可以在其中实现一些通用的方法逻辑,而将一些特定的方法逻辑延迟到子类中去实现。这样可以提高代码的复用性和可维护性。

  6. 限制了类的层次结构:通过使用抽象类,可以限制类的层次结构,要求子类实现指定的抽象方法。这样可以确保子类在继承时必须满足一定的条件和规范。

2.2.2 接口总结

  1. 定义接口:接口使用interface关键字来定义,并且所有方法都是抽象的,不包含具体的实现,可以包含常量。

  2. 实现接口:一个类可以实现一个或多个接口,使用implements关键字来实现接口,并且必须实现接口中的所有方法。

  3. 多态性:通过实现接口,可以实现多态性。一个对象可以被赋值给其实现的接口类型,然后使用该接口来调用对象的方法。

  4. 规范性:接口定义了一组规范,所有实现该接口的类都必须遵循这些规范,提供相同的方法和常量。这有助于提高代码的可读性和可维护性。

  5. 松耦合:接口是松耦合的,因为它们在定义时不需要考虑实现的细节,只需要关注方法的签名和返回类型。这样可以使代码更加灵活和可扩展。

  6. 扩展性:通过添加新的接口,可以很容易地扩展系统的功能,只需要实现新的接口即可。

  7. JDK中的接口:Java中有很多内置的接口,例如Comparable、Iterable、Runnable等。这些接口提供了一些基本的功能和规范,可以在开发中直接使用。

;