final修饰符

final修饰变量时,表示该变量一旦获得了初始值就不可改变,

由于final变量获得初始值之后不能被重新赋值,因此final修饰成员变量和修饰局部变量时有一定的不同。

5.4.1final成员变量

成员变量是随类初始化或对象初始化而初始化的,

类初始化时,系统会为该类的类变量分配内存,并分配默认值;

创建对象时,系统会为该对象的实例变量分配内存,并分配默认值。

java语法规定:final修饰的成员变量必须由程序员显式地指定初始值

归纳:

final修饰的类变量,实例变量 能指定初始值的地方:

类变量:

- 在静态初始化块中指定初始值

     final static int;
              static{
              i = 10;
              }
  • 声明该类变量时指定初始值
final static int i = 10;

实例变量:

- 非静态初始化块

 final int i;
 {
      i = 10;
}
  • 声明该实例变量
final int i = 10;
  • 构造器中指定初始值
public class FinalVariableTest{
    final int i;
    public FinalVariableTest(){
        i = 10;
        //如果在初始化块已经赋值,就不能在构造器中重新赋值
    }
}

实例变量不能在静态初始化块中指定初始值,因为静态初始化块是静态成员,不可访问实例变量——非静态成员类变量不能在普通初始化块中指定初始值,因为类变量在类初始化阶段已经被初始化了,普通初始化块不能对其重新赋值。

如果打算在构造器、初始化块中对final成员变量进行初始化,则不要在初始化之前就访问成员变量的值。

package code;
public class FinalErrorTest{
    final int age;
    {
        //System.out.println(age);
        age = 6;
        System.out.println(age);
    }
    public static void main(String [] args){
        new FinalErrorTest();
    }
}

I:>javac -d . FinalErrorTest.java

FinalErrorTest.java:5: 错误: 可能尚未初始化变量age

System.out.println(age);

^

1 个错误

5.4.2 final局部变量

package code;
public class FinalLocalVariable{
    public void test(final int a){
        //不能对final修饰的形参赋值,下面语句非法
        //a = 5;
    }
    public static void main(String[] args){
        //定义final局部变量时指定默认值,则str变量无法重新赋值
        final String str = "hello";
        //str = "java";
        final double d;
        d = 44.5;
        //d = 443.3;
    }
}

I:>javac -d . FinalLocalVariable.java

FinalLocalVariable.java:10: 错误: 无法为最终变量str分配值

str = “java”;

^

1 个错误

I:>javac -d . FinalLocalVariable.java

FinalLocalVariable.java:5: 错误: 不能分配最终参数a

a = 5;

^

FinalLocalVariable.java:13: 错误: 可能已分配变量d

d = 443.3;

^

2 个错误

因为形参在调用该方法,由系统根据传入的参数来完成初始化,因此使用final修饰的形参不能被赋值。

5.4.3 final修饰基本类型变量和引用类型变量的区别

package code;
import java.util.Arrays;
class Person{
    private int age;
    public Person(){}
    public Person(int age){
        this.age = age;
    }
    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return age;
    }
}
public class FinalReferenceTest{
    public static void main(String[]args){
        final int[] iArr = {5,6,12,8};
        System.out.println(Arrays.toString(iArr));
        Arrays.sort(iArr);
        System.out.println(Arrays.toString(iArr));
        iArr[2] = -8;
        System.out.println(Arrays.toString(iArr));
        //iArr = null;
        final Person p = new Person(45);
        p.setAge(21);
        System.out.println(p.getAge());
        //p = null;
    }
}

[5, 6, 12, 8]

[5, 6, 8, 12]

[5, 6, -8, 12]

21

使用final修饰的引用类型变量不能被重新赋值,但可以改变引用类型变量所引用对象的内容。

5.4.4 可执行“宏替换”的final变量

对一个final变量,不管它是类变量,实例变量,还是局部变量,只要该变量满足三个条件,这个final变量就不再是一个变量,而是相当于一个直接量。

  • 使用final修饰符修饰
  • 在定义该final变量时指定了初始值
  • 该初始值可以在编译时就被确定下来
package code;
public class FinalReplaceTest{
    public static void main(String[]args){
        final int a = 5+3;
        final double b = 1.2/3;
        final String str = "疯狂" + "Java";
        final String book = "疯狂Java讲义:" + 99.0;
        final String book2 = "疯狂Java讲义" + String.valueOf(99.0);
        System.out.println(book == "疯狂Java讲义:99.0");
        System.out.println(book2 == "疯狂Java讲义:99.0");
    }
}

true

false

由于定义book2变量时显式将数值99.0转换为字符串,但由于该变量的值需要调用String类的方法,因此编译器无法在编译时确定book2的值,book2不会被当成“宏变量”处理。

package code;
public class StringJoinTest{
    public static void main(String[] args){
        String str1 = "疯狂Java";
        String str2 = "疯狂" + "Java";
        String str3 = str1 + str2;
        System.out.println(str1 == str2);
        System.out.println(str1 == str3);

    }
}

true

false

由于编译器可以在编译阶段就确定str2的值为“疯狂Java”,所以系统会让s2直接指向常量池中缓存的“疯狂Java”字符串,因此str1 = str2.

对于final实例变量而言,只有在定义该变量时指定初始值才会有“宏变量”的效果

5.4.5 final方法

final修饰的方法不可被重写,如果出于某些原因,不希望子类重写父类的某个方法,则可以使用final方法。

对于一个private方法,因为它仅在当前类中可见,其子类无法访问该方法,所以子类无法重写该方法—–如果子类中定义一个与父类private方法有相同方法名,相同形参列表,相同返回值类型的方法,也不是方法重写,只是重新定义了一个新方法。

package code;
public class PrivateFinalMethodTest{
    private final void test(){}
}
class Sub extends PrivateFinalMethodTest{
    public void test(){}
}
class FinalOverload{
    //final修饰的方法只是不能被重写,完全可以被重载
    public final void test(){}
    public final void test(String agr){}
}

5.4.6 final类

final修饰的类不可以有子类,例如java.lang.Math类就是一个final类,它不可以有子类

时间: 2024-10-05 16:47:15

final修饰符的相关文章

final修饰符,多态,抽象类,接口

1.final修饰符 final可以修饰类,该类不能被继承. final可以修饰方法,该方法不能被重写.(覆盖,复写) final可以修饰变量,该变量不能被重新赋值.因为这个变量其实常量 2.多态 同一个对象(事物),在不同时刻体现出来的不同状态. 举例:        猫是猫,猫是动物.        水(液体,固体,气态). 多态的前提: A:要有继承关系.        B:要有方法重写.            其实没有也是可以的,但是如果没有这个就没有意义.              

static修饰符与final修饰符

■ static修饰符与final修饰符: ★ static修饰符: 1. 修饰的对象: 类中的成员(属性[静态变量或类变量]和方法[静态方法或类方法]) 2. 静态属性的特点: 1. 静态变量被所有对象共享 2. 随着类的加载而加载,随着类的消失而消失,和对象的创建无关 3. 可以直接被类名调用 3. 静态方法的特点: 1. 静态方法优先于对象存在,在静态方法中无法访问与对象相关的实例变量(这时候对象还没有创建,其属性也就没有) 2. 静态方法无法访问实例变量 3. 静态方法可以访问静态变量

JAVA基础-栈与堆,static、final修饰符、内部类和Java内存分配

Java栈与堆 堆:顺序随意 栈:后进先出(Last-in/First-Out). Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过new.newarray.anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放.堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据.但缺点是,由于要在运行时动态分配内存,存取速度较慢. 栈的优势是

final修饰符—不可变

final 修饰符 修饰类 不可以有子类 修饰变量 变量一旦获得初始值就不可改变,不能被重新赋值 成员变量:初始值必须有程序员显式设置,系统不会对其隐式初始化 类变量:静态初始化块 | 声明该类变量时      实例变量:非静态初始化块 | 声明该实例变量时 | 构造器中      局部变量:初始值必须有程序员显式设置,系统不会对其隐式初始化                 定义变量时指定 | 后面代码中指定                 形参变量由传入参数值来完成初始化,故不能被赋值    

final修饰符的难点记录

今天看到了final字段这块,把不会的或者难点记录下来. 第一,空白final. 书上说的有点绕,说空白final更灵活.但之前又说过final变量必须进行初始化,这是什么意思呢,二者难道有冲突吗? 其实空白final的核心就是:构造器赋值. <script src="https://code.csdn.net/snippets/401447.js"></script> 第二,static final 同 final 的区别. 以前我提过,static字段只会初

Java中的final修饰符

1.什么时候可以选择final修饰符 如果想让一个类不被其他类继承,不允许在有子类,这时候就要考虑用到final来修饰. 2.用final修饰的类 首先大家要明白,用final修饰的类是不能被继承的,下面来看一个错误案例. eg: final class Penguin { } class SubPenguin extends Penguin { } 此时这段代码的class SubPenguin extends Penguin这行代码会报错: The type SubPenguin canno

Java中的(构造方法、方法重载、final修饰符使用及继承和抽象)

构造方法: 构造方法的名称和类名相同,没有返回类型,参数列表(类型.个数)不同 方法重载:成员方法和构造方法都可以进行重载 方法名相同但是参数列表(类型,个数)不同,成为方法的重载. 继承:直支持单继承,一个类只能有一个父类 继承要用extends关键字修饰 public class Dog extends Pet{ //方法体 } 子类调用父类公用的成员变量和方法需使用关键字super 如super.方法名 super(成员变量,成员变量....) 方法重写: 方法重写的需求: 1.重写方法和

Java中final修饰符深入研究

一.开篇 本博客来自:http://www.cnblogs.com/yuananyun/ final修饰符是Java中比较简单常用的修饰符,同时也是一个被"误解"较多的修饰符.对很多Java程序员来说,他们大都只是草草看了一下各种书本上的介绍,然后背下来,什么时候想起 来有这东西就用一下.对于何时使用final修饰符.使用final修饰符对程序有什么影响,这些其实他们并不知道,当然在这篇文章之前,我也是一知半解的. 我们书本上对final的描述大概有三种用法: final可以修饰变量,

java中final修饰符的使用

1.final修饰符的用法: final可以修饰变量,被final修饰的变量被赋初始值之后,不能对它重新赋值. final可以修饰方法,被final修饰的方法不能被重写. final可以修饰类,被final修饰的类不能够被继承. 上面的这些"语法口诀"对真正掌握final修饰符的用法依然是不够的. 2.final修饰的变量:被final修饰的实例变量必须显示指定初始值,而且只能在如下三个位置指定初始值: 定义final实例变量时指定初始值. 在非静态初始化块中为final实例变量指定初