2010-01-23 21 views
5

Sabemos que cuando usamos objetos en la instrucción sysout (System.out.Println) internamente se llama al método toString. y con primitiva imprime directamente. pero cuando utilizamos cualquier tipo clase contenedora de objetos se utiliza decir Entero supongo que como siguienteunboxing o toString() se usa en sysout en java

 Integer i = new Integer(10) 
     System.out.Println(i); 

es toString() es responsable de la impresión o Unboxing?

+0

Creo que solo sería unbox en casos donde int era la única opción. Dado que hay un println (Object), probablemente lo llamen. –

+0

@gurukulki, actualizado por respuesta espero que ayude. –

Respuesta

10

una prueba y depuración rápida de comportamiento muestra que print(Object) se invoca, no print(int).

Una buena manera de comprobar esto es:

Integer val = null; 
System.out.print(val); 

Si se utilizara un-boxing, esto sería lanzar una NullPointerException. Esto no sucede, sin embargo, se imprime la cadena null, que es la salida de String.valueOf(Object) cuando un nulo se pasa.

Otro aspecto a tener en cuenta es que PrintStream existía antes de Java 5. Cuando se introdujo en autoboxing Java 5, se tenía que asegurar que cualquier código existente que usara PrintStream no cambiara repentinamente su comportamiento.Por lo tanto, cualquier código existente que llame al print(Object) no debe cambiar repentinamente su comportamiento para llamar al print(int), simplemente debido a una nueva función de idioma. La compatibilidad con versiones anteriores siempre se debe mantener.

+1

(+1) perspicaz :) – Bozho

+1

Esto es interesante, pero ¿es concluyente? Podría haber un nulo 'if' manejando nulos. –

+0

Un 'si' ¿dónde? Aquí no hay magia, y si anulas un nulo, * siempre * lanzará un NPE. – skaffman

4

Todo esto es anterior a autoboxing, que se introdujo en 1.5. El código que responde a estas preguntas, o los documentos de la API, no ha cambiado para 1.5+.

Básicamente, al final de la línea está el método toString para no primitivos como instancias de Integer.

Primero, con primitivos, hay un tratamiento diferente para cada uno. Para int, por ejemplo

Imprime un número entero. La cadena producida por String.valueOf (int) se traduce en bytes según la codificación de caracteres por defecto de la plataforma, y ​​estos bytes se escriben exactamente de la manera del método de escritura (int).

Pero para objetos como Integer, println llama print cuales:

Imprimir un objeto. La cadena producida por el método String.valueOf (Objeto) se traduce en bytes según de la plataforma de caracteres por defecto codificación, y estos bytes se escriben exactamente de la forma del método de escritura (int).

¿Qué significa valueOf usar? Esta es la respuesta a su pregunta: para Integer se llama su método toString. Esto es a partir de los documentos en String.valueOf

si el argumento es nulo, una cadena igual a "cero"; de lo contrario, se devuelve el valor de obj.toString().

+1

¿Qué quieres explicar aquí? mi pregunta es simple toString() o Unboxing? ¿Cuál es el responsable? – GuruKulki

+0

arreglando mi respuesta ahora para aclarar eso ... –

5

(...) pero cuando utilizamos cualquier tipo de clase Envoltura de objetos se usa decir suponer Entero como seguir

Integer i = new Integer(10) 
    System.out.println(i); 

es que toString() es responsable de la impresión o Unboxing ?

Estás pasando un Object a println por lo que es, obviamente, println(Object obj) que se llama el que escribe la salida de String.valueOf(obj) que exige obj.toString() si obj no es null.

PD: Sin ánimo de ofender, ¿por qué no mira las fuentes?

Actualización: Quizás me haya perdido el sentido de la pregunta (lo cual es engañoso en su forma actual si puedo). En realidad, la pregunta podría ser:

(...) pero cuando utilizamos cualquier tipo clase de contenedor se utiliza de objetos decir supongamos Entero como seguir

Integer i = new Integer(10) 
    System.out.println(i); 

¿Qué método se llama: println(Object) o println(int)?

Si esto es de lo que se trata la pregunta, entonces la respuesta yace por supuesto en The Java Language Specification. Para simplificar, el método invocado en tiempo de ejecución será el método que se determina en tiempo de compilación. Ahora, ¿cómo determina el compilador el método que se invocará? Bueno, esto se explica en la sección 15.12 Method Invocation Expressions. No cubriré todos los detalles, la especificación lo hace mejor que yo pero, básicamente, el primer paso es encontrar la clase o interfaz para buscar, el segundo paso es encontrar todos los métodos aplicables y luego recoger los más específicos método, el tercer paso es verificar si el método elegido es apropiado. Me centraré en el segundo paso (que es el más interesante aquí). Como se detalla en la sección 15.12.2 Compile-Time Step 2: Determine Method Signature:

Un método es aplicable si es o bien aplicable por subtipificación (§15.12.2.2), aplicable por invocación de método conversión (§15.12.2.3), o que es un método aridad variable de aplicable (§15.12.2.4).

El proceso de determinar aplicabilidad comienza determinando los métodos potencialmente aplicables (§15.12.2.1). El resto del proceso se divide en tres fases.


Discusión

El propósito de la división en fases es asegurar la compatibilidad con las versiones anteriores de la programación en Java idioma.


la primera fase (§15.12.2.2) realiza sobrecarga de resolución sin boxeo permitiendo o unboxing conversión , o el uso de la variable aridad invocación de método. Si no se encuentra el método aplicable durante esta fase , el procesamiento continúa hasta la segunda fase .


Discusión

Esto garantiza que cualquier llamada que eran válidos en las versiones anteriores de la lengua no se consideran ambigua como resultado de la introducción de métodos Arity variables, implícita boxeo y/o unboxing.


la segunda fase (§15.12.2.3) realiza sobrecarga resolución mientras permitiendo boxeo y unboxing, pero todavía impide el uso de la variable aridad invocación de método. Si no se encuentra el método aplicable durante esta fase , el procesamiento continúa hasta la tercera fase .


Discusión

Esto asegura que una variable método aridad Nunca se invoca si existe un método aridad fijo aplicable .


La tercera fase (§15.12.2.4) permite la sobrecarga para ser combinado con métodos Arity variables, el boxeo y unboxing.

decidir si un método es voluntad aplicable, en el caso de métodos genéricos (§8.4.4), requieren que los argumentos de tipo real sean determinar. Los argumentos de tipo reales pueden pasar explícita o implícitamente. Si se pasan de forma implícita, deben inferirse (§15.12.2.7) a partir de los tipos de las expresiones de argumento.

Si han han identificado varios métodos aplicables durante uno de los tres fases de pruebas aplicabilidad, entonces se elige el más específico, como se especifica en la sección §15.12.2.5. Consulte las siguientes subsecciones para obtener detalles sobre .

En este caso particular, println(Obj) es aplicable por subtipificación (y println(int) sería aplicable por conversión invocación como el boxeo/unboxing es una conversión (§5.3)). Entonces el compilador ingresará el phase 1. Y si miramos la última oración:

Si no se encuentra un método aplicable por subtipificación, la búsqueda de los métodos aplicables continúa con la fase 2 (§15.12.2.3). De lo contrario, el método más específico (§15.12.2.5) se elige entre los métodos que se aplican al subtipar.

Aquí, no hay otros métodos aplicables por subtipificación por lo que este es el final, println(Object) se invocará (y por lo tanto toString() será llamada, responder a la pregunta inicial).

+0

, tengo una duda de que puede unbox e imprimir la primitiva int – GuruKulki

+0

@Pascal: Esto no es realmente un problema de la API, sin embargo, se trata de si el lenguaje prefiere el desempaquetado a pasando el objeto. – skaffman

+0

@skaffman, es un problema de API y tiene que ver con cómo se especifica la API de cadena. El comportamiento de String, al ser un objeto y no un primitivo, está determinado por la API. –