标签: final

在Java中初始化最终变量的问题

我一直在努力解决Java中的一个问题并且它已经开始找到我了,我真的想不出一个正确的解决方法.

我有一个最终的对象属性,但是动态的.也就是说,我希望值在指定后保持不变,但每个运行时的值可以不同.所以我在类的开头声明了类级变量 - 比如说private final FILE_NAME;.然后,在构造函数中,我为它赋值 - 比方说FILE_NAME = buildFileName();

当我在buildFileName()抛出异常的方法中有代码时,问题就开始了.所以我在构造函数中尝试这样的东西:

try{
   FILE_NAME = buildFileName();
}
catch(Exception e){
   ...
   System.exit(1);
}
Run Code Online (Sandbox Code Playgroud)

现在我有一个错误 - "空白的最终字段FILE_NAME可能尚未初始化." 这是我开始对Java的严格编译器感到有些恼火的地方.我知道这不会是一个问题,因为如果它到达catch,程序将退出...但编译器不知道,因此不允许此代码.如果我尝试在catch中添加一个虚拟赋值,我会得到 - "可能已经分配了最终字段FILE_NAME." 我显然不能在try-catch之前分配一个默认值,因为我只能分配一次.

有任何想法吗...?

java final exception constants

20
推荐指数
3
解决办法
1万
查看次数

最终字段对于线程安全是否真的有用?

多年来,我一直在使用Java Memory Model进行日常工作.我认为我对数据竞争的概念以及避免它们的不同方法(例如,同步块,易变变量等)有很好的理解.但是,仍然有一些我认为我完全不了解内存模型的东西,这是类的最终字段应该是线程安全的方式而没有任何进一步的同步.

所以根据规范,如果一个对象被正确初始化(也就是说,没有引用对象在其构造函数中以某种方式转义,使得引用可以被另一个线程看到),那么,在构造之后,任何看到该对象的线程对象将保证看到对象的所有最终字段的引用(在它们构造时的状态),没有任何进一步的同步.

特别是,标准(http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4)说:

最终字段的使用模型很简单:在该对象的构造函数中设置对象的最终字段; 并且在对象的构造函数完成之前,不要在另一个线程可以看到的地方写入对正在构造的对象的引用.如果遵循此原因,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本.它还将看到那些最终字段引用的任何对象或数组的版本,这些字段至少与最终字段一样是最新的.

他们甚至给出了以下示例:

class FinalFieldExample { 
    final int x;
    int y; 
    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3; 
        y = 4; 
    } 

    static void writer() {
        f = new FinalFieldExample();
    } 

    static void reader() {
        if (f != null) {
            int i = f.x;  // guaranteed to see 3  
            int j = f.y;  // could see 0
        } 
    } 
}
Run Code Online (Sandbox Code Playgroud)

其中线程A应该运行"reader()",并且线程B应该运行"writer()".

到目前为止,显然是如此的好.

我主要担心的是......这在实践中真的有用吗?据我所知,为了使线程A(运行"reader()")看到对"f"的引用,我们必须使用一些同步机制,例如使f volatile,或者使用lock来同步访问F.如果我们不这样做,我们甚至不能保证"reader()"将能够看到初始化的"f",也就是说,由于我们没有同步访问"f",读者可能会看到" null"而不是由writer线程构造的对象.这个问题在http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalWrong中说明,这是Java内存模型的主要参考之一[大胆强调我的]:

现在,已经说过所有这些,如果在一个线程构造一个不可变对象(即一个只包含最终字段的对象)之后,你想确保所有其他线程都能正确看到它,你仍然通常需要使用同步.例如,没有其他方法可以确保第二个线程可以看到对不可变对象的引用.程序从最终字段获得的保证应该仔细调整,仔细了解如何在代码中管理并发.

因此,如果我们甚至不能保证看到对"f"的引用,那么我们必须使用典型的同步机制(volatile,lock等),并且这些机制确实已经导致数据争用消失,最终的需求是我甚至都不会考虑的事情.我的意思是,如果为了使"f"对其他线程可见,我们仍然需要使用volatile或synchronized块,并且它们已经使内部字段对其他线程可见......有什么意义(在线程安全术语中)首先在场上进行决赛?

java multithreading synchronization final

20
推荐指数
3
解决办法
3178
查看次数

Java最终局部变量存储在哪里?

请看以下示例:

public void init() {
    final Environment env = new Environment();
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
             env.close();
        }
     });
}
Run Code Online (Sandbox Code Playgroud)

首先,env存储在哪里?是吗:

  • 由编译器复制到引用它的内部类的隐藏成员变量中
  • 复制到堆上并在其上引用
  • 留在堆栈上,不知何故在那里引用
  • 别的

我的猜测是第一个选择.

其次,执行这样做会产生任何性能问题(而不是简单地创建env类的成员变量并引用它),特别是如果要创建大量引用最终局部变量的内部类构造.

java performance final local-variables

19
推荐指数
1
解决办法
5328
查看次数

Java'final'关键字是否真正提高了安全性?

虽然在Java中使用'final'关键字的原因很多,但我一遍又一遍地听到的一个原因是它使您的代码更安全.虽然这在这个微不足道的案例中似乎有意义:

public class Password
{
    public final String passwordHash;
    ...
}
Run Code Online (Sandbox Code Playgroud)

使用final关键字,您可以预期没有恶意代码可以更改变量passwordHash.但是,使用反射可以更改passwordHash字段的最终修饰符.

"最终"提供任何真正的安全性,还是只是安慰剂?

编辑: 有一些非常有趣的讨论,我希望我能接受不止一个答案.谢谢各位的意见.

java security final

19
推荐指数
3
解决办法
2601
查看次数

将最终变量传递给匿名类

通过构造函数传递给匿名类的最终变量中,Jon Skeet提到变量通过自动生成的构造函数传递给匿名类实例.在这种情况下,为什么我无法使用反射来查看构造函数:

public static void main(String... args) throws InterruptedException {
final int x = 100;
new Thread() {
    public void run() {
        System.out.println(x);      
        for (Constructor<?> cons : this.getClass()
                .getDeclaredConstructors()) {
            StringBuilder str = new StringBuilder();
            str.append("constructor : ").append(cons.getName())
                    .append("(");
            for (Class<?> param : cons.getParameterTypes()) {
                str.append(param.getSimpleName()).append(", ");
            }
            if (str.charAt(str.length() - 1) == ' ') {
                str.replace(str.length() - 2, str.length(), ")");
            } else
                str.append(')');
            System.out.println(str);
        }
    }

}.start();
Thread.sleep(2000);
Run Code Online (Sandbox Code Playgroud)

}

输出是:

100
constructor : A$1()
Run Code Online (Sandbox Code Playgroud)

java constructor final anonymous-class inner-classes

19
推荐指数
2
解决办法
1507
查看次数

如何检测C++ 11中的类是否是最终的?

代码优先.

#include <iostream>

using namespace std;

struct A final {};
struct B {};

int main()
{ 
    cout << is_final<A>::value << endl; // Output true
    cout << is_final<B>::value << endl; // Output false

    return 0; 
}
Run Code Online (Sandbox Code Playgroud)

如何实现类is_final?

c++ final type-traits c++11

19
推荐指数
2
解决办法
1476
查看次数

导入的java类中的public static final变量

我碰巧在我的工作场所遇到过Java代码.这是场景:有两个类 - ClassAClassB.

ClassA除了4个公共静态最终字符串值之外什么都没有.它的目的是使用那些值ClassA.variable(不要问我为什么,这不是我的代码).

ClassB进口ClassA.我编辑了字符串值ClassA并对其进行了编译.当我跑步时,ClassB我可以看到它使用的是旧值 - 而不是新值.我必须重新编译ClassB才能使用新的值ClassA!(我不得不重新编译其他导入的类ClassA!)

这只是因为JDK 1.6或我之前应该知道重新编译的ClassB!开导我.:)

java static final public recompile

18
推荐指数
1
解决办法
3万
查看次数

在内部类(java)中访问局部变量

编译完代码后,我遇到了两个错误.

错误是:

1.

  local variable input is accessed within inner class; 
  needs to be declared final
     String name = input.getText();
Run Code Online (Sandbox Code Playgroud)

2.

  local variable c_age is accessed within inner class; 
  needs to be declared final
     Object child_age = c_age.getSelectedItem();
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

import javax.swing.*;
import java.awt.event.*;

public class GUI
{
    public static void main(String[] args)
    {
        JFrame frame = new JFrame("Try GUI");
        JLabel l1 = new JLabel("Please Enter Your Child's Name");
        JTextField input = new JTextField("",10);

        JLabel l2 = new JLabel("Choose Your Child's …
Run Code Online (Sandbox Code Playgroud)

java final inner-classes actionlistener

18
推荐指数
2
解决办法
6万
查看次数

switch语句中的最终变量大小写

        final int a = 1;
        final int b;
        b = 2;
        final int x = 0;

        switch (x) {
            case a:break;     // ok
            case b:break;     // compiler error: Constant expression required

        }
        /* COMPILER RESULT:
                constant expression required
                case b:break;
                     ^
                1 error
        */
Run Code Online (Sandbox Code Playgroud)

为什么我会遇到这种错误?如果我愿意final int b = 2,一切正常.

java final case switch-statement

18
推荐指数
2
解决办法
2万
查看次数

在Java中运行时添加final修饰符

听起来有点奇怪,但是可以final在运行时添加修改器吗?

我有一个标记为的变量public static int/short.在某些时候我想阻止改变它的值,我希望将其可访问性保持为标准静态值(ClassName.field).

public class Main {

    private static int a = 0;

    public static void addFinalMod(Field f) {

        Field modifiersField = null;
        try {
            modifiersField = Field.class.getDeclaredField("modifiers");
        }
        catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        modifiersField.setAccessible(true);
        try {
            modifiersField.setInt(f, f.getModifiers() & Modifier.FINAL);
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        System.out.println(a);
        try {
            Field f = Main.class.getDeclaredField("a");
            addFinalMod(f);
        }
        catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        a = …
Run Code Online (Sandbox Code Playgroud)

java final modifier

18
推荐指数
1
解决办法
1249
查看次数