Как работает 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() никогда не выдает ошибку.

Для меня я никогда не работал над каким-либо проектом, где это требование было таким. Если я получу такое требование, я действительно не знаю, как его решить.

Кто-нибудь может объяснить мне, как это делается?

Ответ 1

System.out - это просто экземпляр PrintStream. Вы можете проверить его JavaDoc. Его изменчивость основана на перегрузке методов (несколько методов с одним и тем же именем, но с разными параметрами).

Этот поток печати отправляет свой вывод на так называемый стандартный вывод.


В своем вопросе вы упоминаете технику, называемую переменными функциями (или переменными). К сожалению, это не поддерживается PrintStream#print, поэтому вы должны ошибиться с чем-то другим. Однако это очень легко реализовать в Java. Просто проверьте документацию.


И если вам интересно, как Java знает, как объединять "foo" + 1 + true + myObj переменные "foo" + 1 + true + myObj, это в основном является обязанностью компилятора Java.

Когда в конкатенации нет переменных, компилятор просто конкатенирует строку. Когда задействована переменная, конкатенация преобразуется в цепочку StringBuilder#append. В результирующем байтовом коде нет инструкции конкатенации; т.е. оператор + (когда речь идет о конкатенации строк) разрешается во время компиляции.

Все типы в Java могут быть преобразованы в строку (int через методы в классе Integer, boolean через методы в классе Boolean, объекты через их собственный #toString ,...). Вы можете проверить исходный код StringBuilder, если вы заинтересованы.


ОБНОВЛЕНИЕ: мне было любопытно, и я проверил (используя javap), что компилирует мой пример System.out.println("foo" + 1 + true + myObj). Результат:

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

Ответ 2

Несмотря на то, что 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 для имитации чего-то вроде C printf вы можете объявить это так:

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

Здесь происходит передача массива Strings с длиной предоставленных аргументов. Здесь Java может сделать проверку типов для вас.

Если вы действительно хотите printf, то вы должны сделать это так:

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

Тогда вы должны были бы привести или интерпретировать аргументы соответственно.

Ответ 3

Это очень чувствительный момент, чтобы понять, как работает System.out.print. Если первый элемент - String, то оператор плюс (+) работает как оператор String concate. Если первый элемент - целое число плюс (+), оператор работает как математический оператор.

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

Ответ 4

Все о Перегрузка метода.

Существуют отдельные методы для каждого типа данных в метод println()

Если вы передаете объект:

Печать объекта, а затем завершение строки. Этот метод вызывает сначала String.valueOf(x), чтобы получить значение строки печатного объекта, а затем ведет себя так, как будто он вызывает печать (String), а затем println().

Если вы пройдете примитивный тип:

соответствующие вызовы метода примитивного типа

если вы передадите строку:

соответствующий метод println (String x) вызывает

Ответ 5

Я думаю, вы путаетесь с методом printf(String format, Object... args). Первый аргумент - это строка формата, которая является обязательной, и вы можете передать произвольное число Object s.

Не существует такой перегрузки для методов print() и println().

Ответ 6

Вы можете конвертировать что угодно в String, пока вы выбираете, что печатать. Требование было довольно простым, поскольку Objet.toString() может возвращать стандартную неровную строку: package.classname + @ + object number.

Если ваш метод печати должен возвращать сериализацию 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");

напечатает что-то [email protected]! Даже если у вас есть только два члена String, и это может быть реализовано для печати

[email protected]{"field1":"a","field2":"b"}

(или в значительной степени, как он появляется в debbuger)

Ответ 7

Очевидно, что компилятор был запутан в замешательстве, хотя разработчики компилятора подумали, что они добавили некоторую сообразительность. Истинная умность, которую они должны действительно добавить, - это выглядеть целым аргументом и последовательно интерпретировать оператор+. Например, System.out.println(1+2+"hello"+3+4); должен выводить 3hello7 вместо 3hello34

Ответ 8

@ikis, во-первых, как сказал @Devolus, это не многократные вызовы, передаваемые в print(). Действительно, все эти переданные аргументы объединяются в одну строку. Таким образом, print() не использует несколько аргументов (иначе как var-args). Теперь остается обсудить, как print() печатает любой тип аргумента, переданного ему.

Чтобы объяснить это - toString() является секретом:

System представляет собой класс, со статическим полем out, типа PrintStream. Итак, вы вызываете метод println(Object x) для PrintStream.

Это реализовано так:

 public void println(Object x) {
   String s = String.valueOf(x);
   synchronized (this) {
       print(s);
       newLine();
   }
}

Как мы видим, он вызывает метод String.valueOf(Object). Это реализовано следующим образом:

 public static String valueOf(Object obj) {
   return (obj == null) ? "null" : obj.toString();
}

И здесь вы видите, что вызывается toString().

Таким образом, все, что возвращается из метода toString() этого класса, тоже печатается.

И, как мы знаем, toString() находится в классе Object и, таким образом, наследует реализацию по умолчанию от Object.

ex: Помните, когда у нас есть класс, toString() мы переопределяем, а затем передаем эту переменную ref в print, что вы видите напечатанным? - Это то, что мы возвращаем из toString().

Ответ 9

Сценарии, которые вы упомянули, не перегружены, вы просто объединяете различные переменные со строкой.

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);

во всех этих случаях вы вызываете только print (String s), потому что когда что-то объединяется со строкой, оно преобразуется в String, вызывая toString() этого объекта, и примитивы напрямую соединяются. Однако, если вы хотите узнать о разных сигнатурах, тогда print() перегружается для различных аргументов.