System.out.print()如何工作?

我已经使用Java很长一段时间了,我想知道函数System.out.print()是如何工作的。

这是我的疑问:

作为一个函数,它在io包中的某个地方有一个声明。 但是Java开发人员是如何做到这一点的,因为这个函数可以接受任意数量的参数和任何参数类型,无论它们如何排列? 例如:

 System.out.print("Hello World"); System.out.print("My name is" + foo); System.out.print("Sum of " + a + "and " + b + "is " + c); System.out.print("Total USD is " + usd); 

无论变量a, b, c, usd, foo或它们如何传递的数据类型是什么, System.out.print()不会抛出错误。

对我来说,我从未参与任何需求如此的项目。 如果我得到这样的要求,我真的不知道如何解决它。

任何人都可以向我解释它是如何完成的吗?

System.out只是PrintStream一个实例。 您可以检查其JavaDoc 。 它的可变性基于方法重载 (具有相同名称但具有不同参数的多个方法)。

此打印流将其输出发送到所谓的标准输出


在你的问题中,你提到了一种称为可变函数 (或变量函数 )的技术。 不幸的是, PrintStream#print不支持,所以你必须把它误认为是别的。 但是,在Java中实现它们非常容易。 只需查看文档。


如果你很好奇Java如何连接非字符串变量"foo" + 1 + true + myObj ,它主要负责Java编译器。

当连接中没有涉及变量时,编译器只是连接字符串。 当涉及变量时,连接将转换为StringBuilder#append chain。 结果字节代码中没有连接指令; 即在编译期间解析+运算符(当谈论字符串连接时)。

Java中的所有类型都可以转换为字符串( int通过Integer类中的方法, boolean通过Boolean类中的方法,对象通过自己的#toString ,…)。 如果您有兴趣,可以查看StringBuilder的源代码。


更新:我很好奇自己并检查(使用javap )我的示例System.out.println("foo" + 1 + true + myObj)编译成。 结果:

 System.out.println(new StringBuilder("foo1true").append(myObj).toString()); 

即使看起来好像System.put.print...()采用可变数量的参数,它也不会。 如果你仔细观察,字符串只是连接在一起,你可以对任何字符串做同样的事情。 唯一发生的事情是,传入的对象被java调用toString()方法隐式转换为字符串。

如果您尝试这样做,它将失败:

  int i = 0; String s = i; System.out.println(s); 

原因是,因为这里隐式转换没有完成。

但是,如果您将其更改为

  int i = 0; String s = ""+i; System.out.println(s); 

它工作正常,这也是使用System.put.print...()时发生的情况。

如果你想在java中实现可变数量的参数来mimimc像C printf你可以这样声明:

 public void t(String s, String ... args) { String val = args[1]; } 

这里发生的是传入一个字符串数组,其中包含所提供参数的长度。 这里Java可以为您进行类型检查。

如果你想真正的printf那么你必须这样做:

 public void t(String s, Object ... args) { String val = args[1].toString(); } 

那么你是否必须相应地演绎或解释这些论点。

我认为你对printf(String format, Object... args)方法感到困惑。 第一个参数是格式字符串,这是必需的,其余的可以传递任意数量的Object

print()println()方法都没有这样的重载。

它的全部是关于方法重载 。

println()方法中的每种数据类型都有单独的方法

如果传递对象:

打印一个对象,然后终止该行。 此方法首先调用String.valueOf(x)来获取打印对象的字符串值,然后表现为调用print(String)然后调用println()。

如果您传递原始类型:

相应的原始类型方法调用

如果你传递字符串:

对应的println(String x)方法调用

只要选择要打印的内容,就可以将任何内容转换为String。 由于Objet.toString()可以返回默认的哑字符串: package.classname + @ + object number因此要求非常简单。

如果您的print方法应返回XML或JSON序列化,则toString()的基本结果将不可接受。 即使该方法成功。

这是一个简单的例子,表明Java可能是愚蠢的

 public class MockTest{ String field1; String field2; public MockTest(String field1,String field2){ this.field1=field1; this.field2=field2; } } System.out.println(new MockTest("a","b"); 

将打印一些package.Mocktest@3254487 ! 即使您只有两个String成员,也可以实现打印

 Mocktest@3254487{"field1":"a","field2":"b"} 

(或几乎如何在debbuger中出现)

显然,尽管编译器开发人员认为它们增加了一些智能,但编译器仍然以令人困惑的方式制作。 他们真正应该添加的真正聪明之处在于查看整个论证并始终如一地解释+运算符。 例如, System.out.println(1+2+"hello"+3+4); 应该输出3hello7而不是3hello34

了解如何使用System.out.print是一个非常敏感的问题。 如果第一个元素是String,则plus(+)运算符用作Strig concate运算符。 如果第一个元素是整数加(+)运算符,则作为数学运算符。

 public static void main(String args[]) { System.out.println("String" + 8 + 8); //String88 System.out.println(8 + 8+ "String"); //16String }