我可以在Java的String类中添加新方法吗?

我可以在Java的String类中添加新方法吗?

Can I add new methods to the String class in Java?

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

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

谢谢并恭祝安康。


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


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

1
2
3
4
5
6
7
class MyString{
    public String str;
    public MyString(String str){
        this.str = str;
    }
    // Your methods.
}

然后,这很简单,您可以将String设置为:

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

当您需要在String库中调用方法时,可以像这样简单地进行操作:

1
StringOne.str.equals("");

或类似的东西,就在那里...扩展String类。


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

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


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

您可以随时使用辅助方法作为前缀。如果您不喜欢,可以考虑使用Groovy或Scala,JRuby或JPython都是与Java兼容的JVM语言,并且允许此类扩展。


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

1
public final class String

C#(.net 3.5)具有使用扩展程序方法的功能,但可惜的是Java没有。有一些Java扩展名为nice http://nice.sourceforge.net/,尽管这似乎为Java添加了相同的功能。

这是您使用尼斯语言编写示例的方式(
Java):

1
2
3
4
5
6
7
8
9
10
11
12
13
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上找到有关尼斯的更多信息。


就像其他人都说的那样,不可以将String归类,因为它是最终的。但是,以下内容可能会有所帮助吗?

1
2
3
4
5
6
7
8
9
10
11
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;
    }

}

或许:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
    }

}


不可能的,那是一件好事。字符串是字符串。它的行为已定义,偏离它是邪恶的。另外,它被标记为final,这意味着即使您愿意也不能将其子类化。


是!

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

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

使用Gradle和IntelliJ想法请按照以下步骤操作:

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

    1
    2
    3
    4
    5
    public class Extension {
        public static String appendSize(String i){
            return i +"" + i.length();
        }
    }
  • 在您想使用方法的地方注释类,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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(),只要您已对其进行了注释并为上述示例生成了结果

    This is a String!

    将会:

    This is a String! 17


    否,您无法在Java中修改字符串类。因为这是最后一堂课。并且默认情况下,final类中存在的每个方法都是final。

    String不可更改或最终更改的绝对最重要的原因是它由类加载机制使用,因此具有深远的基础安全方面。

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


    用关键字"将方法添加到内置类"搜索的人们可能会在这里结束。如果要向非最终类(例如HashMap)添加方法,则可以执行以下操作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    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);
        }
    }

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

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

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

    1
    objectMap.getInt("KEY");

    编辑:

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

    1
    objectMap.map.get("KEY");

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    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;
        }
    }

    现在您不必打电话

    1
    objectMap.map.get("KEY");

    只需致电

    1
    objectMap.get("KEY");

    最好使用StringBuilder,它具有方法append()并完成所需的工作。 String类是最终的,不能扩展。


    之前其他贡献者都说过了。您不能直接扩展String,因为它是最终的。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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?
      }

    Java String类是最终的,使其不可变。这是出于效率方面的考虑,并且很难在逻辑上进行扩展而不会出错。因此,实现者选择将其设为最终类,这意味着无法通过继承对其进行扩展。

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

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

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


    实际上,您可以修改String类。如果您编辑src.zip中的String.java文件,然后重建rt.jar,则String类将为您添加更多方法。缺点是该代码仅在您的计算机上可用,或者如果您提供String.class并将其放在默认代码之前的classpath中,则该代码将只在您的计算机上起作用。


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


    推荐阅读