试问Java中还有谁比final更有边界感?

final定义

中文意思:最后的,最终的

可以修饰类、属性、方法和局部变量

final的具体使用场景

在某些情况,程序员可能会有以下需求,就会使用到final关键字

  • 当不希望类被继承时,可以用final修饰
 //A类不想被B类继承,前面加个final,就可以实现A和B保持边界感
 final class A{
 ​
 }
 /*
 class B extends A{
 ​
 }*/
  • 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰
 //父类A中的核心方法不想被子类B重写,此时,将父类的核心方法用final修饰,就可以实现B类可远观而不可亵玩焉,
 class A {
     public final void growing() {
         System.out.println("父类特有的核心方法");
     }
 }
 class B extends A {
     /*@Override
     public void growing() {
         System.out.println("子类此时重写了父类的核心方法");
         super.growing();
     }*/
 }
  • 当不希望类的某个属性的值被修改,可以用final修饰
 public class Journey {
     public static void main(String[] args) {
    /*     A a = new A();
         a.sweat= 99.99;*/
     }
 }
 ​
 class A {
     //假使你比较笨,想实现一个目标需要付出比别人多0.01的汗水,但你摇摆不定,没有下定决心,
     //别人说差不多就好了,你就听之任之,付出了99.99的努力,然后停下来了,结果就是无功而返
     //此时用final修饰你的内心,持之以恒,那么谁也没法创建对象,扰你道心
     public final double sweat = 100.01;
 }
  • 当不希望某个局部变量被修改,可以使用final修饰
 public class Journey {
     public static void main(String[] args) {
         A a = new A();
         a.FeelHappy();//使劲玩就对了(没用final修饰时,会输出被二次修改后need的值)
     }
 }
 class A { 
     public  void FeelHappy(){
         //此中NEED起初被初始化后,如果不想再被二次修改,用final修饰它,就可以实现
         //这时候的NEED也被称为局部常量,不允许变化,用全大写来命名
         
         /**final String NEED = "你需要学会克制,降低自己的幸福阈值";
            NEED = "使劲玩就对了";
            System.out.println(NEED);*/
     }
 }

final的使用注意事项和相关细节 

final修饰的属性又叫常量,一般用XX_XX_XX来命名

final修饰的属性在定义时,必须赋初值,并且以后也不能再修改,赋值可以在以下位置之一(任选一个即可)

  • 定义时
  • 在构造器中
  • 在代码块中
 class A {
     public final double sweat = 100.01;
     //此时就会报错,因为常量必须给它赋初值
 //    public final double sweat2 ;
     //1.要么在定义时直接在后面赋初值
     public final double sweat2 = 100.02;
 ​
     //2.要么给它创建构造方法,在其中赋值
     public final double sweat3;
     public A() {
         sweat3 = 100.03;
     }
     //3.要么就给它创建代码块,在代码块中赋值
     public final double sweat4;
     {
         sweat4=100.04;
     }
 ​
 }

如果final修饰的属性是静态的,则初始化的位置只能是

  • 定义时
  • 在静态代码块中,不能在构造器中赋值
 class B{
     //同样,如果不初始化赋初值的话,以下语句会报错
 //    public static final double sweat ;
     //1.在定义时,直接在后面赋初值
     public static final double sweat2=100.02 ;
     //2.通过静态代码块来实现赋值
     public static final double sweat3;
     static {
         sweat3 = 100.03;
     }
     //尝试在构造器中给sweat4赋值,发现报错,
 ​
 //    public static final double sweat4;
 //    public B() {
     /** reason:
             构造器是在创建对象的时候,它才会被触发或者才会被调用,
             而静态变量的初始化是在类加载的时候就要给值,
             所以static类加载的时候你没给值,
             之后想去挽回再给值是不行滴
      */
 //        sweat4=100.04;
 //    }
 }

final类不能继承,但是可以实现实例化

 public class Journey {
     public static void main(String[] args) {
         //被final修饰了的C类,不能被继承,但是可以实现实例化
         C c = new C();
     }
 }
 final class C{
 ​
 }

如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承

 public class Journey {
     public static void main(String[] args) {
         //D类不是final类,但是有final方法say(),其不能被E重写,但是可以继承
         E e = new E();
         e.say();
     }
 }
 class D {
     public final void say() {
         System.out.println("hi!");
     }
 }
 class E extends D { }

一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法

final不能修饰构造方法(即构造器)

final和static往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理

 public class Journey {
     public static void main(String[] args) {
         //我这里想单纯使用下A的属性youth,不想让类加载,执行静态代码块的语句
         System.out.println(A.youth);
     }
 }
 class A{
     //这里如果不加final,就会类加载,执行静态代码块中的语句,然后静态属性youth才会被调用
     public final static int youth =659;
     static{
         System.out.println("A 的静态代码块被执行");
     }
 }
 ​
 输出结果如下
 A 的静态代码块被执行
 659

 包装类(Integer、Double、Float、Boolean等都是final),String也是final类,顺带看下源码哈

 //String
 public final class String{
                     ///此处省略几千行
 }
 //Integer
 public final class Integer extends Number implements Comparable<Integer> {
                     //此处也省略几千行//
 }
 //Double
 public final class Double extends Number implements Comparable<Double> {
                     //此处也省略几千行//
 }
 //Float
 public final class Float extends Number implements Comparable<Float> {
                     //此处也省略几千行//
 }
 //Boolean
 public final class Boolean implements java.io.Serializable,Comparable<Boolean>{
                     //此处也省略几千行//
 }

 相关练习(看到这儿的小伙伴可以试着做下,巩固学习成果)

 //Q1:编写程序,实现求圆的面积,将final在三个地方赋初值都呈现出来


//A1:
 public class Journey {
     public static void main(String[] args) {
         double area = new Circle(10.0).getArea();
         System.out.println("圆的面积是"+area);
     }
 }
 class Circle{
     private double Area  ;
     private double radius;
     //直接在定义时赋初值
     private final double PI3 = 3.14;
     private final double PI;
     //构造器中赋初值
 ​
     public Circle(double radius) {
         this.radius = radius;
         PI = 3.14;
     }
 ​
     //代码块中赋初值
     private final double PI2;
     {
         PI2 = 3.14;
     }
     public double getArea(){
         return radius*radius*PI;
     }
 ​
 }
 ​
 ​
 ​
 //Q2: 判断以下代码书写的错对,如有不当之处,指出并修改
 public class A{
     public int addOne(final int v){
         ++v;
         return v+1;
     }
 }


 //A2:正确结果
 public class A{
     public int addOne(final int v){//这儿也是没问题的
         ++v;//这儿是不可以这样书写的,reason:不能修改final v 的值
         return v+1;//这里没毛病,没有修改v的值
     }
 }

感谢铁子看完全文,我是尝试写博客记录自己成长的Java小白Kerwin,如若阅读过程中发现有表述不当之处或其他可改进的地方,还望指出,倘若我的博客分享能给任何一个素不相识的小伙伴带来一点帮助或鼓励,都是我的荣幸,铁子们,那就下一篇博客见啦,拜!!! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值