22

我们怎么可能在创建对象时初始化类的最终变量?

任何人都可以解释它怎么可能?...

4

9 回答 9

40

您必须初始化最终变量一次且仅一次。对于实例变量,有三种方法可以做到这一点:

  1. 在构造函数中
  2. 在实例初始化块中。
  3. 当你声明它时

这是所有三个的示例:

public class X
{
    private final int a;
    private final int b;
    private final int c = 10;

    {
       b = 20;
    }

    public X(final int val)
    {
        a = val;
    }
}

在每种情况下,代码都会在您调用时运行一次,new X(...)并且无法再次调用其中任何一个,这满足了每个实例只发生一次初始化的要求。

于 2013-09-03T05:43:07.237 回答
7

在声明期间未初始化的最终变量称为空白最终变量,必须进行初始化on all constructor either explicitly or by calling this()。不这样做编译器将抱怨为"final variable (name) might not be initialized".


根据维基百科

最终变量只能通过初始化程序或赋值语句初始化一次。它不需要在声明时初始化:这称为"blank final"变量。必须在声明它的类的每个构造函数的末尾明确分配一个类的空白最终实例变量;类似地,一个空白的 final 静态变量必须在声明它的类的静态初始化器中明确赋值;否则,在这两种情况下都会发生编译时错误。

例如。

public class Sphere {

    // pi is a universal constant, about as constant as anything can be.
    public static final double PI = 3.141592653589793;  

    public final double radius;
    public final double xPos;
    public final double yPos;
    public final double zPos;

    Sphere(double x, double y, double z, double r) {
         radius = r;
         xPos = x;
         yPos = y;
         zPos = z;
    }

    [...]
}

有关更多详细信息,请阅读 wiki 页面 http://en.wikipedia.org/wiki/Final_(Java)

于 2013-09-03T05:28:44.790 回答
1

如果您的意思是静态最终成员,则可以使用静态初始化程序:

class Example {
  public final static Map<String,Object> C;

  static {
    C = new HashMap<>();
    C.put("hi", 5);
  }
}
于 2013-09-03T05:46:05.910 回答
1

这是可能的,因为 JVM 内部的工作方式和 Java 的设计方式。

编译代码后,生成的 .class 文件将包含代码的字节码表示。一个 Class 文件只不过是一堆按定义顺序构造的字节,这些字节可以被 JVM 解释。

在类文件结构中,您将能够找到称为常量池的东西,它只是 JVM 在加载类时使用的符号引用表。您的最终变量将在此处找到,无论它们是否被初始化为文字。

所以现在你知道了,让我们继续思考一下 final 修饰符的含义,它只是一种告诉 JVM 在这种情况下将为变量赋值的方式,一旦完成,重新赋值不允许对该变量进行操作,因此正如 Java 语言文档所述,最终变量只能被赋值一次。

既然你有这个背景,为了直接回答你的问题:

无论您的变量是对象还是原始类型,非类成员的最终变量的值(意味着不是静态的)将由 JVM 使用运行时常量池中的值为您的对象自动设置,或者如果这样变量在声明时未初始化,则需要在构造函数运行时设置。所有这一切都是可能的,因为 Java 被设计成这种方式为程序员提供了变量赋值的一些灵活性,以避免硬编码,并提供了一种将对象分配给最终引用的方法。

就像最后的提示一样,停止将最终变量视为 C++ 中的常量。它们可能看起来很相似,但实际上并不相似,它们的处理方式完全不同。

于 2013-09-03T05:49:51.663 回答
1

是的,我们可以在创建对象时初始化类的最终变量,这样每次都会为该最终实例变量(不是最终静态变量)的每个对象分配一个最终值,但是一旦分配了值对于对象,它不能被改变。

    class Demo
{
    public final int num;
    
    public Demo(final int n)
    {
        this.num = n;// this will assign a final value for each object now 
    }
    
}
public class Sample
{  public static void main(String[] args)
    {
        Demo d = new Demo(20);
        System.out.println(d.num);
        
        Demo d1 = new Demo(21);
        System.out.println(d1.num);
        
        d1.num=22;//Invalid will give error now because you are trying to change the final value for d1 object
        System.out.println(d1.num);
    }
} 
于 2021-05-21T07:50:39.617 回答
0

为什么不。像这样

public class GenericFoo{

    final int var;

    GenericFoo(){
        var = 100;
    }

}
于 2013-09-03T05:28:52.387 回答
0

您可以在构造函数完成之前初始化最终实例变量。
根据JSL

必须在声明它的类的每个构造函数的末尾明确分配一个空白的最终实例变量;否则会发生编译时错误。

Java中的空白最终变量是声明时未初始化的最终变量

所以有两种方法可以做到。

方式1:在构造函数中

class Program {
    final int i3;   
    Program() {
        i3 = 10;
    }
}

方式2:在实例块中

class Program {
       final int i3;   
       {
             i3 = 10;
        }
    }
于 2013-09-03T05:29:06.003 回答
0

一个final值只能设置一次,并且只能在构造函数中设置。构造函数没有理由不能将它设置为您喜欢的任何值。

如果您有一个希望成为所有实例的常量的值,那么您将创建它static final并且您将无法在构造函数中设置它。也许你混淆了两者。

于 2013-09-03T05:35:27.213 回答
0

如您所知,实例变量仅与类对象相关联,而变量之前的 final 关键字意味着您无法更改变量的值,因此变量的存在仅在创建对象时才存在,这就是为什么我们可以如上所述以三种方式分配最终变量值的原因在创建对象之前(例如通过静态块,当您声明时)或在创建对象时(例如通过构造函数)

于 2017-11-07T11:57:55.867 回答