final,见名知意,就是最终的意思,那么它在java中可以修饰什么呢?又有什么作用呢?

一、final的使用

在java中,final可以修饰变量,方法,类。

1.1 final修饰变量

当变量被final修饰时,那么此时的变量也就称之为常量。当一旦final修饰的变量被初始化后,那么值(数值和引用地址值)将不能再被改变。

1.1.1 final修饰成员变量

当final修饰成员变量时,必须要显式初始化,也就是你必须要给它赋个值。

final在java中是什么意思 final在java的作用_初始化


那么有哪些方式可以赋值呢?

1.1.1.1 成员变量为基本类型时

当成员变量为基本类型时,那么此时被final修饰的它们,一旦初始化后,数值将不可改变。

public class Demo {
    public static void main(String[] args) {
        Box b1=new Box();
        System.out.println(b1);
        System.out.println("=================");
        Box b2=new Box(20);
        System.out.println(b2);
    }
}

class Box{
    //Variable 'length' might not have been initialized
    //final int length;
    //一般对于常量,我们都全大写表示,为了演示方便,就不用了
    //final int LENGTH=0;

    final int length=5;  //声明时初始化
    final int width;     //代码块中初始化
    final int height;    //构造器初始化

    {
        //Cannot assign a value to final variable 'length':不能将值赋给最终变量length
        //length=10;
    }

    //代码块初始化
    {
        width=10;
    }

    public Box() {
        this.height = 15;
    }

    public Box(int height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Box{" +
                "length=" + length +
                ", width=" + width +
                ", height=" + height +
                '}';
    }
}

输出:

Box{length=5, width=10, height=15}
=================
Box{length=5, width=10, height=20}

通过上例代码,我们可以发现,当成员变量被final修饰时,我们可以通过声明初始化,代码块,构造器,为final修饰的成员变量进行赋值初始化操作,而在初始化后值将不能再改变

1.1.1.2 成员变量为引用类型
class Duck{
    private String name;

    public Duck() {
    }

    public Duck(String name) {
        this.name = name;
    }
}

class Dog {
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    //getter方法
    public String getName() {
        return name;
    }
}

class Cat {
    private String name;

    public Cat(String name) {
        this.name = name;
    }

    //getter方法
    public String getName() {
        return name;
    }
}

class Mouse {
    private String name;

    public Mouse(String name) {
        this.name = name;
    }

    //getter和setter方法
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Box {
    Duck duck=new Duck();
    final Dog dog = new Dog("Speike");  //声明初始化
    final Cat cat;       //代码块初始化
    final Mouse mouse;   //构造器初始化

    //代码块初始化
    {
        cat = new Cat("Tom");
    }

    //代码块初始化
    {
        duck=new Duck("唐老鸭");
        //Variable 'dog' might already have been assigned to
        //dog = new Dog("大黄");  //编译不通过
    }

    //无参构造初始化
    public Box() {
        mouse = new Mouse("Jerry");
    }

    //有参构造初始化
    public Box(Mouse mouse) {
        this.mouse = mouse;
    }

    @Override
    public String toString() {
        return "Box{" +
                "dog地址值:" + System.identityHashCode(dog) +
                ",dog值:" + dog.getName() +
                ", cat地址值:" + System.identityHashCode(cat) +
                ", cat值:" + cat.getName() +
                ", mouse地址值:" + System.identityHashCode(mouse) +
                ", mouse值:" + mouse.getName() +
                '}';
    }
}

public class Demo {
    public static void main(String[] args) {

        Box box=new Box();
        System.out.println(box);
        System.out.println("========================================分割线==============================================");

        Mouse mouse = new Mouse("米老鼠");
        Box b1 = new Box(mouse);
        System.out.println("修改前:"+b1);
        //修改mouse的值
        mouse.setName("杰瑞");
        System.out.println("修改后:"+b1);



    }
}

输出:

Box{dog地址值:460141958,dog值:Speike, cat地址值:1163157884, cat值:Tom, mouse地址值:1956725890, mouse值:Jerry}
========================================分割线==============================================
修改前:Box{dog地址值:356573597,dog值:Speike, cat地址值:1735600054, cat值:Tom, mouse地址值:21685669, mouse值:米老鼠}
修改后:Box{dog地址值:356573597,dog值:Speike, cat地址值:1735600054, cat值:Tom, mouse地址值:21685669, mouse值:杰瑞}

在上例中,我们在Box中初始化无final修饰的Duck和有final修饰的Dog,Cat,Mouse。通过比较我们可以发现,final修饰的引用类型的成员变量亦是可以通过声明,代码块,构造器进行初始化,并且比较Duck和Dog后,还可以发现,final修饰的引用类型的成员变量在第一次初始化后,不可以被再次赋值,而Duck没被final修饰,则没有此限制。
接着我们在main方法中创建了一个mouse对象和b1对象,然后我们打印了下b1对象,接下了我们修改了mouse的name值,接着再次进行打印。比较一下修改前后的打印的值,发现在将mouse值由米老鼠修改成杰瑞时,他们的mouse对象的地址值并没有改变。由此我们可以确认,final修饰引用类型的成员变量时,在将它们初始化后,将不能再指向其他对象,但它们所指向对象的内容却是可以修改的。

1.1.2 final修饰局部变量

当使用final修饰局部变量时,在初始化后,将不可给它们再次赋值,也就是说,在第一次赋值后,它们的值(无论是数值还是地址值)都将不能改变。

1.1.2.1 局部变量类型为基本类型
public class Demo{
    public static void main(String[] args) {
        Box box=new Box();
        box.show(10);
    }
}

class Box{

    public void info(){
        final int ID=10;
        //ID=10; //Cannot assign a value to final variable 'ID'
    }

    public void show(final int price){
        //Cannot assign a value to final variable 'price'
        //price=10;
        System.out.println(price);
    }

}

输出:

10

通过上例,我们可以发现在final修饰基本类型的局部变量(参数列表也是局部变量)时,数值在第一次赋值后将不能再被改变。

1.1.2.2 局部变量类型为引用类型
class Box {

    public void info() {
        final Gift gift=new Gift();
        //Cannot assign a value to final variable 'gift'
        //gift=new Gift();
    }

    public void showFinal(final Gift gift){
        //Cannot assign a value to final variable 'gift'
        //gift=new Gift();
        System.out.println(gift);
    }

    public void show(Gift gift){
        gift=new Gift();
        System.out.println(gift);
    }

}

在上例,final修饰的引用类型的局部变量在初始化后,会发现不能改变它们指向的引用地址值了。

1.2 final修饰方法

当方法被final所修饰时,那么这个方法不能被重写(覆盖)

class Animal{

    final void info(){

    }
}

class Cat extends Animal{

    //'info()'cannot override 'info()'in 'Animal';overridden method is final
    //info()方法不能被重写
//    void info() {
//        super.info();
//    }
    
}

1.3 final修饰类

当类被final所修饰时,那么这个不会被其他类所继承

public class Demo {
    public static void main(String[] args) {
        Animal cat=new Animal();
        cat.name="Tom";
        cat.info();
    }
}

final class Animal{
    String name;
    final int age=1;

    void info(){
        System.out.println(name+":"+age+"岁");
    }
}
//Cannot inherit from final 'Animal'  //无法继承最终类A
//class Cat extends Animal{
//
//}

输出:

Tom:1岁

上述代码中,当类Animal被final修饰后,Cat类将不可以继承Animal类,这时编译是不会通过的,理所当然的,既然类不能被继承,那么类中的方法自然也不会被重写(覆盖)。对于属性name,age可以发现在最终类Animal中,属性可以为final所修饰,也可以不被final修饰。

在java中也有许多类被final修饰,比如说:String类,System类等等。它们都不能被继承。

final在java中是什么意思 final在java的作用_成员变量_02

二、总结

通过以上可以总结出:
final可以修饰变量,方法,类
final修饰变量时,此时的变量被称为常量。当变量经过初始化后,它们的数值或者引用地址值是不能再次改变的。

  • final修饰成员变量:成员变量为基本数据类型时,在初始化后,就不能改变数值了。成员变量为引用数据类型时,在初始化后,成员变量就不能指向其他的对象了。对于初始化,成员变量可以通过声明初始化,代码块初始化,构造器初始化三种方式
  • final修饰局部变量:局部变量在初始化后,它的数值或引用地址值将不能改变。

final修饰方法:当方法被final修饰时,将不能被重写。
final修饰类:当类被final修饰时,将不能被继承,而由此方法也必定不会被重写

最后:static关键字可以和final连用。可以用来修饰属性和方法()。
当修饰属性时,此时变量为全局常量,并且它在类的加载时就会初始化。