我试图简单地测试JLS保证的最终字段的初始化安全性.这是我写的一篇论文.但是,根据我当前的代码,我无法让它"失败".有人可以告诉我我做错了什么,或者这只是我必须反复运行然后看到一个不幸的时机失败?
这是我的代码:
public class TestClass {
final int x;
int y;
static TestClass f;
public TestClass() {
x = 3;
y = 4;
}
static void writer() {
TestClass.f = new TestClass();
}
static void reader() {
if (TestClass.f != null) {
int i = TestClass.f.x; // guaranteed to see 3
int j = TestClass.f.y; // could see 0
System.out.println("i = " + i);
System.out.println("j = " + j);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的线程正在调用它:
public class TestClient {
public static void …Run Code Online (Sandbox Code Playgroud) 可能重复:
何时应该使用final?
final除非必要,否则我倾向于声明所有变量.我认为这是一个很好的做法,因为它允许编译器检查标识符是否按预期使用(例如,它没有变异).另一方面,它使代码混乱,也许这不是"Java方式".
我想知道是否存在关于最终变量的非必要使用的普遍接受的最佳实践,以及是否应该了解该讨论的其他权衡或方面.
对于以下代码:
public class StaticFinal
{
private final static int i ;
public StaticFinal()
{}
}
Run Code Online (Sandbox Code Playgroud)
我得到编译时错误:
StaticFinal.java:7: variable i might not have been initialized
{}
^
1 error
Run Code Online (Sandbox Code Playgroud)
这符合JLS8.3.1.2,其中说:
如果空白的final(§4.12.4)类变量未被声明它的类的静态初始化程序(第8.7节)明确赋值(第16.8节),则为编译时错误.
所以,完全理解上述错误.
但现在考虑以下内容:
public class StaticFinal
{
private final static int i ;
public StaticFinal()throws InstantiationException
{
throw new InstantiationException("Can't instantiate"); // Don't let the constructor to complete.
}
}
Run Code Online (Sandbox Code Playgroud)
这里,构造函数永远不会完成,因为它InstantiationException是在构造函数的中间抛出的.这段代码编译得很好!!
为什么?为什么这段代码没有显示关于final变量非初始化的编译时错误i?
编辑
我正在使用javac 1.6.0_25命令提示符编译它(不使用任何IDE)
C++ 11将允许将类和虚方法标记为最终,以禁止从它们派生或覆盖它们.
class Driver {
virtual void print() const;
};
class KeyboardDriver : public Driver {
void print(int) const final;
};
class MouseDriver final : public Driver {
void print(int) const;
};
class Data final {
int values_;
};
Run Code Online (Sandbox Code Playgroud)
这非常有用,因为它告诉读者接口有关使用此类/方法的意图.如果用户尝试覆盖,则用户获得诊断也可能有用.
但编译器的观点是否有优势?当编译器知道"这个类永远不会从中派生出来"或"这个虚拟函数永远不会被覆盖"时,编译器能做些什么吗?
因为final我主要发现只有N2751指的是它.通过一些讨论,我发现了来自C++/CLI方面的论据,但没有明确暗示为什么final对编译器有用.我正在考虑这个问题,因为我也看到了标记类的一些缺点final:要对受保护的成员函数进行单元测试,可以派生一个类并插入测试代码.有时这些课程是很好的候选人final.在这些情况下,这种技术是不可能的.
在/sf/answers/137702841/中,提供了一种解决方案,用于静态检查成员是否存在,可能在类型的子类中:
template <typename Type>
class has_resize_method
{
class yes { char m;};
class no { yes m[2];};
struct BaseMixin
{
void resize(int){}
};
struct Base : public Type, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U>
static no deduce(U*, Helper<void (BaseMixin::*)(), &U::foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
Run Code Online (Sandbox Code Playgroud)
但是,它不适用于C++ 11 final类,因为它继承了被测试的类,这会final阻止它.
OTOH,这一个:
template <typename C>
struct has_reserve_method {
private:
struct No …Run Code Online (Sandbox Code Playgroud) 以下陈述之间有什么区别
String name = "Tiger";
final String name ="Tiger";
Run Code Online (Sandbox Code Playgroud)
虽然String类是finalclass,但为什么我们需要创建一个String"CONSTANT"变量作为final?
在Java中,当跨多个线程(通常)使用对象时,最好将字段设为final.例如,
public class ShareMe {
private final MyObject obj;
public ShareMe(MyObject obj) {
this.obj = obj;
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,obj的可见性将在多个线程中保持一致(假设obj具有所有最终字段),因为它是使用final关键字安全构造的.
在scala中,它不会出现val编译到最终引用,而是val是scala中的语义,阻止您重新分配变量(构造函数中的Scala最终变量).如果scala构造函数变量未定义为final,它们是否会遇到同样的问题(在actor中使用这些对象时)?
我最近在一次采访中被问到这个问题:
你可以在Java API中命名任何不应该是最终的类,或者那个不应该且应该是'的类吗?
我什么都想不到.这个问题意味着我应该知道所有的API类,比如我的手,我个人不希望任何Java开发人员知道.
如果有人知道任何此类课程,请提供示例.
以下代码段发出编译时错误.
char c = 'c';
char d = c + 5;
Run Code Online (Sandbox Code Playgroud)
第二行的错误说,
possible loss of precision
required: char
found: int
Run Code Online (Sandbox Code Playgroud)
该错误消息基于NetBeans IDE.
当此字符c声明final如下时.
final char c = 'c';
char d = c + 5;
Run Code Online (Sandbox Code Playgroud)
编译器时间错误消失了.
它与最终字符串的情况无关
什么是final修改有所作为吗?
我正在阅读一篇非常棒的C++ 11教程,作者在解释final关键字的同时提供了这个例子:
struct B {
virtual void f() const final; // do not override
virtual void g();
};
struct D : B {
void f() const; // error: D::f attempts to override final B::f
void g(); // OK
};
Run Code Online (Sandbox Code Playgroud)
那么在这里使用final关键字是否有意义?在我看来,你可以避免在virtual这里使用关键字,防止f()被覆盖.
final ×10
java ×6
c++ ×3
c++11 ×3
actor ×1
char ×1
class ×1
compilation ×1
concurrency ×1
jls ×1
scala ×1
static ×1
string ×1
type-traits ×1
variables ×1
visibility ×1