繁体   English   中英

final String类与非最终String类的final方法

[英]final String class vs final methods of Non-final String class

我知道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

简单来说,我可以通过采用任何一种方法达到相同的不变性水平吗? 它们是否都能使对象变得不可变?

最后的课程不能延长。

可以扩展具有final方法的非final类(可以在子类中添加新方法),但不能覆盖现有的final方法。

类的final-modifier并不意味着属性也是final和immutable。 它只是意味着该类不再是父类。 最终的课程是不可能的。

请参阅在Java中使用final类

决赛在你使用它的地方有不同的效果。

如果一个类是最终的,则不能进行子类化。

如果一个方法最终它不能被任何子类覆盖。

如果变量是最终的,它只能初始化一次,使其保持不变。

你忘记了Constructor。 构造函数不能是final.To避免Is-A情况。

如果您没有将类标记为final,尽管所有方法都是final,仍然可以扩展String并且可以欺骗线程,声称我的类也是String类。

如果String不是最终的并且方法是最终的,则下面是合法的,这会导致混乱

public class MyUnTrustedClass extends String {

   void MyUnTrustedClass(String virus){
        super(virus);
     }

}
public final String { ... }
public ExtendedString extends String { ... } // compiler error

public String { ... }
public ExtendedString extends String { ... } // fine

再解释一下:

使类最终也隐式地使所有方法最终,但也禁止甚至扩展类。 仅使方法最终仍允许扩展类,并且仅禁止覆盖最终方法。 在后一种情况下,您仍然可以在扩展类中声明全新的方法。

具有所有最终方法的非final String类仍然是不可变的(如果所有其他不变性方面都适用)。 请注意,使一个类最终成为使其不可变的努力太少。 实际上,如果设计正确,即使非final类也可以是不可变的。

我不理解的是,使用所有最终变量和最终方法是否可以实现相同目的而不是声明最终类?

将类声明为final的目的与将类中的所有方法声明为final的目的不同。

最后的课程

当我将A类声明为final时,我指出这样的类被冻结 ,它不用于扩展,并且除了在其结构和声明中表达之外,它不能以任何其他方式使用。 由于是最终的A级不容易改进。

注1: 无论你需要使用类型为A的东西,只有一个类,只有一个类,即你可以使用的A类。 根据您所追求的任何设计或根据您的要求,该限制是故意的。

java.lang.System类是一个很好的例子。 在运行时,有一种类型的系统。 可以有一个系统的多个实例,(或者,如在Java中,系统的一种单独包装器。)但是类型,该系统类型的功能只有一个。

具有最终方法的类

另一方面,所有方法final A级只是简单地说我提供的任何东西 ,你不能扩展。 但是,您可以向我的扩展添加更多功能或状态。

注2:无论何时需要使用非最终的A类,但大多数方法都是最终方法,您可以使用A的实例或其子类。 您可以在不同的上下文中使用A的子类,但不更改类型A提供的核心功能。

我无法想象所有方法都是最终的好例子。 我通常看到的是final结合abstract方法的方法组合。 在这种情况下,最终方法实现算法,其细节通过抽象方法扩展。

考虑一个访问监视器类的缺乏想象力且相当冗长(故意)的示例,该类冻结主要授权逻辑(除非该用户被授权,否则为任何人抛出异常。)更多详细信息保留为“空白”,由类填写专业化。

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.
    } 
}

在现实生活中,我们通常会看到通过继承进行纯粹细化的其他替代方案 - 组合和委派会浮现在脑海中。 实际上,在一般情况下,人们更喜欢合成/委托而不是继承。

然而,这完全是一个不同的主题(一个值得一两本书),并且基于继承的示例在此上下文中更好地用于说明具有最终方法的非最终类的要点。

最后一个例子说明了一个非最终类背后的想法,所有方法都是最终的(即使示例为抽象方法留下了空间。)与同一响应中的前一个相比,我希望你能看到意图的不同两个人背后。

简单来说,我可以通过采用任何一种方法达到相同的不变性水平吗? 它们是否都能使对象变得不可变?

不。如果String类不是final,那么有人可以扩展String并创建一个可变的子类。 所有Java开发人员都会失去假设Strings是线程安全的能力。

这取决于我们如何定义不可变的。 我们可以调用一个不可变的对象

  1. 对象的所有字段都是final,而已知引用类型的字段指向不可变类
  2. 对象的可观察状态不得改变,其中可观察的定义为
    1. 可通过公共方法获取,或
    2. 可以通过某些特定类的公共方法访问

如果我们使用定义1,那么类本身必须是final,否则子类可以声明一个新的非final字段。

如果我们使用定义2.1,那么类本身也必须是final,否则它可以用getter和setter声明一个非final字段。

如果我们使用定义2.2,那么每个字段都是final或private,每个方法final或private都是足够的,并且该类的所有现有方法都保留了不变性。 (如果我们知道要封装的软件包,并且已经验证软件包中的所有其他代码都保留了不变性和封装,我们可能会放宽这个以包含受软件包保护的字段和方法。

为了Java平台的安全性,定义2.2和上面概述的实现方法就足够了。 然而,与宣布类本身最终相比,沟通,实现和验证要复杂得多。 由于违反该不变量会损害平台的安全性,因此采用更简单,更可靠的方法似乎是明智的。

Final就像C ++中的const一样,因此你无法改变它的状态。 不可变是String类的内部功能。 你可以做的是使用StringBuilder来实现它。 当您为其分配新值时,不可变对象在RAM中创建新实例。 我从不改变它的状态,因此创建了一个新的实例,它被引用作为引用传递

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM