我们都熟悉不变性。一个非常简单的不可变类将是
final class Immutable {
public final float PI = 3.14;
}
这真的是一成不变的吗? Java开发人员真的不能修改PI
吗?
不可以,他们可以使用Reflection API访问和修改PI
。但是,由于这是一种非常规的访问字段的方式,尽管可以使用安全管理器阻止对反射API的修改(对吗?),所以即使没有激活安全管理器,我们也说Immutable
是不可变的。>
interface ImmutableName {
public String getName();
}
class MutableName implements ImmutableName {
private String name;
public String getName() { return name; }
public void setName(String val) { name = val; }
}
如果我将所有MutableName
个实例称为ImmutableName
实例,则开发人员将修改name
。实际上,开发人员可以检查实例的运行时实现,然后将实例下放到MutableName
。在Java中,向下转换比反射API更常见,但这是否仍然是一些非常规的技巧?班级设计人员是否应该防御性地编写代码以防止沮丧?
答案 0 :(得分:0)
您需要保持透视。
是的,从技术上讲,可能会编写会干扰我们通常认为是不可变的类的代码。 (如果有人这样做,JLS会很清楚地表明未指定行为。)
但这是众所周知的。通常这不是问题,因为:
那么,如果您真的 认为某人可能会编写疯狂的/不熟练的代码来执行此操作,您该怎么办?
解决方案:
好的,这些方法都不是水密的。但是,IT领域从来没有。 (除非您愿意断开系统与Internet的连接并在法拉第笼中工作。这有时是必要的,但对于普通人而言不是明智的选择。)
就其价值而言,Java语言和Java虚拟机设计是在一方面使事情安全和简单,又使程序员能够以(例如)名义执行聪明和(有时)危险的事情之间的折衷方案。性能。如果语言设计师全力以赴地执行不变性之类的事情,那么
1-所需的限制类型也将使Java开发人员/库所依赖的其他事情变得不可能。例如,用于实现DI框架,序列化绑定,远程处理等的jvm功能。
2-否Unsafe
。没有本机代码。
3-聪明的开发人员最终会找到解决方法。
答案 1 :(得分:0)
采用完全不同的方式...
您的第一个示例询问特定类的不变性,并且该类在正常意义上被认为是不变的。 (我的另一个答案解释了应该应该足够好。)
您的第二个示例是关于一个类是否可以违反接口中陈述的关于不变性的假设。显然可以。实际上,不可能以强制接口的所有实现不可变的方式设计Java接口。您不能阻止垂头丧气。
同样,您不能阻止某人这样做:
class SneakyName implements ImmutableName {
private String name;
public String getName() {
if (SomeOtherClass.beSneaky) {
name += " ";
}
return name;
}
}
...不需要向下转换即可利用。
但是再一次,我们在这里真正想要实现什么?
如果您只是想避免别人犯错误,那么MutableName implements ImmutableName
并不是错误。
如果您要强制人们做正确的事,请使用代码审查。或者,如果您找到了一个足够好的静态代码分析器,则可以随意破坏规则……使用它。