28

我想AddDefaultNamespace()在 Java 中的 String 类中添加一个方法,以便我可以键入"myString".AddDefaultNamespace()而不是DEFAULTNAMESPACE + "myString", 以获得类似"MyDefaultNameSpace.myString". 我也不想添加另一个派生类(PrefixedString例如)。

也许这种方法对您不利,但我个人讨厌使用+. 但是,无论如何,是否可以在 Java 中向 String 类添加新方法?

谢谢并恭祝安康。

4

15 回答 15

67

String是一个最终类,这意味着它不能扩展为在您自己的实现上工作。

于 2008-09-17T10:25:49.900 回答
27

好吧,实际上每个人都缺乏想象力。我需要编写自己的startsWith 方法版本,因为我需要一个不区分大小写的方法。

class MyString{
    public String str;
    public MyString(String str){
        this.str = str;
    }
    // Your methods.
}

那么这很简单,你可以这样制作你的字符串:

MyString StringOne = new MyString("Stringy stuff");

当您需要调用 String 库中的方法时,只需这样做:

StringOne.str.equals("");

或类似的东西,你有它...... String 类的扩展。

于 2011-07-24T11:09:13.633 回答
19

正如其他人所指出的那样,您不允许扩展 String (由于 final )。但是,如果您真的很疯狂,您可以修改 String 本身,将其放入 jar 中,并在 bootclasspath 前面加上 -Xbootclasspath/p:myString.jar 以实际替换内置的 String 类。

由于我不会进入的原因,我实际上之前已经这样做过。您可能有兴趣知道,即使您可以替换该类,但 String 在 Java 的各个方面的内在重要性意味着它在整个 JVM 启动过程中都会使用,并且某些更改只会破坏 JVM。添加新方法或构造函数似乎没有问题。添加新字段非常冒险 - 特别是添加对象或数组似乎会破坏事物,尽管添加原始字段似乎有效。

于 2008-09-17T14:01:02.877 回答
6

这是不可能的,因为 String 是 Java 中的 final 类。

您可以一直使用辅助方法来为某些内容添加前缀。如果你不喜欢,你可以研究一下 Groovy 或 Scala、JRuby 或 JPython,它们都是与 Java 兼容的 JVM 语言,并且允许此类扩展。

于 2008-09-17T10:27:42.390 回答
3

类声明几乎说明了一切,因为你不能继承它,因为它是最终的。您当然可以实现自己的字符串类,但这很可能只是一个麻烦。

public final class String

C# (.net 3.5) 具有使用扩展方法的功能,但遗憾的是 java 没有。有一些名为 nice http://nice.sourceforge.net/的 java 扩展,虽然这似乎为 java 添加了相同的功能。

以下是您将如何使用 Nice 语言(Java 的扩展)编写示例:

private String someMethod(String s)
{
   return s.substring(0,1);

}

void main(String[] args)
{
   String s1 = "hello";
   String s2 = s1.someMethod();
   System.out.println(s2);

}

您可以在http://nice.sf.net找到更多关于尼斯的信息

于 2008-09-17T10:34:45.290 回答
3

是的!

根据您的要求(向 String 添加不同的命名空间而不使用派生类),您可以使用 Lombok 项目来做到这一点,并在 String 上使用如下功能:

String i = "This is my String";
i.numberOfCapitalCharacters(); // = 2

使用 Gradle 和 IntelliJ IDEA 的步骤如下:

  1. 从 intelliJ 插件存储库下载 lombok 插件。
  2. 将 lombok 添加到 gradle 中的依赖项,如下所示:compileOnly 'org.projectlombok:lombok:1.16.20'
  3. 转到"Settings > Build > Compiler > Annotation Processors"并启用注释处理
  4. 使用您的扩展函数创建一个类并添加一个静态方法,如下所示:

    public class Extension {
        public static String appendSize(String i){
            return i + " " + i.length();
        }
    }
    
  5. 注释要在其中使用方法的类,如下所示:

    import lombok.experimental.ExtensionMethod;
    
    @ExtensionMethod({Extension.class})
    public class Main {
        public static void main(String[] args) {
            String i = "This is a String!";
            System.out.println(i.appendSize());
        }
    }
    

现在您可以.appendSize()在任何类中的任何字符串上使用该方法,只要您已对其进行注释并为上述示例生成结果

这是一个字符串!

将会:

这是一个字符串!17

于 2018-05-18T13:54:45.250 回答
2

不可能,这是一件好事。一个字符串就是一个字符串。它的行为是有定义的,偏离它就是邪恶的。此外,它被标记为 final,这意味着即使你想也不能继承它。

于 2008-09-17T10:29:20.703 回答
2

正如其他人所说,不,你不能继承 String 因为它是最终的。但是可能会有类似以下的帮助吗?

public final class NamespaceUtil {

    // private constructor cos this class only has a static method.
    private NamespaceUtil() {}

    public static String getDefaultNamespacedString(
            final String afterDotString) {
        return DEFAULT_NAMESPACE + "." + afterDotString;
    }

}

或许:

public final class NamespacedStringFactory {

    private final String namespace;

    public NamespacedStringFactory(final String namespace) {
        this.namespace = namespace;
    }

    public String getNamespacedString(final String afterDotString) {
        return namespace + "." + afterDotString;
    }

}
于 2008-09-17T10:47:34.357 回答
2

使用关键字“将方法添加到内置类”搜索的人可能会在这里结束。如果您希望将方法添加到诸如 HashMap 之类的非 final 类中,您可以执行类似的操作。

public class ObjectMap extends HashMap<String, Object> {

    public Map<String, Object> map;

    public ObjectMap(Map<String, Object> map){
        this.map = map;
    }

    public int getInt(String K) {
        return Integer.valueOf(map.get(K).toString());
    }

    public String getString(String K) {
        return String.valueOf(map.get(K));
    }

    public boolean getBoolean(String K) {
        return Boolean.valueOf(map.get(K).toString());
    }

    @SuppressWarnings("unchecked")
    public List<String> getListOfStrings(String K) {
        return (List<String>) map.get(K);
    }

    @SuppressWarnings("unchecked")
    public List<Integer> getListOfIntegers(String K) {
        return (List<Integer>) map.get(K);
    }

    @SuppressWarnings("unchecked")
    public List<Map<String, String>> getListOfMapString(String K) {
        return (List<Map<String, String>>) map.get(K);
    }

    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> getListOfMapObject(String K) {
        return (List<Map<String, Object>>) map.get(K);
    }

    @SuppressWarnings("unchecked")
    public Map<String, Object> getMapOfObjects(String K) {
        return (Map<String, Object>) map.get(K);
    }

    @SuppressWarnings("unchecked")
    public Map<String, String> getMapOfStrings(String K) {
        return (Map<String, String>) map.get(K);
    }
}

现在将此类的新实例定义为:

ObjectMap objectMap = new ObjectMap(new HashMap<String, Object>();

现在您可以访问内置 Map 类的所有方法,以及新实现的方法。

objectMap.getInt("KEY");

编辑:

在上面的代码中,要访问地图类的内置方法,您必须使用

objectMap.map.get("KEY");

这是一个更好的解决方案:

public class ObjectMap extends HashMap<String, Object> {

    public ObjectMap() {

    }

    public ObjectMap(Map<String, Object> map){
        this.putAll(map);
    }

    public int getInt(String K) {
        return Integer.valueOf(this.get(K).toString());
    }

    public String getString(String K) {
        return String.valueOf(this.get(K));
    }

    public boolean getBoolean(String K) {
        return Boolean.valueOf(this.get(K).toString());
    }

    @SuppressWarnings("unchecked")
    public List<String> getListOfStrings(String K) {
        return (List<String>) this.get(K);
    }

    @SuppressWarnings("unchecked")
    public List<Integer> getListOfIntegers(String K) {
        return (List<Integer>) this.get(K);
    }

    @SuppressWarnings("unchecked")
    public List<Map<String, String>> getListOfMapString(String K) {
        return (List<Map<String, String>>) this.get(K);
    }

    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> getListOfMapObject(String K) {
        return (List<Map<String, Object>>) this.get(K);
    }

    @SuppressWarnings("unchecked")
    public Map<String, Object> getMapOfObjects(String K) {
        return (Map<String, Object>) this.get(K);
    }

    @SuppressWarnings("unchecked")
    public Map<String, String> getMapOfStrings(String K) {
        return (Map<String, String>) this.get(K);
    }

    @SuppressWarnings("unchecked")
    public boolean getBooleanForInt(String K) {
        return Integer.valueOf(this.get(K).toString()) == 1 ? true : false;
    }
}

现在你不必打电话

objectMap.map.get("KEY");

只需调用

objectMap.get("KEY");
于 2016-05-24T06:50:26.937 回答
1

更好地使用 StringBuilder,它具有方法 append() 并且可以完成您想要的工作。String 类是最终的,不能扩展。

于 2008-09-17T10:29:24.180 回答
1

不,您不能在 java 中修改字符串类。因为这是最后一节课。并且默认情况下存在于最终类中的每个方法都是最终的。

String 是不可变或 final 的绝对最重要的原因是它被类加载机制使用,因此具有深刻和基本的安全方面。

如果 String 是可变的或不是最终的,加载“java.io.Writer”的请求可能已更改为加载“mil.vogoon.DiskErasingWriter”

于 2017-07-24T13:50:02.047 回答
0

Java String 类是 final 类,使其不可变。这是出于效率原因,并且在逻辑上没有错误地扩展将是极其困难的;因此,实现者选择使其成为最终类,这意味着它不能通过继承进行扩展。

根据单一职责原则,您希望您的类支持的功能不是 String 的常规职责的一部分,它是一个不同的抽象,它更专业。因此,您应该定义一个新类,其中包括 String 一个成员并支持您提供所需的命名空间管理所需的方法。

不要害怕添加抽象(类),这些是良好 OO 设计的精髓。

尝试使用类责任协作 (CRC) 卡 来阐明您需要的抽象。

于 2008-09-17T10:38:53.363 回答
0

以上都是其他贡献者所说的。您不能直接扩展 String 因为它是最终的。

如果您要使用 Scala,则可以使用如下隐式转换:

object Snippet {
  class MyString(s:String) {
    def addDefaultNamespace = println("AddDefaultNamespace called")
  }
  implicit def wrapIt(s:String) = new MyString(s)

  /** test driver */
  def main(args:Array[String]):Unit = {
    "any java.io.String".addDefaultNamespace // !!! THAT is IT! OR?
  }
于 2010-01-16T14:11:19.477 回答
-2

您可以创建自己的 String 类版本并添加一个方法 :-)

于 2008-09-17T10:39:01.320 回答
-2

实际上,您可以修改 String 类。如果您编辑位于 src.zip 中的 String.java 文件,然后重新构建 rt.jar,则 String 类将拥有更多由您添加的方法。缺点是该代码只能在您的计算机上运行,​​或者如果您提供您的 String.class,并将其放置在默认路径之前的类路径中。

于 2008-09-17T10:41:39.173 回答