我知道java.lang.String
类因安全性和性能原因而被声明为final。
我不理解的是,使用所有最终变量和最终方法是否可以实现相同目的而不是声明最终类?
简而言之,以下两个代码片段之间有什么区别.. 例如
public class final String { .. }
V / S
// non final class
public class String {
// all final variables
private final char[] value;
// all final methods
public final String subString() { .. }
public final int length() { return value.length;}
// etc
}
EDITS
简单来说,我可以通过采用任何一种方法达到相同的不变性水平吗?它们是否都能使对象变得不可变?
答案 0 :(得分:15)
无法延长最终课程。
可以扩展具有最终方法的非最终类(可以在子类中添加新方法),但不能覆盖现有的最终方法。
答案 1 :(得分:7)
类上的final-modifier并不意味着属性也是final和immutable。它只是意味着该类不再是父类。最终的课程是不可能的。
答案 2 :(得分:3)
Final会对您使用它的位置产生不同的影响。
如果一个类是最终的,则不能进行子类化。
如果一个方法是最终的,它不能被任何子类覆盖。
如果变量是最终变量,则只能初始化一次,使其保持不变。
答案 3 :(得分:3)
你忘记了Constructor。构造函数不能是最终的。要避免 Is-A 情况。
如果您没有将类标记为 final ,尽管所有方法都是最终的,我们仍然可以扩展String并且可以欺骗声称我的类也是String类的线程。
如果String本身不是最终的并且方法是最终的,则以下是合法的,这会导致混乱
public class MyUnTrustedClass extends String {
void MyUnTrustedClass(String virus){
super(virus);
}
}
答案 4 :(得分:1)
public final String { ... }
public ExtendedString extends String { ... } // compiler error
public String { ... }
public ExtendedString extends String { ... } // fine
再解释一下:
使类最终也隐式地使所有方法都是最终的,但也禁止甚至扩展类。仅使方法最终仍允许扩展类,并且仅禁止覆盖最终方法。在后一种情况下,您仍然可以在扩展类中声明全新的方法。
包含所有最终方法的非final String类仍然是不可变的(如果所有其他不变性方面都适用)。请注意,使一个类最终成为使其不可变的努力太少。事实上,如果设计得当,即使非最终类也可以是不可变的。
答案 5 :(得分:1)
我不理解的是同一目的是否可以 使用所有最终变量和最终方法代替 宣布最后一堂课?
将类声明为final的目的与将类中的所有方法声明为final的目的不同。
当我将一个类 A 声明为final时,我表示这样的类是冻结,它不是用于扩展,而是它不是除了在结构和声明中表达之外,以任何其他方式使用。由于是最终的, A 类不能进行细化。
注意1: 无论您需要使用A类型的东西,只有一个类,只有一个类,即您可以使用的A类。根据您所追求的任何设计或根据您的要求,该限制是故意的。
java.lang.System
类就是一个很好的例子。在运行时,有一种类型的系统。可以有一个系统的多个实例,(或者,如在Java中,系统的一种单独包装器。)但是 System 类型的类型和功能是唯一的。< / p>
另一方面,所有方法final
的 A 类只是在说我提供的任何内容,你无法扩展。不过,您可以为我的扩展添加更多功能或状态。
注意2:无论您何时需要使用非最终的A类,但大多数(如果不是所有)方法都是最终的,您可以使用A的实例或其子类。您可以在不同的上下文中使用A的子类,但类型A提供的核心功能不会更改。
我无法想象所有方法都是最终的好例子。我通常看到的是final
与abstract
方法相结合的方法组合。在这种情况下,最终方法实现算法,其细节通过抽象方法扩展。
考虑一个缺乏想象力且相当冗长(故意)的访问监控类示例,冻结主要授权逻辑(.ie。抛出异常,除非该用户被授权。)更多细节是留下“空白”,由专业专业填补。
class AccessMonitor {
abstract AuthorizationMechanism getUnderlyingMechanism();
final void checkAccess(User user)
{
AuthorizationMechanism mechanism = getUnderlyingMechanism()
if( mechanism.noAccess(user) )
{
throw someSecurityException("blah");
}
// otherwise, happy camper
}
}
class LdapBasedMonitor extends AccessMonitor {
final AuthorizationMechanism getUnderlyingMechanism()
{
return someLdapThingieMajingie;
}
}
class DbBasedAuthenticator extends Authenticator {
final AuthorizationMechanism getUnderlyingMechanism()
{
//query some database and make a decision, something something.
}
}
在现实生活中,我们通常会看到通过继承进行纯粹细化的其他替代方案 - 构图和委派会浮现在脑海中。实际上,在一般情况下,人们更喜欢合成/委托而不是继承。
然而,这是一个完全不同的主题(一个值得一两本书),基于继承的示例在此上下文中提供更好的 来说明非最终类的最终要点方法
最后一个例子说明了一个非final类的背后的想法,所有方法都是final(即使示例为抽象方法留下空间。)与同一响应中的前一个相比,我希望你能看到两者背后的意图差异。
答案 6 :(得分:0)
简单来说,我可以通过去达到相同的不变性水平 两种方法?它们是否都能使对象变得不可变?
没有。如果String类不是final,那么有人可以扩展String并创建一个可变的子类。所有Java开发人员都会失去假设Strings是线程安全的能力。
答案 7 :(得分:0)
这取决于我们如何定义不可变的。如果
,我们可以调用一个不可变的对象如果我们使用定义1,那么类本身必须是final,否则子类可以声明一个新的非final字段。
如果我们使用定义2.1,那么类本身也必须是final,否则它可以用getter和setter声明一个非final字段。
如果我们使用定义2.2,只要每个字段都是final或private,每个方法final或private,并且该类的所有现有方法都保留不变性就足够了。 (如果我们知道要封装的软件包,并且已经验证软件包中的所有其他代码都保留了不变性和封装,我们可能会放宽这个以包含受软件包保护的字段和方法。
为了Java平台的安全性,定义2.2和上面概述的实现方法就足够了。然而,与宣布类本身最终相比,沟通,实现和验证要复杂得多。由于违反该不变量会损害平台的安全性,采用更简单,更可靠的方法似乎是明智的。
答案 8 :(得分:-1)
Final就像C ++中的const一样,因此你无法改变它的状态。 不可变是String类的内部功能。 你可以做的是使用StringBuilder来实现它。 当您为其分配新值时,不可变对象在RAM中创建新实例。我永远不会改变它的状态,因此创建了一个新的实例,它被引用为引用传递