static 和 final 和 static final

原创
2021/03/02 16:11
阅读数 248

众所周知,static(实例化,全局) 是静态修饰关键字:可以修饰变量,程序块,方法,类。

1.修饰变量。(该变量就与对象无关,所有对该变量的引用都指向同一个地址)

属性随着类的加载而加载,是类变量,其加载早于对象,不需要new即可加载

类变量所在的类的所有对象共用这一个属性,存放在静态域中

得知:如果static修饰的是变量,则JVM会将将其分配在内存堆上,该变量就与对象无关,所有对该变量的引用都指向同一个地址。

因此我们使用该变量的时候,直接指明类的静态变量,当然修饰符必须 public

1 public class StaticBean {
2     public static String A = "A";
3 }

使用方式

1 public static void main(String[] args) throws Exception{
2         System.out.println(StaticBean.A);
3     }

2.修饰程序块,猜猜输出结果是什么?。(用于系统初始化)

1 public class BaseTest {
 2     
 3     static{
 4         System.out.println("B");
 5     }
 6 
 7     public static void main(String[] args) throws Exception{ 8  System.out.println("A"); 9  } 10 }

结论:JVM就会优先加载静态块中代码,因此会优先输出B,static 修饰代码块,这主要用于系统初始化。

B
A

3.修饰方法:(类方法,加载早于对象,不需要new)

方法随着类的加载而加载随着类的加载而加载,是类方法,其加载早于对象,不需要new

类方法所在的类的所有对象共用这一个方法.

类方法内部只可调用静态的属性和静态的方法,而不能调用非静态的属性和方法
反之,非静态方法可以调用静态的属性和方法

在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象,静态方法在访问本类的成员时,只允许访问静态成员,而不允许访问实例成员变量和实例方法。

 
public class StaticBean {
    public static String A = "A";
    public String D;
    public static void getMessage(){
        System.out.println(A);
        System.out.println(D);
    }
}

上面代码,哪句是错误的,很显然。

System.out.println(D);

4.修饰类。在我们的熟知之中,static 修饰符一般用于修饰变量,程序块,方法,但是什么时候使用static来修饰类呢?(只能修饰内部类,)

普通类是不允许声明为静态的,只有内部类才可以

被static修饰的内部类可以直接作为一个普通类来使用,而不需实例一个外部类

内部类。如果在外部类声明为static,程序会编译都不会过。

内部类特点如下:

那就很简单引出,什么时候会使用静态内部类呢? 我们来看下以下一个例子

1 public class Outer {
 2     private int i = 0;
 3 
 4     public Outer() {
 5         i++;
 6         System.out.println("=====init Outer "+i+"===="); 7 8  } 9 10 public static Outer getInstance(){ 11 return Inner.INSTANCE; 12  } 13 //静态内部类 14 public static class Inner{ 15 private static final Outer INSTANCE = new Outer(); 16  } 17 }

调用方

1 public class BaseTest {
2     public static void main(String[] args) throws Exception{
3         for(int i = 0; i < 1000;i++) {
4             Outer.getInstance();
5  } 6  } 7 }

输出结果:

=====init Outer 1====

我们总结下:

由于 INSTANCE 是常量,因此只能赋值一次;它还是静态的,因此随着内部类一起加载,这种也是单例懒汉模式的一种实现方式,同时保证了线程安全。

 

final 关键字可以用来修饰类,方法和变量

1.修饰类

表示该类不允许被继承,final类中的成员方法都会被隐式的指定为final方法。

public final class FinalBean {

    public  void test(){

    }
}

2.修饰方法

表示该方法不能被重写,一个类的private方法会隐式的被指定为final方法。

以下例子SunFinalBean的test方法报错。

public class FinalBean {

    public final void test(){

    }

    public class SunFinalBean extends FinalBean{
        public void test(){
            
        }
    }
}

3.修饰变量

表示该变量必须初始化,且值不能改变。如果是基本类型则值不能改变,如果是引用类型,则引用地址不能改变,但是这个引用所指向的对象里面的内容还是可以改变的。

 猜猜看,以下那句通不过编译器编译。

public class FinalBean {
    private final int i = 0;
    private final int j;
    private final String name = "";

    public FinalBean(){ j = 1; this.name.concat("123"); this.name = "123"; } }

这句,记住final的原理即可理解,那为什么this.name.concat("123");不会报错呢,因为底层实现是返回一个新的String对象

this.name = "123";

 

那static final 一起用:

static修饰的属性强调它们只有一个,final修饰的属性表明是一个常数(创建后不能被修改)。static final修饰的属性表示一旦给值,就不可修改,并且可以通过类名访问。

static final也可以修饰方法,表示该方法不能重写,可以在不new对象的情况下调用。

展开阅读全文
打赏
1
0 收藏
分享
加载中
好文
2021/03/08 14:48
回复
举报
更多评论
打赏
1 评论
0 收藏
1
分享
返回顶部
顶部