根据the tutorial:
static
修饰符与final
修饰符结合使用,也用于定义常量。final
修饰符表示此字段的值不能更改。
只有涉及的类型是原始的,我才同意这一点。使用参考类型,例如类Point2D
的实例,其位置属性不是final
(即,我们可以更改其位置),此类变量(如public static final Point2D A = new Point2D(x,y);
)的属性仍然可以更改。这是真的吗?
答案 0 :(得分:67)
是的,它可以改变。只能更改引用,但其内部字段可以是。以下代码显示了它:
public class Final {
static final Point p = new Point();
public static void main(String[] args) {
p = new Point(); // Fails
p.b = 10; // OK
p.a = 20; // Fails
}
}
class Point {
static final int a = 10;
static int b = 20;
}
Groovy(另一种JVM语言)有一个名为@Immutable的注释,它在构造对象后阻止更改为对象的内部状态。
答案 1 :(得分:16)
正确,它仍然可以改变。在这种情况下," static final"指的是引用本身,不能更改。但是,如果它是引用的对象是可变的,则可以更改它引用的对象。
不可变对象(如String)将是常量。
答案 2 :(得分:10)
public static final Point2D A = new Point2D(x,y);
此处参考 A
最终且不是类Point2D
内的值。
定义静态最终结果后,您无法执行此操作:
//somewhere else in code
A = new Point2D(x1,y1);
答案 3 :(得分:6)
public static final Point2D A = new Point2D(x,y);仍然可以改变。这是真的吗?
无法更改A的引用,但如果属性不是最终的,则其真正的关联对象的值可以更改。
class Point2D{
private int x;
private int y;
<getter & setter>
}
class Constant{
Public static final Point2D A = new Point2D(1,2);
public static void main(String[] args){
A.setX(10); // this will work
A = new Point2D(10,20);// this will not work
}
}
如果Point2D's
属性为final,则Point2D
class
将为immutable
。
或者您可以发送可克隆的对象。
喜欢 -
private static final Point2D A = new Point2D(x,y);
public static getA(){
return A.clone();
}
答案 4 :(得分:6)
这是真的。 final
修饰符不会以任何可能的方式传递。
这只表示引用不会改变。参考的内容(对象的字段)可能会随着时间而改变。
答案 5 :(得分:2)
对点(您的案例中为A
)的引用无法更改。只有对象的状态才能改变。因此,您无法创建新的Point2D
并将其分配给变量。
答案 6 :(得分:2)
只有引用是最终的,引用的对象可以更改(除非它是一个不可变的对象,如Integer等)。所以是的,对于给定的“常数”值,它只是常数。
答案 7 :(得分:1)
是
当然,您也可以稍后更改最终字段的值as described elsewhere。
答案 8 :(得分:1)
你可以在这里找到一个非常类似的问题,并有很好的解释:
下面: Why can final object be modified?
顺便说一下,我开始考虑反思机制......
理论上......我相信你可以拥有类实例..然后获取类成员,找到当前实例并检查它是最终的....
我没有检查它,如果可能的话我甚至不知道 - 这只是一个想法(也许?)
在
public class Final {
static final Point p = new Point();
public static void main(String[] args) throws MyImmutableException {
p = new Point(); // Fails
p.setB(10); // OK
p.setA(20); // Fails - throws MyImmutableException
}
}
public class Point() {
int a = 10;
int b = 20;
public setA(int a) {
this.a = a;
}
public setB(int b) throws MyImmutableException {
detectIsFinal()
this.b = b;
}
private void detectIsFinal() throws MyImmutableException {
int mod = this.getClass().getModifiers()
if (Modifier.isFinal(mod)) {
throw new MyImmutableException();
}
}
}
public class MyImmutableException extends Exception {
public MyImmutableException() {super(); }
}
我在想你还能做些什么...再次它只是一个!!!!!!!!! PSEUDOCODE !!! 我不确定它是否会起作用:P
也许拥有注释知识的人会受到启发并使其发挥作用。不幸的是,本周我没有更多时间。也许以后我会尝试制作一个POC。
public class Final {
@Immutable
static final Point p = new Point();
public static void main(String[] args) {
p = new Point(); // Fails
p.setB(10); // Fails
p.setA(20); // OK
}
}
public class Point() {
int a = 10;
@ImmutableOnThisInstance
int b = 20;
@DetectIsImmutable
public setA(int a) {
this.a = a;
}
@DetectIsImmutable
public setB(int b) {
this.b = b;
}
}
class Immutable {
?????????????????
}
class DetectIsImmutable {
/**
* Just a pseudocode - I don't know how to work with ANNOTATIONS :) :) :)
* SORRY :)
* @throws MyImmutableException
*/
private void detectMethod() throws MyImmutableException {
Immutable instance = CLASS_THAT_IS_ANNOTATED.getClass().getAnnotation(Immutable.class)
if (instance != null) {
// get parent Method invocation name (from stacktrace list)
String methodName = .............;
if (methodName.startsWith("set")) {
// check id we have variable with this settername
String fieldName = ...; // cut "set" get rest of it, make first letterSmall
// find this field in object fields
Field f = this.getClass().getDeclaredField(fieldName);
if (f.getAnnotation(ImmutableOnThisInstance.class) != null) {
throw MyImmutableException();
}
}
}
}
}
答案 9 :(得分:0)
仍然如此。
您引用的声明有一种方法是正确的。 static final
描述了变量,并且该变量无法更改,因此是常量。变量是指向对象的指针,该对象可以更改。但这并不能阻止变量成为常数。
这是一种不那么强大的方法,你可以用C ++中的const
来实现,但它就是这样。
答案 10 :(得分:0)
是的,你是对的。引用不能更改,但引用的对象可以是。这样的事情是完全合法的:
public static final List<Object> someList = new ArrayList<Object>();
// ...
someList.add(someThing); // <-- this would be illegal if the referenced object was also constant
答案 11 :(得分:0)
您可以更改Point2D的属性,但不能创建它的新实例。
我还应该提到Point2D是抽象的,所以你必须创建一个扩展它的子类的实例。
答案 12 :(得分:0)
正如其他已经提到的那样,它是对Point2D对象的引用,它是静态final,而不是属性x和y。如果你想确保你不能改变Point2D对象的位置,你应该在Point2D类中设置属性x和y static和final(初始化)。
答案 13 :(得分:0)
static final Point2D A = new Point2D(x,y);
所有它都说是Point2D
类的引用无法改变。
_____________
| |
A----------|--->(x,Y) |
| |
|_____________|Heap
所以你不能通过指向不同的对象来改变A,当然你可以改变(x,y)的值或点对象的内容
如果你想使你的对象也是常数,你必须使Point对象不可变。
答案 14 :(得分:0)
当引用变量声明为final时,一旦引用对象,就无法为其重新分配新对象。但是,您可以更改最终引用变量指向的对象的状态。请看下面的例子..
class A
{
int i = 10;
}
public class UseOfFinalKeyword
{
public static void main(String[] args)
{
final A a = new A(); //final reference variable
a.i = 50;
//you can change the state of an object to which final reference variable is pointing
a = new A(); //compile time error
//you can't re-assign a new object to final reference variable
}
}
有关详情,请点击以下链接:final keyword in java