为什么String的格式(Object ... args)被定义为静态方法?

时间:2009-04-27 04:43:19

标签: java string format printf

我想知道为什么 Java 5及以上版本提供了一个printf风格的格式化程序,在类String中使用静态方法,如下所示:

public static String format(String format, Object... args)

而不是

public String format(Object... args)

这样我们就可以写"%02d".format(5)来获取05而不是String.format("%02d", 5)

我想象如果我可以修改String类,我可以添加它:

public String format(Object... args) {
    return format(this, args)
}

得到相同的结果。

我发现在C#中,也使用静态方法代替实例方法。

我想知道为什么他们决定这样做,但我没有得到解释。实例方法trimsubstring返回一个新的字符串实例,因此他们应该使用format完成相同的操作。

此外,DateFormat类也使用此:

public final String format(Date date)

用于格式化日期。因此,如果我们将DateFormat的实例视为格式化程序,则String的实例也可以用作格式化程序。

有什么想法吗?

14 个答案:

答案 0 :(得分:11)

或许"%02d".format(5)似乎暗示调用format方法的对象是格式字符串。

在这种情况下,格式字符串恰好也是String,所以进一步说明,可以说所有String都是格式字符串

可以通过说String类中的静态方法可以用来格式化字符串,而不是通常对所有String做一些隐式声明来避免这种情况。

答案 1 :(得分:7)

虽然我不是Java的设计师,但我可以告诉你一个明确的理由让它变得静止。

Java 5推出了许多功能,但有两个注意事项:

  • 执行“import static”命令的功能,该命令允许在类中轻松使用静态方法,而无需列出其类名。
  • 一种轻松执行printfs的静态实用程序方法。

虽然能够通过使方法静态来说"bla: %d".format("foo"),是一件好事,但你可以使用格式,这种格式对于习惯于printf()的C程序员来说非常熟悉和清晰。< / p>

import static java.lang.String.format;

public class Demo {

   public void Test() {

      //Do some stuff

      format("Hey, this is easy to read!");

   }
 }

这就是原因!通过使用静态导入,printfs看起来几乎与他们在C. Awesome中完全一样!

答案 2 :(得分:5)

主要原因可能是Java的设计者不想在String的接口上添加太多东西。使它成为一个成员函数意味着将它放在字符串上。请记住,非静态方法必须在String对象上。

第二个原因是静态格式与C的printf保持相似, 看起来像printf(FORMAT,ARG1,ARG2 ......)

另一个原因是格式重载:有一个版本将locale作为第一个参数(在字符串之前),因此在字符串对象上执行此操作会很棘手。

答案 3 :(得分:3)

“%02d”.format(5)看起来像“%02d”使用格式5而不是相反的格式。大多数字符串也不适合作为格式(“hello world”.format(5)?),因此该方法应该为大多数字符串对象抛出异常。

答案 4 :(得分:3)

答案取决于格式化方法。

至少在我看来,“格式字符串输入到格式方法”比说“格式字符串格式化”更合乎逻辑和直观。就是这样,因为我们“通常”将格式字符串(在设计时已知)传递给Format。相反,对于Trim,我们“通常”传递变量字符串,其值在设计时是未知的。

因此,使格式化方法保持静态,使代码读取更加直观。请看下面的(C#)。

answer = String.Format("This is format string : {0}", someValue); 
//More readable to me

answer = "This is format string : {0}".Format(someValue);

编辑:尽管我使用过C#示例代码,但它很适用于Java。我得到了投票使用C#语法!

答案 5 :(得分:2)

我真的认为format必须是String的实例方法,所以

也是如此
  • 蟒:
    2.6: print "%s" % ("Hello")
    3.0: print("{0}".format("Hello"))
  • 阶:
    2.7.6:   println("%s".format("Hello"))

答案 6 :(得分:1)

调用strfmt.format(objects)而不是String.format(strfmt,objects)

  • 是一个面向对象的调用 调用静态助手。
  • 更短的类型。
  • 它更简单,因为它少了一个参数。
  • 更容易使用代码完成。如果你从开始 格式化字符串并点击。你得到了 format()作为IDE中的选项。
  • String.format(strfmt,objects)可能被意外调用为 strfmt.format(text,objects) 不会做它看起来做的事。

答案 7 :(得分:0)

可能是为了表明它是一个“实用程序”函数,为方便起见而存在,但它实际上并不是String的内在函数。也就是说,字符串"%02d"是一种表示格式的方式,但它实际上并不进行任何格式化。

该方法可以方便地格式化字符串,但Formatter(执行实际格式化)也可以格式化其他类型的对象(日期等)。

答案 8 :(得分:0)

仅仅因为这个电话让人想起C的sprintf功能。

答案 9 :(得分:0)

可能是因为String是不可变的,因此该方法必须创建并返回String实例的新实例。如果该方法未声明为static,您可能希望它修改已调用它的String实例。

答案 10 :(得分:0)

我认为Java并不是强制要求任何构造类似于其他任何构造,甚至是C ++。任何采用的都必须如此,因为开发人员接受它。此外,“他们使其与其他东西相似”这样的论点并没有解释为什么他们不只是制作一个实例方法版本,他们用原始包装器做这个(除了实例toString()方法,他们有静态版本)。

这就是我的想法:

在正常情况下,两种形式都是等价的,但假设我们有类似的东西:

String invalidFormat = "%invalid"; // or something else that is invalid

然后我们打电话:

String.format(invalidFormat, anything);
// "anything" is indeed anything....

无效成为参数,Java通过抛出IllegalArgumentException实例来澄清这一点(即使在Formatter的情况下,也有很多种类)。

然而,在某些事情上:

invalidFormat.format(anything);

无效的不再是参数。问题现在在于它被调用的实例,因此被更好地描述为“无效状态”(不是Java的“IllegalStateException”,它具有完全不同的用法)。但是因为字符串是不可变的,所以这个所谓的“状态”永远不会改变,所以它总是作为一种格式保持无效,即使它是一个有效的简单字符串。

将此与java.lang.Long进行比较。两个版本的toString都不会抛出任何异常,所以它们都是等价的。

答案 11 :(得分:0)

answer = String.Format("This is format string : {0}", someValue); 
//More readable to me

answer = "This is format string : {0}".Format(someValue);

答案 12 :(得分:0)

糟糕的设计。蟒蛇发现它很痛苦。

答案 13 :(得分:-1)

在C#中,strings are immutable。我认为在Java中也是如此(不是100%肯定)。因此,您不是通过调用格式方法来更改字符串,而是仅返回带有格式的新字符串。这使它成为类级方法而不是实例级方法,因此它是静态的。您可以使用扩展函数在C#中添加实例级别Facade,但这只是静态函数之上的语法糖。