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

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

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返回一个新的string实例,所以他们应该用format做同样的事情。

而且, DateFormat类也使用这个:

 public final String format(Date date) 

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

有任何想法吗?

也许"%02d".format(5)似乎意味着调用format方法的对象是格式字符串。

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

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

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

Java 5出现了许多function,但有两个注意事项:

  • 能够执行“导入静态”命令,允许在类中轻松使用静态方法,而无需列出其类名。
  • 一种静态实用程序方法,可以轻松执行printfs。

虽然能够说"bla: %d".format("foo"),很高兴"bla: %d".format("foo"),通过使方法成为静态,您可以使用格式,这种方式对于习惯于printf() C程序员来说非常熟悉和清晰。 printf()

 import static java.lang.String.format; public class Demo { public void Test() { //Do some stuff format("Hey, this is easy to read!"); } } 

这就是原因! 通过使用静态导入,printfs看起来几乎就像在C中一样。太棒了!

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

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

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

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

答案在于格式方法的责任。

至少在我看来,“格式字符串输入到格式方法”比说“格式字符串格式化”更合乎逻辑和直观。 就是这样,因为我们“通常”将格式字符串(在设计时已知)传递给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#语法!

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

  • python:
      2.6:打印“%s”%(“你好”) 
      3.0:print(“{0}”。format(“Hello”)) 
  • 斯卡拉:
      2.7.6:println(“%s”。format(“Hello”)) 

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

  • 是面向对象的调用,而不是对静态帮助器的调用。
  • 它的类型更短。
  • 它更简单,因为它有一个较少的论点。
  • 它更容易使用代码完成。 如果你从格式字符串开始并点击。 您将format()作为IDE中的选项。
  • String.format(strfmt,objects)可能被意外地称为strfmt.format(text,objects),它们不会像它看起来那样做。

仅仅因为这个电话让人想起C的sprintffunction。

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

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

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

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

这就是我的想法:

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

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

然后我们打电话给:

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

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

但是,在这样的事情:

 invalidFormat.format(anything); 

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

比较一下,例如java.lang.Long。 两个版本的toString都不会抛出任何exception,所以它们都是等价的。

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

只是糟糕的设计。 python发现它很痛苦。

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