Java 开发中static 和 final 关键字

我们在Java 开发中大量使用staticfinal关键字,面试中也经常被提到.下面就这两个关键字的用法进行讲解.

static关键字

通常我们在下述两种情况下用static :
1.只想为特定域分配单一存储空间,而不考虑究竟要创建多少对象,甚至不创建任何对象.
2.希望某个方法不与包含他的类的对象关联在一起.即使没有创建对象也能够调用这个方法.
那么这两句话的含义是啥呢,我们还是来看一个示例.

static 修饰字段:

public class StaticTest {
    static int i =26;
    public static void main(String[] args){
        StaticTest st1 = new StaticTest();
        StaticTest st2 = new StaticTest();
        System.out.println(st1.i);
        System.out.println(st2.i);
    }

}

输出结果:
26
26

上面这个结果是大家都可以猜到的,接着我们让st1.i 或st2.i 自增,看一下输出结果.

public class StaticTest {
    static int i =26;
    public static void main(String[] args){
        StaticTest st1 = new StaticTest();
        StaticTest st2 = new StaticTest();
        st1.i++;
        System.out.println(st1.i);
        System.out.println(st2.i);
    }
}
输出结果:
27
27

大家看出区别了吧,static 字段对每个类来说都只有一份存储空间 StaticTest 中的i 变量占据了单一的存储空间,保证了创建多个StaticTest 对象时, 变量i 也只有一份. st1.i和st2.i指向了同一个存储空间.

static 修饰方法:

一句话,没有创建对象,也能使用该类中的方法.这里就不贴代码了.
static 是不是很简单,下面我们看final 关键字,讲解的过程中会穿插着用一下static 关键字


final 关键字

final 关键字的意思是 “这里是无法改变的”,下面我们会讨论被final 修饰的三种情况.

1.fianl 修饰”数据”

我们开发的时候可能希望数据是恒定不变的,比如:
1.一个永不改变的编译时常量.
2.一个在运行时被初始化的值,而你不希望它被改变.
当对基本类型时,final 使数值恒定不变,而应用于对象引用,final 使引用恒定不变,但是对象自身确实可以被修改的.
下面的示例示范了final 修饰数据的情况.

package com.example;
import java.util.Random;
public class FinalData {
    private static Random rand = new Random(47);
    private String id;
    public FinalData(String id){
        this.id = id;
    }
    private final int valueOne = 9;
    private static final int VALUE_TWO = 99;
    public  static final int VALUE_Three = 39;
    private  final int i4 = rand.nextInt(20);
    static final  int INT_5 =rand.nextInt(20);
    private Value v1 = new Value(11);
    private final Value v2 = new Value(11);
    private static final Value VAL_3 = new Value(33);
    private final int[]  a = {6,5,4,3,2,1};
    public String toString(){
        return id+": "+i4+", INT_5=" + INT_5;
    }
    public static void main(String[] args){
        FinalData fd1 = new FinalData("fd1");
        fd1.v2.i++;
        fd1.v1 = new Value(9);
        for(int i=0;i<fd1.a.length;i++){
            fd1.a [i]++;
            //fd1.v2 = new Value(0);//  error
            //fd1.VAL_3 = new Value(1);// error
            //fd1.a = new int[3]; //error
        }
        FinalData fd2 = new FinalData("fd2");
        System.out.println(fd1);
        System.out.print(fd2);
    }
}
class  Value{
    int i;
    public Value(int i){
        this.i =i;
    }
}
输出结果:
fd1: 15, INT_5=18
fd2: 13, INT_5=18

代码中无法通过编译器检测的我已经在注释中标上了大大的error.原因就是上面提到的被fianl 修饰过的引用,一旦被初始化指向一个对象,就没有办法把它改为指向另一个对象了, 好专一啊………..
专一的人是不是都被final 修饰过~~~ 有点扯远了
我们还需要注意一个细节,当我输出i4 和 INT_5 ,一个没有被static 修饰过一个被修饰过,没有被修饰的,两个对象,两个不同的值.被static修饰过 在类中只有一份,同时又是不可以修改的,因此一但被赋值,也就不会改变了.

空白final:
允许刚开始时,被final 修饰的变量不用初始化,但后面使用的时候一定要初始化.

package com.example;
/**
 *  blank final
 */
public class BlankFinal {
    private  final int i= 0;
    private  final int j;
    private  final Poppet p;
    public BlankFinal(){
        j=1;
        p =new Poppet(1);
    }
    public BlankFinal(int x){
        j=x;
        p=new Poppet(x);
    }
    public static void main(String[] args ){
        new BlankFinal();
        new BlankFinal(26);
    }
}
class  Poppet{
    private  int i;
    Poppet(int ii){
        i = ii;
    }
}

final修饰参数
fianl 修饰的参数,无法在方法中更改参数引用所指向的对象.

public final class People {
  public void swim(){}
}
 class Animail{
  void with(final People people){
    // people = new People();//error
  }
}

final 修饰方法

被final 修饰过的方法,子类是无法覆盖的,需要注意的一点private 修饰方法都隐式的指定为方法 添加了final .下面的代码有点迷惑性.

public class withFinals {
     private final void f(){
        System.out.println("withFinals.f()");
    }
    // automatically add fianl
     private void g(){
        System.out.println("widthFinals.g()");
    }
  } 
    class OverringPrivate extends  withFinals{
         private final void f(){
            System.out.println("OverringPrivate.f()");
        }
        private  final void g(){
            System.out.println("OverringPrivate.g()");
        }

    }
    class OverringPrivate2 extends  OverringPrivate{
        public final void f(){
            System.out.println("OverringPrivate2.f()");
        }
        public final  void g(){
            System.out.println("OverringPrivate2.g()");
        }
    }
    class FinalOverridingIllusion{
        public static void main(String[] args){
            OverringPrivate2 op2 = new OverringPrivate2();
            op2.f();
            op2.g();
            OverringPrivate op = op2;
           // op.f(); error
           // op.g(); error
            withFinals wf = op2;
           // wf.f(); error
           // wf.g(); error

        }
    }

方法貌似被”覆写”了,其实不然,覆写的概念: “只有非private 方法才能被覆写”,对于private 修饰的方法是没有覆写这个概念的.可以把它看做是隐藏在类中的程序代码,只不过具有相同的名字而已! 好坑啊~~

final 修饰类

也是一句话,被final 修饰过得类,就表明该类是无法继承的,子类是无法继承和覆写.这里我们就不贴代码了,大家可以写个代码测一下.

ok 这两个关键字就介绍到这里,相信你再次使用它们的时候,会有更加清晰的认识.

参考文章:

thinking in java

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值