【问题标题】:How to create a String class replica?如何创建 String 类副本?
【发布时间】:2011-01-05 07:55:15
【问题描述】:

我需要用与java.lang.String完全相同的方法创建一个类。

在 Java 中执行此操作的最佳方法是什么?

我知道我不能扩展 String 类,因为它是 final。我不是在寻找需要复制java.lang.String 源代码的解决方案。例如,假设我需要名为 MyString 的自定义类中的功能 length(),它具有相应的 'myLength()` 方法。

实现myLength() 的最佳方式是什么?

我不是在查看各种算法来找出字符串的长度,而是重用Stringlength() 方法。现在,一旦我准备好 MyString 类,我应该可以在任何地方使用它来进行自定义操作。

【问题讨论】:

  • 您要解决的实际问题是什么?
  • 我正在尝试找出最适合此类问题的设计模式。
  • 我一直想知道,为什么 String 在 Java 中是 final 的?当然,它提供了我曾经需要的所有功能,并且从未想过需要扩展 String 类的操作,但您仍然永远不会知道某人可能需要什么!
  • @Alex:选择可能更多地与安全性有关,而不是设计。不要让我澄清这一点,因为我认为这只是我可能(或可能没有)读过的东西;-)

标签: java string


【解决方案1】:

通过这里的各种答案,以及提问者的更新和澄清,看起来提问者想要的是一个看起来、闻起来和听起来像字符串的类,但不是。

这是他们希望能够做到的:

MyString string = "String!!";

这是行不通的,因为java.lang.String 是最终类,因此编译器生成的每个"String" 都将是java.lang.String 对象,因为这不是MyString 对象,所以它们不能相互分配.

在弱类型语言中,您将能够创建这样一个类,因为如果一个类看起来、闻起来和听起来都像 duck,那么从所有意图和目的来看,它就是一只鸭子。然而,Java 是一种强类型语言,如果它恰好来自 Anatidae family of birds,那么鸭子只是鸭子。

【讨论】:

  • +1 这是真的。 SO 用户要求提供 String 副本而不是委托,委托仍将创建 String 对象。
【解决方案2】:

由于final 类不能被子类化,创建一个新的类有一个 内部有String 实例并对该对象进行操作。

public class MyString {
  private String s;

  public MyString( String s ) {
    setInternalString( s );
  }

  public int myLength() {
    return getInternalString().length();
  }

  private void setInternalString( String s ) {
    this.s = s;
  }

  private String getInternalString() {
    return this.s == null ? "" : this.s;
  }
}

【讨论】:

    【解决方案3】:

    从您的问题看来,您正在寻找的东西很简单delegation

    class MyString {
    
      String delegate; // The actual string you delegate to from your class
    
      public MyString(String delegate) {
        this.delegate = delegate; // Assign the string that backs your class
      }
    
      int length() {
        return delegate.length(); // Delegate the method call to the string
      }
    
      // other methods that delegate to the string field
    }
    

    【讨论】:

    • 这看起来不错。但是我可以做 MyString strAbc = "This is my String" 吗?我正在寻找 String 的精确副本。在您的解决方案中,我需要在构造函数中传递字符串。
    • @Harsha,你想要的根本不可能。
    • @Paul 你能解释一下吗?
    • @Harsha,我添加了一个答案,以比这些 cmets 允许的更全面地解释。
    • @Harsha 没问题...如果它有帮助,并且点赞总是好的 ;-)
    【解决方案4】:

    我假设你的意思是java.lang.String。但是,您不能将String 替换为您自己的课程。您可以使用相同的方法创建另一个类(通过复制源代码并更改包声明),但您将无法将该类的实例传递给需要 String 的方法。

    这带来了一个重要的问题:你认为你为什么要这样做?

    【讨论】:

    • 我不想仅仅通过复制 String 类的所有方法来创建一个类。这个问题是在一次采访中问我的。
    • 也许这是一个诡计问题,您应该向他们解释为什么这样做会阻止您与几乎所有现有的 Java API 进行互操作。
    • 采访的另一个答案是指出 String 实现了 CharSequence 并且您可以创建其他实现。当然,如果使用 ersatz 字符串的 API 需要 String 而不是 CharSequence,这也无济于事。
    【解决方案5】:

    Proxy 设计模式,我猜。不过,这是一个愚蠢的问题(不是对提问者的反映,而是对在工作面试中问他的人的反映)。可能问你的人没有意识到 String 是最终的?否则我想不出他们为什么会问。

    【讨论】:

    • 我认为真正的挑战在于字符串是最终的。否则答案很简单不是吗?只需扩展 String 即可。
    【解决方案6】:

    创建一个新类(它需要一个不同的包,当然,实现相同的接口并添加 String 类中的所有公共方法(阅读 javadoc 以确保您掌握了所有内容)。

    我不得不假设这是家庭作业。

    【讨论】:

      【解决方案7】:

      您可以使用重构:Replace inheritance with delegation,这基本上是(如前面的答案所示)创建所需类型的实例变量并在新类中实现其所有方法并将消息传递给它们。

      为超类创建一个字段,调整方法以委托给超类,并删除子类。

      您会注意到这需要大量输入,这时一个好的 IDE 就派上用场了。

      以下视频展示了 IntelliJ IDEA 9 是如何做到的。

      【讨论】:

        【解决方案8】:

        如果您只想覆盖部分字符串行为,您可以尝试使用动态代理。在 API 中查找 java.lang.reflect.Proxy

        【讨论】:

        • 内置动态代理支持仅适用于接口。 ASM 和其他字节码库可以使用类,但我不确定最终类。
        猜你喜欢
        • 2017-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多