Static和Final修饰类属性变量及初始化(转载)

本文详细解析Java中final和static修饰符的使用场景及限制条件,包括属性初始化规则、内存分配特性以及类加载过程中的表现。
1.static修饰一个属性字段,那么这个属性字段将成为类本身的资源,public修饰为共有的,可以在类的外部通过test.a来访问此属性;在类内部任何地方可以使用.如果被修饰为private私有,那么只能在类内部使用.
  public class Test{
public static int a;
private Test(){
a=0;
}
}
  如果属性被修饰为static静态类资源,那么这个字段永远只有一个,也就是说不管你new test()多少个类的对象,操作的永远都只是属于类的那一块内存资源.例如:
  Test t1=new Test();
t1.a=10;
Test t2=new Test();
System.out.println(t1.a);
System.out.println(t2.a);
System.out.println(Test.a);
  结果是3个0
  2.final 用于声明属性,方法和类,分别表示属性一旦被分配内存空间就必须初始化并且以后不可变,方法一旦定义必须有实现代码并且子类里不可被覆盖,类一旦定义不能被定义为抽象类或是接口,因为不可被继承。
  而你的代码里对final修饰的属性进行了修改,所以错误.
  3. 被final修饰而没有被static修饰的类的属性变量只能在两种情况下初始化:
  a.在它被定义的时候,例:
  public class Test{
public final int a=0;
private Test(){
}
}
  b.在构造函数里初始化,例:
  public class Test{
public final int a;
private Test(){
a=0;
}
}
  4.同时被final和static修饰的类的属性变量只能在两种情况下初始化:
  a.在它被定义的时候,例:
  public class Test{
public final int a=0;
private Test(){
}
}
  b.在类的静态块里初始化,例:
  public class Test{
public final int a;
static{
a=0;
}
}
  5.分析第三第四原因:
  第三条:当这个属性被修饰为final,而非static的时候,它属于类的实例对象的资源,当类被加载进内存的时候这个属性并没有给其分配内存空间,而只是定义了一个变量a,只有当类被实例化的时候这个属性才被分配内存空间,而实例化的时候同时执行了构造函数,所以属性被初始化了,也就符合了当它被分配内存空间的时候就需要初始化,以后不再改变的条件.
  第四条:当类的属性被同时被修饰为static和final的时候,他属于类的资源,那么就是类在被加载进内存的时候(也就是应用程序启动的时候)就要已经为此属性分配了内存,所以此时属性已经存在,它又被final修饰,所以必须在属性定义了以后就给其初始化值.而构造函数是在当类被实例化的时候才会执行,所以用构造函数,这时候这个属性没有被初始化.程序就会报错.而static块是类被加载的时候执行,且只执行这一次,所以在static块中可以被初始化.
 
————————————————————————————————————————————————
令一篇文章解释:
 
看languageSpec,上说,final变量的初始化分三种情况:
共性:
1。final在初始化之后,就不能再赋值了,也就是说,它们只能被赋值一次
2。一般情况下是定义时直接初始化如:final int i=3;
但也可以定义时不初始化,叫blank final,如 final int bi;
然后留待后面进行赋值。但这因三种情况而不同:
1。普通auto变量(就是如方法中的局部变量):可以在其后的代码中赋值,
但也可以不赋值。
final int i;//blank final
anything();
i=1;//在其后赋值。
//i=3; error!不可再次赋值

而成员变量必须被赋值,只是赋值的地方不同:
2。静态成员变量:
静态成员变量必须在静态构造代码中初始化,
static final int s;
static { s=3;}//静态构造块
//static final int s; error!

3。非静态成员变量:
必须在构造函数中被赋值。如:
final int ai;
{ ai = 3; }//这种叫什么的,估且称之为实例初始化块吧(instance
initializer)
public Contructor(){ai=3;}//构造函数中
public Contructor(int in){ai=in;}//构造函数中

注意构造函数可以会有互相调用,注意在这过程中不要使变量被重复的赋值。

另外,如果变量是对象或数组这样的引用类型。则可以操作其对象或数组,但不可以
改变引用本身:
final int [] array={1,2,3};//一个由三个数字组成的数组。
array[1]=9;//array == {1,9,3}
// array=new int[6]; error!
### Java 中 `final` 修饰变量为什么必须被初始化 `final` 修饰变量在 Java 中表示其值不可更改,因此必须确保其在使用前具有明确的值。这种要求是 Java 语言规范中的一部分,旨在保证变量在访问之前具有一个确定的状态。对于不同作用域的 `final` 变量初始化的要求方式有所不同。 #### 局部变量 当 `final` 修饰的是局部变量时,必须在使用之前显式赋值一次,否则编译器会报错。这是因为局部变量没有默认值,且其作用域仅限于方法内部,无法通过其他方式隐式赋值。例如: ```java void method() { final int localVar; // System.out.println(localVar); // 编译错误:变量尚未初始化 localVar = 5; // 使用前初始化 System.out.println(localVar); } ``` 这种设计确保了局部变量在使用时始终具有一个明确的值,避免了未定义行为的发生[^4]。 #### 成员变量(字段) 对于类的成员变量,如果被 `final` 修饰,则必须在对象构造完成之前完成初始化。具体来说,初始化可以通过以下两种方式之一完成: 1. **显式赋值**:在声明时直接赋值,例如 `private final int x = 1;`。 2. **构造器初始化**:在构造函数中为 `final` 字段赋值。这种方式适用于需要根据构造参数动态决定最终值的场景。 ```java public class Demo01 { private final int a; public Demo01() { a = 3; // 构造函数中初始化 } } ``` 如果一个 `final` 成员变量在声明时没有赋值(即“空白 final”),则必须在构造器或初始化块中赋值,否则编译失败[^2]。 #### 静态成员变量 对于 `static final` 修饰变量(静态常量),初始化规则与实例变量类似,但要求在类加载时完成初始化。静态变量可以通过以下方式初始化: - 在声明时直接赋值。 - 在静态代码块中赋值。 ```java public class StaticFinalExample { private static final int VALUE; static { VALUE = 42; // 静态代码块中初始化 } } ``` 这种设计确保了静态常量在类加载完成后即具有确定的值,避免了并发访问时的不确定性[^3]。 #### 为什么必须初始化 `final` 变量必须初始化的根本原因在于其不可变性。Java 要求 `final` 变量一旦赋值,就不能再改变,因此必须保证其在使用前具有一个合法的初始值。如果允许未初始化的 `final` 变量存在,则可能导致访问到未定义的值,破坏程序的稳定性可预测性。 此外,Java 的内存模型编译器优化机制依赖于变量初始化状态。未初始化的 `final` 变量会破坏这些机制,导致诸如指令重排序、内存可见性等问题。因此,Java 强制要求所有 `final` 变量在使用前必须被明确初始化[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值