100% encontró este documento útil (3 votos)
5K vistas722 páginas

Head First Java Traducido

Cargado por

gaston
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
100% encontró este documento útil (3 votos)
5K vistas722 páginas

Head First Java Traducido

Cargado por

gaston
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Machine Translated by Google

Machine Translated by Google

Lo que están diciendo sobre Cabeza Primero


Machine Translated by Google

Elogios para Cabeza Primero Java


Machine Translated by Google

alabanza para otros Cabeza Primero libros en coautoría de Kathy y Bert


Machine Translated by Google

Otros libros sobre Java de O'Reilly

Primero los patrones de diseño


Primero los servlets
Cabeza primero EJB™

Hormiga: La Guía Definitiva™


Mejor, más rápido y más ligero Java™
Enterprise JavaBeans™
Hibernate: un cuaderno para desarrolladores
Java™ 1.5 Tiger: un cuaderno para desarrolladores
Libro de recetas de
Java™ Java™ en pocas
palabras Programación de redes Java™
Libro de recetas de servlets y JSP Java™
Java™ Swing
JavaServer Faces™
JavaServer Pages™
Programación de Jakarta Struts
Tomcat: la guía definitiva

Esté atento a más libros de la serie Head First.


Machine Translated by Google

Dirígete primero a Java™


Segunda edicion

¿No sería fantástico si


hubiera un libro sobre Java
que fuera más estimulante
que esperar en la cola del
DMV para renovar la licencia
de conducir? Probablemente
sea sólo una fantasía...

Kathy Sierra
Bert Bates

Beijing • Cambridge • Colonia • París • Sebastopol • Taipei • Tokio


Machine Translated by Google

Dirígete primero a Java™


Segunda edicion

Editor:

Diseñador de la portada:

Diseñadores de interiores:

Historial de impresión:
Machine Translated by Google
Machine Translated by Google

Creadores de la serie Head First

Kathy Sierra

Bert Bates

Aunque Kathy y Bert intentan responder tantos correos electrónicos como pueden, el volumen de correo y su agenda de viajes lo hacen
difícil. La mejor forma (más rápida) de obtener ayuda técnica con el libro es en el muy activo foro para principiantes de Java en [Link].
Machine Translated by Google

Tabla de contenidos (resumen)


Introducción xxi

1 Rompiendo la superficie: un chapuzón rápido 1

2 Un viaje a Objectville: sí, habrá objetos 27

3 Conozca sus variables: primitivas y referencias 49

4 Cómo se comportan los objetos: el estado del objeto afecta el comportamiento del método 71

5 Métodos extrafuertes: control de flujo, operaciones y más 95

6 Usando la biblioteca Java: para que no tengas que escribirlo todo tú mismo 125

7 Vivir mejor en Objectville: planificar el futuro 165

8 Polimorfismo serio: explotación de clases e interfaces abstractas 197

9 Vida y muerte de un objeto: constructores y gestión de memoria 235

10 Los números importan: matemáticas, formato, envoltorios y estática 273

11 Comportamiento riesgoso: manejo de excepciones 315

12 Una historia muy gráfica: introducción a la GUI, manejo de eventos y clases internas 353

13 Trabaja en tu swing: administradores de diseño y componentes 399

14 Guardar objetos: serialización y E/S 429

15 Haga una conexión: sockets de red y subprocesos múltiples 471

16 Estructuras de datos: colecciones y genéricos 529

17 Libere su código: empaquetado e implementación 581

18 Computación distribuida: RMI con una pizca de servlets, EJB y Jini 607

A Apéndice A: Código final cocina 649

B Apéndice B: Diez cosas principales que no se incluyeron en el resto del libro 659

Índice 677

Tabla de contenidos (la versión completa)

yo introducción
Tu cerebro en Java.

¿Para quién es este libro? XXII

Lo que tu cerebro está pensando xxiii

Metacognición xxvi

Dobla tu cerebro hacia la sumisión xxvii

Lo que necesitas para este libro. xxviii

editores técnicos xxx

Agradecimientos xxxi

ix
Machine Translated by Google

1 Rompiendo la superficie
Java te lleva a nuevos lugares.

La forma en que funciona Java 2


Virtual
Estructura del código en Java 7
Máquinas
anatomía de una clase 8

El método principal() 9

Método Partido() 11
Bucle
0 carga_0
Ramificación condicional (si hay pruebas) 13
1 invokespe­
cial #1 <Método
Codificando la aplicación “99 botellas de cerveza” 14
[Link]()>
Frase­o­matic dieciséis

4 regreso

Charla informal: compilador frente a JVM 18


Código de
usted apuesta

Dispararme

Ejercicios y rompecabezas 20
bytes compilado

Un viaje a Objectville
2 Me dijeron que habría objetos.

Chair Wars (Brad, el chico de OO, contra Larry, el chico de procedimientos) 28

Herencia (una introducción) 31

Métodos primordiales (una introducción) 32

¿Qué hay en una clase? (métodos, variables de instancia) 34

Creando tu primer objeto usando 36

main() 38

Código del juego de adivinanzas 39

Ejercicios y rompecabezas 42

X
Machine Translated by Google

3
Conozca sus variables
Las variables vienen en dos tipos: primitivas y de referencia.

Declarar una variable (A Java le importa el tipo) 50


24
Tipos primitivos (“Me gustaría un doble con espuma extra, por favor”) 51
tamaño

palabras clave de Java 53


En t
Variables de referencia (control remoto a un objeto) 54

Ct
mi 55
Doh gramo bj
oh
Declaración y asignación de objetos.

Objetos en el montón de basura recolectable 57

fido Matrices (una primera mirada) 59

Ejercicios y rompecabezas 63

Referencia de perro

4
Cómo se comportan los objetos
El estado afecta el comportamiento, el comportamiento afecta al estado.

Los métodos utilizan el estado del objeto (ladrido diferente) 73


pasar por valor significa 74
Argumentos del método y tipos de retorno

pasar por copia Pasar por valor (la variable siempre se copia) 77

Captadores y definidores 79

Encapsulación (hazlo o corre el riesgo de ser humillado) 80


copia de x
Usar referencias en una matriz 83
00000111
00000111 Ejercicios y rompecabezas 88

X z
En t En t

[Link](x); vacío ir(int z){ }

xi
Machine Translated by Google

5 métodos extrafuertes
Pongamos algo de fuerza en nuestros métodos.

vamos a construir el
Hundir un juego Dot Com
Construyendo el juego Sink a Dot Com 96

Comenzando con el juego Simple Dot Com (una versión más simple) 98

Escribir prepcode (pseudocódigo para el juego) 100

Código de prueba para Simple Dot Com 102

Codificando el juego Simple Dot Com 103

Código final para Simple Dot Com 106

Generando números aleatorios con [Link]() 111

Código listo para obtener la entrada del usuario desde la línea de comandos. Bucles 112

con bucles for . 114

Convertir primitivas de un tamaño grande a un tamaño más pequeño 117

Convertir una cadena en un int con [Link]() 117

Ejercicios y rompecabezas 118

Usando la biblioteca Java


6 Java viene con cientos de clases prediseñadas.

Analizando el error en el juego Simple Dot Com 126

ArrayList (aprovechando la API de Java) 132

Arreglando el código de clase DotCom 138

Construyendo el juego real (Sink a Dot Com) 140


­ Julia, 31 años, modelo de mano. 144
Código de preparación para el juego real

Código para las expresiones 146

booleanas del juego real . 151

Usando la biblioteca (Java API) 154

Uso de paquetes (declaraciones de importación, nombres completos) 155

Uso de los documentos y libros de referencia de la API HTML 158

Ejercicios y rompecabezas 161

xiii
Machine Translated by Google

7 Vivir mejor en Objectville


Planifique sus programas pensando en el futuro.

Comprender la herencia (relaciones de superclase y subclase) 168

Diseñar un árbol de herencia (la simulación animal) 170

hazlo pegado Evitar código duplicado (usando herencia) 171

Métodos primordiales 172

IS­A y HAS­A (chica de la bañera) 177

¿Qué heredas de tu superclase? 180

¿Qué te compra realmente la herencia ? 182

Polimorfismo (usando una referencia de supertipo a un objeto de subclase) 183

Reglas para anular (¡no toque esos argumentos y tipos de retorno!) 190

Sobrecarga de métodos (nada más que reutilización del nombre del método) 191

Ejercicios y rompecabezas 192

Polimorfismo grave

8 La herencia es sólo el comienzo.

Algunas clases simplemente no deberían ser instanciadas 200

Objeto o = [Link](id); Clases abstractas (no se pueden crear instancias) 201


Perro d = (Perro) o; 203
Métodos abstractos (deben implementarse)
[Link](); 206
Polimorfismo en acción

Objeto de clase (la superclase definitiva de todo) 208


Objeto
Sacar objetos de un ArrayList (salen como tipo Objeto) 211

oh
Doh bj mi
gramo
oh
Connecticut El compilador verifica el tipo de referencia (antes de permitirle llamar a un método) 213

Ponte en contacto con tu objeto interior 214

215
Objeto devolver el objeto
Referencias polimórficas

Convertir una referencia de objeto (moviéndose hacia abajo en el árbol de herencia) 216
d a un perro que
sabemos que está allí. 223
Diamante mortal de la muerte (problema de herencia múltiple)
Perro
Usando interfaces (¡la mejor solución!) 224

Ejercicios y rompecabezas 230

xiii
Machine Translated by Google

9 Vida y muerte de un objeto


Los objetos nacen y los objetos mueren.

La pila y el montón, donde viven los objetos y las variables. 236


Cuando alguien
Métodos en la pila 237
llama al método go(),
este pato se abandona. Donde viven las variables locales 238

Su única referencia ha Donde viven las variables de instancia 239

sido reprogramada El milagro de la creación de objetos 240

t para un Pato diferente.


DtuCk bjoh
miC Constructores (el código que se ejecuta cuando dices nuevo) 241

243
d Inicializando el estado de un nuevo pato

Constructores sobrecargados 247


Montón
t
DtuCk bjoh
miC Constructores de superclase (encadenamiento de constructores) 250

Invocar constructores sobrecargados usando this() 256


A 'd' se le asigna un nuevo objeto Duck, dejando abandonado el
vida de un objeto 258
(primer) objeto Duck original. Eso
Recolección de basura (y hacer que los objetos sean elegibles) 260
El primer pato es una tostada.

Ejercicios y rompecabezas 266

10 números importan Haz las matematicas.

Las variables estáticas


son compartidas por
todas las instancias de
una clase.

variable
estática: helado
Clase de matemáticas (¿realmente necesitas una instancia de ella?) 274
niño instancia dos
niño ejemplo uno métodos estáticos 275

variables de instancia: variables estáticas 277

una por instancia Constantes (variables finales estáticas) 282

Métodos matemáticos (aleatorio(), redondo(), abs(), etc.) 286


variables estáticas:
una por clase Clases contenedoras (entero, booleano, carácter, etc.) 287

Formato de 289

número de autoboxing 294

Formato y manipulación de fechas. 301

Importaciones estáticas 307

Ejercicios y rompecabezas 310

xiv
Machine Translated by Google

Comportamiento riesgoso

11 Estas cosas pasan.

Hacer una máquina de música (el BeatBox) 316

¿Qué pasa si necesitas llamar a un código riesgoso? 319


ohws
a miX Cmi ti
norte

htr
pag
oh
baC 320
norte

2 Las excepciones dicen "algo malo puede haber sucedido..."


k 321
El compilador garantiza ( comprueba) que eres consciente de los riesgos.

Detectar excepciones usando try/catch (patinador) 322


clase vaca {
barra de clase { muu vacío() {
ir vacío() {
326
si (servidorAbajo){

Control de flujo en bloques try/catch


1
mugir(); explotar();
} }
}
int cosas() {
}

}
[Link]();
llama al método arriesgado El bloque final (pase lo que pase, ¡apaga el horno!) 327
}

Detectar múltiples excepciones (el orden importa) 329


tu codigo clase con un
Declarar una excepción (simplemente evítala) 335
método arriesgado
Manejar o declarar la ley 337

Code Kitchen (haciendo sonidos) 339

Ejercicios y rompecabezas 348

12 UnaAcéptalo,
historia muy
necesitas gráfica
crear GUI.

clase MiExterior {

clase MiInterior { Tu primera GUI 355


ir vacío() {
} Obtener un evento de usuario 357
}
Implementar una interfaz de escucha 358
} 360
Obtener el ActionEvent de un botón

Poner gráficos en una GUI 363


Los objetos externos e internos
Diversión con paintComponent() 365
ahora están íntimamente vinculados.
t mi
r
ohtu El objeto Graphics2D 366

Poner más de un botón en una pantalla 370


Estos dos objetos del montón i nortenortemi r
Clases internas al rescate (haz de tu oyente una clase interna) 376
tienen un vínculo especial. El
interno puede usar las 382
Animación (muévelo, píntalo, muévelo, píntalo, muévelo, píntalo...)
variables del externo (y viceversa).
Code Kitchen (pintando gráficos al ritmo de la música) 386

Ejercicios y rompecabezas 394

xvi
Machine Translated by Google

Trabaja en tu swing

13 El swing es fácil.

Componentes del columpio 400

401
Los componentes Administradores de diseño (controlan el tamaño y la ubicación)
del este y del Tres administradores de diseño (borde, flujo, cuadro) 403
oeste obtienen
BorderLayout (se preocupa por cinco regiones) 404
su ancho preferido.
FlowLayout (se preocupa por el orden y el tamaño preferido) 408

BoxLayout (como flujo, pero puede apilar componentes verticalmente) 411


Las cosas en
el norte y 413
JTextField (para entrada de usuario de una sola línea)
El centro se queda
en el sur obtienen con lo que queda. 414
JTextArea (para texto con desplazamiento de varias líneas)
su altura preferida.
JCheckBox (¿está seleccionado?) 416

JList (una lista desplazable y seleccionable) 417

Code Kitchen (The Big One: creación del cliente de chat BeatBox) 418

Ejercicios y rompecabezas 424

14 objetos deseahorro
Los objetos pueden aplanar e inflar.

Guardando el estado del objeto 431


serializado
Escribir un objeto serializado en un archivo 432

Flujos de entrada y salida de Java (conexiones y cadenas) 433

Serialización de objetos 434

¿Alguna pregunta? Implementación de la interfaz serializable 437

Usando variables transitorias 439

deserializado 441
Deserializar un objeto

Escribir en un archivo de texto 447

[Link] 452

Lectura de un archivo de texto 454

División de una cadena en tokens con split() 458

CódigoCocina 462

Ejercicios y rompecabezas 466

xvi
Machine Translated by Google

Hacer una conexión


15 Conéctate con el mundo exterior.

Conexión de socket
al puerto 5000
en Descripción general del programa de chat 473
del servidor en
[Link] Conexión, envío y recepción 474

Tomas de red 475

Puertos TCP 476

Leer datos de un socket (usando BufferedReader) 478

Escribir datos en un socket (usando PrintWriter) 479

Cliente Servidor 480


Conexión de socket Redacción del programa Daily Advice Client
de regreso al cliente Escribiendo un servidor simple 483
en [Link],
Código del servidor de asesoramiento diario 484
puerto 4242
Escribir un cliente de chat 486

Múltiples pilas de llamadas 490

Lanzando un nuevo hilo (hazlo, inícialo) 492

La interfaz Runnable (el trabajo del hilo) 494

Tres estados de un nuevo objeto Thread (nuevo, ejecutable, en ejecución) 495

El bucle ejecutable­en ejecución 496

Programador de hilos (es su decisión, no la tuya) 497

Poniendo un hilo a dormir 501

Hacer e iniciar dos hilos. 503

Problemas de concurrencia: ¿se podrá salvar esta pareja? 505

El problema de concurrencia de Ryan y Monica, en el código Bloqueo 506

para hacer las cosas atómicas 510

Cada objeto tiene un candado. 511

El temido problema de la “Actualización perdida” 512

Métodos sincronizados (usando un candado) 514

¡Punto muerto! 516

Código ChatClient multiproceso 518

SimpleChatServer listo para hornear 520

Ejercicios y rompecabezas 524

xvii
Machine Translated by Google

Estructuras de datos
dieciséis Ordenar es muy sencillo en Java.

Colecciones 533

Ordenar una ArrayList con [Link]() 534

Lista 0 1 2 3 Genéricos y seguridad de 540

tipos Clasificación de elementos que implementan la interfaz Comparable 547

Ordenar cosas con un comparador personalizado 552

La API de colección: listas, conjuntos y mapas 557


Colocar
Evitar duplicados con HashSet 559

Anulando hashCode() y es igual a() 560

HashMap 567

Usar comodines para polimorfismo 574


Mapa “Bola”
“Bola1”“Pez”
“Bola2”“Coche”
“Pez” “Coche”
Ejercicios y rompecabezas 576

Es hora de dejarlo ir.


17 Libera tu código

clases

Opciones de implementación 582


com
Mantenga el código fuente y los archivos de clase separados 584
101101
10 110 1 0
Hacer un JAR ejecutable (Java ARchives) 585
MiAplicació[Link]
foo 11 0
001 10
001 01

Ejecutando un JAR ejecutable 586


MiAplicació[Link]

¡Pon tus clases en un paquete! 587

Los paquetes deben tener una estructura de directorio coincidente. 589

Servidor web Compilando y ejecutando paquetes 590


JWS
loper iure
Compilando con ­d 591
eugue tat
vero
consenso

euguero­ Hacer un JAR ejecutable (con paquetes) 592


MiAplicació[Link]
MiAplicació[Link] MiAplicació[Link]
Java Web Start (JWS) para implementación desde la web 597

Cómo crear e implementar una aplicación JWS 600

Ejercicios y rompecabezas 601

xviii
Machine Translated by Google

18 Computación distribuida
Ser remoto no tiene por qué ser algo malo.

Cliente Servidor Invocación de método remoto de Java (RMI), práctica, muy detallada 614

Servlets (un vistazo rápido) 625

Talón RMI ESQUELETO RMI 631


Enterprise JavaBeans (EJB), un vistazo muy rápido

r Jini, el mejor truco de todos. 632


Cimi
yo r
mi Smirv iCmih
mi
mi
yopag
Smirv miC
t
t iCmi ohbj 636
yo
norte
h
mipag
Construyendo el navegador de servicio universal realmente genial
Cimi
yo
Ct
t bj mi
norte
oh

El fin 648

Un Apéndice A
El proyecto final de Code Kitchen.

BeatBoxFinal (código de cliente) 650

MusicServer (código de servidor) 657

B apéndice B
Las diez cosas principales que no aparecieron en el libro.

Lista de los diez mejores 660

i índice 677

xix
Machine Translated by Google
Machine Translated by Google

como usar este libro


Introducción

¡No puedo creer que


hayaneso
puesto un libro
de programación Java!

En esta sección, respondemos a la pregunta candente:


"Entonces, ¿por qué pusieron eso en un libro de programación Java?"

xxi
Machine Translated by Google

como usar este libro

¿Para quién es este libro?

Este NO es un libro de referencia.


1 ¿Has hecho algo de programación? Head First Java es un libro diseñado no
para ser una enciclopedia aprendiendo,
2 ¿Quieres aprender Java? de datos sobre Java.

3 ¿Prefieres una conversación estimulante en una cena a


conferencias técnicas, aburridas y aburridas?

¿Quién debería probablemente alejarse de este libro?

1 ¿Su experiencia en programación se limita


únicamente a HTML y no tiene experiencia en
lenguajes de programación?

2 ¿ Es usted un programador experto en C++ y busca un


libro? referencia

3 ¿Tienes miedo de probar algo diferente?


¿Preferirías hacerte una endodoncia que mezclar rayas con
cuadros? ¿Crees que un libro técnico no puede ser serio
si hay una imagen de un pato en la sección de gestión de
memoria?

[nota de marketing: ¿quién se hizo cargo de cómo es este libro


para cualquier persona con una tarjeta de crédito válida? ¿Y qué
pasa con la promoción
discutido... ­Fred] navideña “Regala Java” que te ofrecemos?

XXII introducción
Machine Translated by Google

la introducción

Sabemos lo que estás pensando.

su
El cerebro piensa

que ESTO es importante.


Y sabemos cuál es tu cerebro Esta pensando.

Excelente. Sólo
637 páginas más, aburridas,
secas y aburridas.

¡Esto debe ser importante! ¡No lo olvides! tu cerebro piensa


ESTO no vale la pena
ahorro.

estas aqui xiii


Machine Translated by Google

como usar este libro

Pensamos en un lector "Head First Java" como un aprendiz.


entonces asegúrese de
¿algo? Primero, tienes que conseguir

Entonces, ¿qué se necesita para aprender


él. No se trata de meter hechos en tu cabeza. Basado en el
tu no olvidar
últimas investigaciones en ciencia cognitiva, neurobiología y psicología educativa,
requiere mucho más que texto en una página. Sabemos qué enciende tu cerebro.
aprendiendo

Algunos de los principios de aprendizaje de Head First: necesita llamar a


un método en el servicio
servidor remoto RMI
Hazlo visual.
hacerCalc()

Pon las palabras dentro


valor de retorno
o cerca de los gráficos

Utilice un estilo conversacional y personalizado.

Realmente apesta ser


un método abstracto.
No tienes cuerpo.

¿Tiene sentido decir


Haga que el alumno piense más profundamente. Tub IS­A Bathroom?
¿El baño es una bañera? ¿O
es una relación TIENE­A?

vagar por el vacío abstracto();

¡Sin cuerpo de método!


Termine con un punto y coma. Capte y mantenga la atención del lector.

Toca sus emociones.

introducción xxiv
Machine Translated by Google

la introducción

Metacognición: pensar sobre pensar.


Me pregunto cómo
puedo engañar a mi
cerebro para que
recuerde estas cosas...

HACER
Entonces, ¿cómo consigues que tu cerebro trate a Java como si fuera un tigre hambriento?

usted está aquí xxvi


Machine Translated by Google

como usar este libro

Esto es lo que hicimos NOSOTROS:


24

tamaño

En t
fido Ct
D
oh gramo bj mi
oh

Perro
Perro

PuzzleVille Esto es

PUNTOS DE VIÑETA

Barra cerebral
cerebro
con barra

xxvi introducción
Machine Translated by Google

la introducción

Esto es lo que TÚ puedes hacer para


someter tu cerebro.

corta esto y pégalo


en tu refrigerador.

1 Reduzca la velocidad. Cuanto más entiendas, 6 Bebe agua. Montones.


menos tendrás que memorizar.

7 Habla de ello. En voz alta.

2 Haz los ejercicios. Escribe tus propias notas.

8 Escuche a su cerebro.
3 Lea “No hay preguntas tontas”

4 No hagas toda tu lectura en un solo lugar. 9 ¡ Siente algo!

5 Haz que esto sea lo último que leas antes de acostarte. O al


10 Escriba y ejecute el código.
menos lo último. desafiante

usted está aquí xxvii


Machine Translated by Google

como usar este libro

Lo que necesitas para este libro:

CONFIGURAR JAVA

Si aún no tiene un SDK (kit de desarrollo de software) de Java 2 Standard Edition 1.5 o superior , lo
necesita. Si utiliza Linux, Windows o Solaris, puede obtenerlo de forma gratuita en [Link] (el sitio web de
Sun para desarrolladores de Java). Por lo general, no se necesitan más de dos clics desde la página principal para
llegar a la página de descargas de J2SE. Obtenga la última versión no beta publicada.
El SDK incluye todo lo necesario para compilar y ejecutar Java.
Si está ejecutando Mac OS X 10.4, el SDK de Java ya está instalado. Es parte de OS X y no tienes que hacer nada
más. Si tiene una versión anterior de OS X, tiene una versión anterior de Java que funcionará para el 95% del
código de este libro.

Nota: Este libro está basado en Java 1.5, pero por razones de marketing sorprendentemente poco claras, poco
antes de su lanzamiento, Sun le cambió el nombre a Java 5, manteniendo “1.5” como número de versión del kit del
desarrollador. Entonces, si ve Java 1.5 o Java 5 o Java 5.0, o "Tiger" (el nombre en clave original de la versión
5), todos significan lo mismo. Nunca hubo un Java 3.0 o 4.0; saltó de la versión 1.4 a la 5.0, pero aún encontrarás
lugares donde se llama 1.5 en lugar de 5. No preguntes.
(Ah, y solo para hacerlo más entretenido, Java 5 y Mac OS X 10.4 recibieron el mismo nombre en clave de "Tiger", y
dado que OS X 10.4 es la versión de Mac OS que necesitas para ejecutar Java 5 , oirás a la gente hablar de "Tiger
on Tiger". Simplemente significa Java 5 en OS X 10.4).

El SDK no incluye la documentación de la API, ¡y usted la necesita! Vuelva a [Link].


com y obtenga la documentación de la API J2SE. También puede acceder a los documentos de la API en línea,
sin descargarlos, pero eso es una molestia. Confía en nosotros, vale la pena descargarlo.

Necesitas un editor de texto. Prácticamente cualquier editor de texto servirá (vi, emacs, pico), incluidos los GUI que
vienen con la mayoría de los sistemas operativos. El Bloc de notas, Wordpad, TextEdit, etc. funcionan, siempre y
cuando se asegure de que no agreguen un ".txt" al final de su código fuente.

Una vez que haya descargado y descomprimido/comprimido/lo que sea (depende de qué versión y para qué
sistema operativo), debe agregar una entrada a su variable de entorno PATH que apunte al directorio /bin dentro del
directorio principal de Java. Por ejemplo, si J2SDK coloca un directorio en su disco llamado “j2sdk1.5.0”, busque
dentro de ese directorio y encontrará el directorio “bin” donde se encuentran los binarios de Java (las herramientas).
El directorio bin es al que necesita una RUTA, de modo que cuando escriba: % javac

en la línea de comandos, su terminal sabrá cómo encontrar el compilador javac .


Nota: si tiene problemas con la instalación, le recomendamos que vaya a [Link] y se una al foro Java­Beginning.
En realidad, deberías hacerlo tengas problemas o no.

Nota: gran parte del código de este libro está disponible en [Link]

introducción xxviii
Machine Translated by Google

la introducción

Cosas de última hora que necesitas saber:

Usamos un falso UML modificado más simple.

Usamos UML simple como diagramas. Perro

tamaño

ladrar()

comer()

perseguirgato()

No nos preocupamos por organizar y empaquetar su propio código hasta el final del libro.

Debes realizar
TODAS las
actividades de “Afila tu lápiz”

Afila tu lápiz
Los ejercicios de final de capítulo son obligatorios; Los rompecabezas son
opcionales. Las respuestas para ambos se encuentran al final de cada capítulo.

¡Las actividades marcadas con el logo de

Ejercicio (zapatillas para correr) son


obligatorias!
No te los saltes
si realmente estás aprendiendo
acerca de
Java.

Los ejercicios 'Afila tu lápiz' no tienen respuestas.

Si ves el logo de Puzzle, la actividad


Los ejemplos de código son lo más sencillos posible. es opcional, y si no te gusta la lógica
retorcida o los crucigramas, estos no
te gustarán
cualquiera.

estas aqui xix


Machine Translated by Google

edición técnica: Jessica y Valentin

Editores técnicos

Valentin Crettaz

El MINI de Jessica
Jessica Sant

corbata de valentin

introducción xxx
Machine Translated by Google

la introducción

crédito
Otras personas a las que culpar: Algunos de nuestros
revisores expertos en Java...
Jef Cumps

Corey McGlone

Juan de Jong

Jason Ménard

Tomás Pablo

Marilym de
Queiroz

Terri Cubeta Chris Jones


James Cubeta John Nyquist
Ira Becker

Rodney J.
aspa

usted está aquí xxxi


Machine Translated by Google

aun mas reconocimientos

Justo cuando pensabas que no habría


más agradecimientos*.

*La gran cantidad de reconocimientos se debe a que estamos probando la teoría de que todos los mencionados
en el reconocimiento de un libro comprarán al menos una copia, probablemente más, con familiares y todo. Si
te gustaría estar en el reconocimiento de nuestro próximo libro y tienes una familia numerosa, escríbenos.

introducción xxxii
Machine Translated by Google

1 inmersión en A Quick Dip

B r eak i ng t h mi S turFa C mi
¡Vamos, el agua está genial!
Nos sumergiremos y escribiremos algo
de código, luego lo compilaremos y lo
ejecutaremos. Estamos hablando de sintaxis,
bucles y ramificaciones, y de un vistazo a lo
que hace que Java sea tan genial.
Estarás codificando en poco tiempo.

Java te lleva a nuevos lugares.

escribir una vez/ejecutar

en cualquier lugar

tienes suerte

más elegante, más rápido, mucho

mas poderoso

este es un nuevo capitulo 1


Machine Translated by Google

la forma en que funciona Java

La forma en que funciona Java

El objetivo es escribir una aplicación (en este ejemplo,


una invitación a una fiesta interactiva) y hacer que funcione en
cualquier dispositivo que tengan tus amigos.

Método Partido()
código fuente para
0 carga_0
el interactivo
1 invokespe­
invitación de fiesta. cial #1 <Método

[Link]()>

4 regreso

Fuente Producción
usted apuesta

(código) Dispararme

1 Compilador Virtual

Máquinas
3
2
4

2 Capítulo 1
Machine Translated by Google

bucear en un baño rápido

Qué harás en Java


Escribirá un archivo de código fuente, lo compilará usando el compilador javac
y luego ejecutará el código de bytes compilado en una máquina virtual Java.

Solicitud de ayuda de la ventana de edición de archivos Ventana de edición de archivos Ayuda Jurar

importar [Link].*; Método Partido()


%javac [Link] % fiesta java
importar [Link].*;
0 carga_0
clase Fiesta
1 invokespecial #1 <Método
{ public void buildInvite()
[Link]()>
{ Marco f = nuevo Marco();
4 regreso
Etiqueta l = nueva etiqueta ("Fiesta en
casa de Tim"); Botón b = nuevo Método nulo buildInvite()
Botón(“Apuestas”); Botón c = nuevo
Compilador 0 nuevo #2 <Clase [Link]>
Botón ("Dispárame"); Virtual
Panel p 3 dobles
= nuevo Panel(); [Link](l); } // más código aquí... 2 4 invokespecial #3 <Método
Máquinas
}
[Link]()>
4
Fuente javac

1 Salida
(código)

(Nota: esto no pretende ser un tutorial... escribirás


código real en un momento, pero por ahora, solo
queremos que tengas una idea de cómo encaja todo).

usted está aquí 3


Una muy breve historia de Java.
3500
Clases en la biblioteca estándar de Java.

3000
2500
2000
1500
1000
500
0
Java 1.02 Java 1.1 Java 2 Java 5.0
(versiones 1.2 – 1.4) (versiones 1.5 y superiores)
Machine Translated by Google

historia de java

4 capitulo 1
Machine Translated by Google

bucear en un baño rápido

Afila tu lápiz
Mira lo fácil que
es escribir Java.

tamaño entero = 27; declara una variable entera llamada 'tamaño' y dale el valor 27

Nombre de cadena = "Fido";

Perro miPerro = nuevo Perro(nombre, tamaño);

x = tamaño ­ 5;

if (x < 15) [Link](8);

mientras (x > 3) {

[Link]();

int[] listaNúm = {2,4,6,8};

[Link](“Hola”);

[Link](“Perro: “ + nombre);

Número de cadena = “8”;

int z = [Link](núm);

intentar {

leerElArchivo(“[Link]”);

atrapar(FileNotFoundException ex) {

[Link](“Archivo no encontrado.”);

usted está aquí 5


Machine Translated by Google

por qué Java es genial

Afila tu lápiz

Mira lo fácil que


es escribir Java.

tamaño entero = 27; declarar una variable entera llamada 'tamaño' y darle el valor 27

declarar una variable de cadena de caracteres llamada 'nombre' y darle el valor "Fido"
Nombre de cadena = "Fido";

Perro miPerro = nuevo Perro(nombre, tamaño); declarar una nueva variable Perro 'miPerro' y crear el nuevo Perro usando 'nombre' y

x = tamaño ­ 5; 'tamaño' resta 5 a 27 (valor de 'tamaño') y asígnalo a una variable llamada 'x' si

if (x < 15) [Link](8); x (valor de 22) es menor que 15, dile al perro que ladre 8 veces

mientras (x > 3) { siga haciendo el bucle mientras x sea mayor

[Link](); que 3... dígale al perro que juegue (lo que sea que ESO

} signifique para un perro...) esto parece el final del bucle: todo en { } se hace en el bucle

int[] listaNúm = {2,4,6,8}; declare una lista de variables enteras 'numList' y coloque 2,4,6,8 en la lista.

[Link](“Hola”); imprima "Hola"... probablemente en la línea de

[Link](“Perro: “ + nombre); comando imprima "Hola Fido" (el valor de 'nombre' es "Fido") en la línea de

Número de cadena = “8”; comando declare una variable de cadena de caracteres 'num' y asígnele

int z = [Link](núm); el valor de “8” convierte la cadena de caracteres “8” en un valor numérico real 8

intentar { intentar hacer algo... tal vez no se garantiza que lo que estamos intentando

leerElArchivo(“[Link]”); funcione... leer un archivo de texto llamado “[Link]” (o al menos INTENTAR

} leer el archivo...) debe ser el final de las “cosas para probar”, así que supongo que

atrapar(FileNotFoundException ex) { puedes probar muchas cosas... aquí debe ser donde descubrirás si lo que

[Link](“Archivo no encontrado.”); intentaste no funcionó... si lo que intentamos falló, imprime “Archivo no encontrado

} "En la línea de comando parece que todo en {} es qué hacer si el 'intento' no funcionó...

6 Capítulo 1
Machine Translated by Google

bucear en un baño rápido

Estructura del código en Java

perro de clase pública {


¿Qué va en un archivo
fuente ?

} clase

Coloque una clase en un archivo fuente. ¿Qué pasa en una perro de clase pública {
clase?
corteza vacía() {
Poner métodos en una clase.

Poner declaraciones en un método.

método

perro de clase pública {


¿Qué va en un método?
corteza vacía() {

declaración1;

declaración2;

declaraciones

usted está aquí 7


Machine Translated by Google

una clase java

anatomía de una clase

público estático vacío principal (String[] args) {

// tu código va aquí
}

esto es un el nombre de
llave de apertura de
público para que todos clase (duh) esta clase la clase
puedan acceder a él

clase pública MiPrimeraAplicación { argumentos del método.


A este método se le debe
el tipo de devolución. proporcionar una matriz de
(cubriremos esto void significa que no el nombre de
cadenas, y la matriz se llamará 'args'
uno más tarde.) hay valor de retorno. este método llave de apertura

del método

público estático vacío principal (String[] args) {

[Link](“¡Yo mando!”); ¡Cada declaración DEBE


terminar en punto y coma!

esto dice imprimir en salida estándar (por


defecto en la línea de comandos) la cadena que
deseas imprimir
} llave de cierre del método principal

}
llave de cierre de la clase MyFirstApp

No te preocupes por memorizar nada ahora...


este capítulo es sólo para que comiences.

8 Capítulo 1
Machine Translated by Google

bucear en un baño rápido

Escribir una clase con un principal

Hola principal()

clase pública MiPrimeraAplicación { 1 Ahorrar


público estático vacío principal (String[] args) { MiPrimeraAplicació[Link]
[Link](“¡Yo mando!”);
clase pública MiPrimeraAplicación {

principal pública estática vacía

(Argumentos de cadena []) { [Link](“El Mundo”);


}
2 Compilar
[Link](“¡Yo mando!”);

}
}
javac MiPrimeraAplicació[Link]
MiPrimeraAplicació[Link]

compilador
3 Correr
Grito de ayuda de la ventana de edición de archivos

Método Party() 0 aload_0 1 invokespecial


%java Mi primera aplicación
#1 <Método [Link]()>

¡Yo mando!
4 regreso

Método void

main([Link][]) El mundo
0 getstatic #2 <Campo

MiPrimeraAplicació[Link]

usted está aquí 9


Machine Translated by Google

declaraciones, bucles, ramificaciones

bucles
¿Qué puedes decir en el método principal?
declaraciones
derivación

1 hacer algo

entero x = 3;
Nombre de cadena = "Dirk"; * 17;
x=x
[Link](“x es” double d = +x);
[Link](); // esto es un comentario Sintaxis
Divertido

2 hacer algo una y otra vez

mientras (x > 12) { x = x ­1;

x = x + 1;
for (int x = 0; x < 10; x = x + 1) { [Link](“x ahora es +
"
x);
}

x = 22;
3 hacer algo bajo esta condición
// esta línea me molesta

si (x == 10) {
[Link](“x debe ser 10”); X = 3;
} demás {
[Link](“x no es 10”);
}

if ((x < 3) & ([Link](“Dirk”))) {


[Link](“Suavemente”); peso interno;
} //tipo: int, nombre: peso
[Link](“esta línea se ejecuta pase lo que pase”);

public void go() { // código


increíble aquí
}

10 capitulo 1
Machine Translated by Google

bucear en un baño rápido

while (másBalls == verdadero)


{ keepJuggling(); }

Pruebas booleanas simples

Bucles y bucles y...

entero x = 4; // asigna 4 a x

mientras (x > 3) {
// el código del bucle se ejecutará porque // x es
mayor que 3 x = x ­ 1; // o haríamos
un bucle para siempre
}
int z = 27; //
mientras (z == 17) {
// el código del bucle no se ejecutará porque // z no es
igual a 17
}

usted está aquí 11


Machine Translated by Google

Conceptos básicos de Java

no existen
Preguntas tontas Ejemplo de un bucle while
clase pública Loopy {
público estático vacío principal (String[] args) {
entero x = 1;
[Link](“Antes del bucle”);
mientras (x < 4) {
[Link](“En el bucle”);
[Link](“El valor de x es” +x);
x = x + 1;
}

[Link](“Esto es después del ciclo”);


}

% java en bucle esta es la salida


Antes del bucle
En el lazo
El valor de x es 1.

En el lazo
El valor de x es 2.

En el lazo
El valor de x es 3.

Esto es después del bucle.

PUNTOS DE VIÑETA

Las declaraciones terminan en punto y coma ;

Los bloques de código están definidos por un par de llaves { }


entero x = 1;
Declare una variable int con un nombre y un tipo: int x;
mientras (x){ }
El operador de asignación es un signo igual =

El operador igual usa dos signos igual ==

Un bucle while ejecuta todo lo que está dentro de su bloque (definido por
llaves) siempre que la prueba condicional sea verdadera.

Si la prueba condicional es falsa, el bloque de código del bucle while no se


ejecutará y la ejecución descenderá al código inmediatamente después
del bloque del bucle.

booleano isHot = verdadero; Coloque una prueba booleana entre paréntesis:


while (x == 4) { }
mientras (está caliente) { }

12 capitulo 1
Machine Translated by Google

bucear en un baño rápido

ramificación condicional Impresió[Link] vs.

[Link]

clase IfTest {

público estático vacío principal (String[] args) {


entero x = 3;

si (x == 3) {

[Link](“x debe ser 3”);

[Link](“Esto se ejecuta pase lo que pase”);

% java prueba If salida de código


x debe ser 3 Afila tu lápiz
Esto funciona pase lo que pase

% javaDooBee
DooBeeDooBeeDo

clase IfTest2 {

público estático vacío principal (String[] args) {


entero x = 2;

si (x == 3) {

[Link](“x debe ser 3”);

} demás {

[Link](“x NO es 3”);

[Link](“Esto se ejecuta pase lo que pase”);

nueva salida
% java IfTest2 x NO
es 3
Esto funciona pase lo que pase

usted está aquí 13


Machine Translated by Google

aplicación Java seria

Codificar un negocio serio


Solicitud

clase pública BeerSong {

público estático vacío principal (String[] args) {

int númerocerveza = 99;


Palabra de cadena = “botellas”;

mientras (númcerveza > 0) {

if (númcerveza == 1) {

palabra = “botella”; // singular, como en UNA botella.

""
[Link](cervezaNum + + palabra + “de cerveza en la pared”);
""
[Link](cervezaNum + + palabra + “de cerveza.”);

[Link](“Derriba uno.”);

[Link](“Pasarlo.”);

númerocerveza = númerocerveza ­ 1;

si (númcerveza > 0) {
""
[Link](cervezaNum + + palabra + “de cerveza en la pared”);

} demás {

[Link](“No más botellas de cerveza en la pared”);

} // fin de lo contrario
} // finaliza el ciclo while

} // finaliza el método principal


} // finalizar clase

14 capitulo 1
Machine Translated by Google

bucear en un baño rápido

Lunes por la mañana en casa de Bob

El despertador de Bob suena a las 8:30 de la mañana del lunes, como cualquier otro día de la semana. Java dentro
Pero Bob tuvo un fin de semana loco y presiona el botón DORMIR.
Y ahí es cuando comienza la acción y los dispositivos habilitados para Java
cobran vida.

Primero, el despertador envía un mensaje a la cafetera* "Oye, el geek se está durmiendo hasta
tarde otra vez, retrasa el café 12 minutos".

La cafetera envía un mensaje al Motorola™ Java aquí también

tostadora, "Espera la tostada, Bob está durmiendo".

Luego, el despertador envía un mensaje al teléfono celular


Nokia Navigator™ de Bob: "Llama a Bob a las 9 en punto
y dile que llegamos un poco tarde".

Finalmente, el despertador envía un mensaje a


El collar de Sam
El collar inalámbrico de Sam (Sam es el perro), con la señal demasiado familiar de que
tiene Java.
tostadora java
significa: "Consigue el periódico, pero no esperes una caminata".

Unos minutos más tarde, la alarma vuelve a sonar. Y nuevamente Bob


presiona DORMIR y los electrodomésticos comienzan a traquetear.
Finalmente, la alarma suena por tercera vez. Pero justo cuando Bob
busca el botón de repetición, el reloj envía la señal de "salta y ladra" al collar de
Sam. Conmocionado hasta recuperar la conciencia, Bob se levanta, agradecido de
que sus habilidades en Java y un pequeño viaje a Radio Shack™ hayan
mejorado las rutinas diarias de su vida.
mantequilla aquí
Su tostada está tostada.

Su café humea.

Su artículo espera.

Otra mañana maravillosa en The Java­Enabled House.

Puede tener una casa habilitada para Java. Quédese con una solución sensata que utilice tecnología
Java, Ethernet y Jini. Tenga cuidado con las imitaciones que utilizan otras plataformas denominadas
“plug and play” (que en realidad significa “conéctelo y juegue durante los próximos tres días tratando
de que funcione”) o plataformas “portátiles”. Betty, la hermana de Bob, probó uno de esos otros y los
COMO SI ENCENDIDO
resultados, bueno, no fueron muy atractivos ni seguros.
También es una pena lo de su perro...
TELEVISOR

usted está aquí 15


Machine Translated by Google

escribamos un programa

Pruebe mi
nueva frase­o­matic
y será un conversador
hábil como el jefe o
esos tipos de marketing.

clase pública PhraseOMatic {


público estático vacío principal (String[] args) {

1 // crea tres conjuntos de palabras para elegir. ¡Agrega el tuyo propio!


String[] wordListOne = {“24/7”,”varios
niveles”,”30,000 pies”,”B­to­B”,”win­win”,”front­end”, “basado
en web”,” omnipresente”, “inteligente”, “seis sigma”, “camino
crítico”, “dinámico”};

String[] wordListTwo = {“empoderado”, “pegajoso”, “valor


agregado”, “orientado”, “céntrico”, “distribuido”, “agrupado”, “de marca”,
“fuera de lo común”, “posicionado ”, “en red”, “centrados”, “apalancados”,
“alineados”, “dirigidos”, “compartidos”, “cooperativos”,
“acelerados”};

String[] wordListThree = {“proceso”, “inclinación­


punto”, “solución”, “arquitectura”, “competencia central”, “estrategia”,
“mente compartida”, “portal”, “espacio”, “visión”, “paradigma”, “misión”};

// descubre cuántas palabras hay en cada lista


2
int oneLength = [Link];
int twoLength = [Link];
int tresLongitud = lista de [Link];
nota: cuando escriba esto en un editor, ¡deje que el
// genera tres números aleatorios
código haga su propio ajuste de palabras/líneas!
3 int rand1 = (int) ([Link]() * oneLength);
Nunca presiones la tecla de retorno cuando estés
escribiendo una cadena (algo entre "comillas") int rand2 = (int) ([Link]() * twoLength);
o no se compilará. Entonces, los guiones que int rand3 = (int) ([Link]() * tresLongitud);
ve en esta página son reales y puede escribirlos,
pero
de no presione
haber la tecla
cerrado una Intro hasta DESPUÉS
Cadena. 4 // ahora construye una frase
Frase de cadena = ListaPalabraUno[rand1] +
““
+
““
ListaPalabraDos[rand2] + + ListaPalabraTres[rand3];

5 //imprime la frase

[Link](“Lo que necesitamos es un } + frase);

16 capítulo 1
Machine Translated by Google

bucear en un baño rápido

Frase­O­Matic
Cómo funciona.

Cadena[] mascotas = {“Fido”, “Zeus”, “Bin”};

Lo que necesitamos
aquí es un...

int x = [Link]; proceso dirigido


X generalizado

punto de inflexión
dinámico e innovador

aleatorio()

competencia central
distribuida inteligente

enterox = (int) 24,6;


Mindshare empoderado 24 horas al

día, 7 días a la semana

+
Visión beneficiosa para todos de
30.000 pies

Cadena s = mascotas[0]; // s ahora es la cadena “Fido” portal en red seis


s=s+ ““
+ “es un perro”; // s ahora es “Fido es un perro” sigma

usted está aquí 17


Machine Translated by Google

el compilador y la JVM

Charla de esta noche: El compilador


y la JVM luchan por la pregunta:
"¿Quién es más importante?"

La máquina virtual Java El compilador

18 capítulo 1
Machine Translated by Google

bucear en un baño rápido

La máquina virtual Java El compilador

usted está aquí 19


Machine Translated by Google

Ejercicio: Código Imanes

if (x == 1)
X
{ [Link](“d”);
=x­1;
}

si (x == 2) {

[Link](“bc”);

clase aleatoria1 {

público estático vacío principal (String [] argumentos) {

si (x > 2) {
[Link](“a”);
}

entero x = 3;

X
=x­1;

[Link](“­”);

mientras (x > 0) {

Ventana de edición de archivos Ayuda Suspender


Producción:
% java aleatorio1
aBCD

20 capitulo 1
Machine Translated by Google

bucear en un baño rápido

B
público estático vacío principal (String [] argumentos) {

entero x = 5;

mientras ( x > 1 ) {

x = x ­ 1;

si (x < 3) {

[Link](“x pequeña”);
Cada uno de los archivos Java en esta
}
página representa un archivo fuente completo.
}
Su trabajo es jugar al compilador y
determinar si cada uno de estos archivos }

se compilará. Si no se compilan,
¿cómo los solucionarías?

C
A
clase Ejercicio1b {
clase Ejercicio1b {
entero x = 5;
público estático vacío principal (String [] argumentos) {
mientras ( x > 1 ) {
entero x = 1;
x = x ­ 1;
mientras (x < 10) {
si (x < 3) {
si (x > 3) {
[Link](“x pequeña”);
[Link](“x grande”);
}
}
}
}
}
}

usted está aquí 21


Machine Translated by Google

rompecabezas: crucigrama

JavaCross 7.0

22 capitulo 1
Machine Translated by Google

bucear en un baño rápido

prueba de clase {
público estático vacío principal (String [] argumentos) {
int x = 0;
int y = 0; mientras
(x<5) {
el candidato
código
va aquí

““
[Link](x + x = x + 1; + y +“ “);

}
}
}

y = x ­ y; 22 46
Relacionar
cada candidato
y = y + x;
con uno de 11 34 59
los posibles resultados.
y = y + 2;
si( y > 4 ) { 02 14 26 38

y = y ­ 1;
} 02 14 36 48

x = x + 1;
00 11 21 32 42
y = y + x;

11 21 32 42 53
si ( y < 5 ) {
x = x + 1;
si ( y < 3 ) { 00 11 23 36 410
x = x ­ 1;
} 02 14 25 36 47
}
y = y + 2;

usted está aquí 23


Machine Translated by Google

rompecabezas: rompecabezas de piscina

clase PoolPuzzleOne {
público estático vacío principal (String [] argumentos) {
int x = 0;
Rompecabezas de piscina
mientras ( __________ ){

_____________________________
si ( x < 1 ) {
___________________________
}
_____________________________

si ( __________ ){

____________________________

___________

} si (x == 1) {
Truco de ayuda de la ventana de edición de archivos

%java PoolPuzzleOne ____________________________


un ruido
} si ( ___________ ){
molesta
una ostra ____________________________
}
[Link](““);

____________
}
}
}

24 capitulo 1
Machine Translated by Google

bucear en un baño rápido


clase Ejercicio1b {
público estático vacío principal (String [] argumentos) {
entero x = 1;
mientras ( x < 10 ) { x =
x + 1;

si (x > 3) {
A
[Link](“x grande”);
}
Imanes de código:
}
clase aleatoria1 {
} Esto se compilará y ejecutará (sin salida),
público estático vacío principal (String [] argumentos) {
} pero sin agregar una línea al programa, ¡se
entero x = 3; ejecutará para siempre en un bucle infinito ' while'!
mientras (x > 0) {

si (x > 2) {
[Link](“a”);
clase Foo
}
{ public static void main(String [] args) {

x = x ­ 1; entero x = 5;

[Link](“­”); mientras ( x > 1 ) {


x = x ­ 1;
si (x == 2) { si (x < 3) {
B
[Link](“bc”);
[Link](“x pequeña”);
}
}
} ¡Este archivo no se compilará sin
if (x == 1)
{ [Link](“d”); x = x ­ 1; } una declaración de clase y no olvide la
} llave correspondiente!
}
}
}
}
clase Ejercicio1b {

public static void main(String [] args) { int x = 5;


Ventana de edición de archivos Ayuda Poeta
mientras ( x
% java aleatorio1
>1){
aBCD
x = x ­ 1;
C if ( x < 3)
{ [Link](“x pequeña”);
}
}
El código del bucle ' while' debe estar
} dentro de un método. No puede ser
} simplemente pasar el rato dentro de la clase.

usted está aquí 25


Machine Translated by Google

respuestas del rompecabezas

F V PAG

JAVA l OP oh Ud.

R W. oh I B
B R ANCHO A D C V l
A I Nuevo Testamento oh A I
Y l METRO R CI
S YTEOUTPRINT
S METRO

clase PoolPuzzleOne { t A I A
público estático vacío principal (String [] argumentos) { A I l B METRO

int x = 0;
S t PLATAFORMA norte DECLARAR
mientras ( X < 4 ) { I R mi t

C j h
[Link](“a”); si
(x<1) V oh

{ [Link](“ “); DOMINIO


}
[Link](“n”); prueba de clase
{public static void main(String [] args) {
si ( X > 1 ) { int x = 0; int y = 0;
mientras (x<5)
{
[Link](“ ostra”); x = x +

} si (x == 1) { [Link](x + x = x + 1;
““
+ y +“ “);

}
[Link](“noys”);
}
}
} si ( X < 1 ) {

y = x ­ y; 22 46
[Link](“oise”);
} y = y + x; 11 34 59
[Link](““);
y = y + 2;
02 14 26 38
Truco de ayuda de la ventana de edición de archivos si( y > 4 ) {
X = X + 1; }
%java PoolPuzzleOne y = y ­ 1;
un ruido } 02 14 36 48
}
molesta
} x = x + 1; 00 11 21 32 42
una ostra y = y + x;

11 21 32 42 53
si ( y < 5 ) {
x = x + 1; si ( y
< 3 ) { x = x ­ 1; 00 11 23 36 410

} 02 14 25 36 47
}
y = y + 2;

26 capítulo 1
Machine Translated by Google

2 clases y objetos

Un viaje a Objectville

¡Nos vamos a
Objectville! Dejaremos
esta vieja y polvorienta
ciudad procesal para siempre.
Te enviaré una postal.

Me dijeron que habría objetos.

este es un nuevo capitulo 27


Machine Translated by Google

Érase una vez en Objectville

Guerras de sillas

(o cómo los objetos pueden cambiar tu vida)

la especificación

oh

la silla

En el cubo de Larry En la computadora portátil de Brad en el café.

rotar (número de forma) {


// hacer que la forma gire 360º
}

reproducirSonido(numeroforma) {
// usa ShapeNum para buscar cuál }
// sonido AIF para reproducir y reproducirlo
}
}
}

28 capítulo 2
Machine Translated by Google

clases y objetos

Larry pensó que lo había logrado. Casi podía sentir el acero laminado del Aeron debajo
de él...

¡Pero espera! Ha habido un cambio de especificaciones.

Habrá una forma de ameba en la


pantalla, junto con las demás. lo que se agregó a la especificación

Cuando el usuario hace clic en


la ameba, girará como los demás
y reproducirá un archivo de sonido .hif.

De vuelta en el cubo de Larry En la computadora portátil de Brad en la playa.

reproducirSonido(numeroforma) {
// si la forma no es una ameba,
// usa shapeNum para buscar qué // sonido AIF
Ameba
reproducir y reprodúcelo // de lo contrario // reproduce rotar() { //
el sonido código para rotar una ameba }
ameba .hif
}
playSound() { //
código para reproducir el
nuevo // archivo .hif para una

ameba }

usted está aquí 29


Machine Translated by Google

Érase una vez en Objectville

Larry se coló unos momentos antes que Brad.

1) determine el rectángulo que rodea la forma 2) calcule el centro de ese


rectángulo y gire la forma alrededor de ese punto.

Punto de rotación de Ameoba en la


versión de Larry y Brad:

Lo que la especificación olvidó


convenientemente mencionar

Dónde debería estar el punto de

rotación de la ameba:

De vuelta en el cubo de Larry En la computadora portátil de Brad en


su silla de jardín en el Festival Telluride Bluegrass

rotar(shapeNum, xPt, yPt) { // si la forma Ameba


int xPoint
no es una ameba, // calcula el punto central //
int yPoint
basado en un rectángulo,
rotar() { //
código para rotar una ameba //
// luego rotar usando x e y de la ameba }
// demás
// usa xPt e yPt como // el playSound() { //
código para reproducir el
desplazamiento del punto de rotación
nuevo // archivo .hif para
// y luego rotar
una ameba }
}

30 capitulo 2
Machine Translated by Google

clases y objetos

Entonces, Brad, el chico de OO, consiguió la silla, ¿verdad?

Lo que Larry quería


(pensé que la silla la impresionaría)

1
Cuadrado Círculo Triángulo Ameba
Miré lo que los cuatro
girar() girar() girar() girar() las clases tienen en común.
reproducir sonido() reproducir sonido() reproducir sonido() reproducir sonido()

2
Forma
Son formas y todas giran y
reproducir sonido. Así que abstraje el
características comunes y ponerlas en un
girar()
reproducir sonido()
3
nueva clase llamada Forma. Forma Luego vinculé las otras
cuatro clases de forma
superclase girar()
reproducir sonido() a la nueva clase Forma,
en una relación llamada
herencia.
Puede leer esto como "El cuadrado hereda de la forma",
"El círculo hereda de la forma", etc. Eliminé rotar() y subclases
reproducirSound() de las otras formas, por lo que ahora
solo hay una copia que mantener.
Cuadrado Círculo Triángulo Ameba
La clase Shape se denomina superclase de las otras cuatro
clases. Las otras cuatro son las subclases de Shape. Las
subclases heredan los métodos de la superclase. En otras
palabras, si la clase Shape tiene la funcionalidad, entonces
las subclases obtienen automáticamente esa misma funcionalidad.

usted está aquí 31


Machine Translated by Google

Érase una vez en Objectville

¿Qué pasa con la rotación de ameba ()?

mir r
i d mi
ohv
norte
oh
w
Ask w
METRO
mi h oh

superclase
(más abstracto)
Forma
4
girar() Hicelalaanulación
Hice anulaciónde delalaclase
claseAmoeba
Amoeba
reproducir sonido()
elelmétodo
métodorotar()
rotar()del
y playSound()
métodos
Forma de de la superclase Shape.
superclase.
subclases Anular sólo significa que un
Anular sólo significa que un
(mas especifico) subclase redefine uno de sus
subclase redefine uno de sus
métodos heredados cuando necesita
métodos heredados cuando necesita
Ameba
Cuadrado Círculo Triángulo cambiar o ampliar el comportamiento
cambiar o ampliar el comportamiento
de ese método.
girar() { de ese método.
// específico de ameba {
// rotar código
Métodos primordiales
reproducir sonido() {
{
// específico de ameba
// código de sonido

Puedo
hacerme cargo de mí misma.
Sé cómo una ameba
se supone que gira y reproduce
Sé cómo se supone que debe
un sonido.
comportarse una Forma. Tu trabajo
es decirme que haga, yqué
mi trabajo
es hacer que suceda.
No preocupes a tu pequeña cabeza de
programador porque yocómo
lo hago.

32 capitulo 2
Machine Translated by Google

clases y objetos

El suspenso me está matando.


¿Quién consiguió la silla?

¿Qué te gusta de OO?

“Me ayuda a diseñar de una manera más natural. Las cosas tienen una
forma de evolucionar”.
­Joy, 27 años, arquitecto de software

"No estoy jugando con el código que ya he probado, solo para


agregar una nueva característica".
­Brad, 32 años, programador

"Me gusta que los datos y los métodos que operan con esos datos estén
juntos en una clase".
­Josh, 22 años, bebedor de cerveza.

“Reutilizando código en otras aplicaciones. Cuando escribo una nueva


clase, puedo hacerla lo suficientemente flexible como para usarla en
algo nuevo más adelante”.
­Chris, 39 años, director de proyectos

“No puedo creer que Chris haya dicho eso. No ha escrito una línea de
código en 5 años”.
­Daryl, 44 años, trabaja para Chris. consejo metacognitivo
Si estás estancado en un ejercicio, intenta hablar sobre
“¿Además de la silla?”
en voz alta. Hablar (y oír) activa
­Amy, 34 años, programadora
una parte diferente de tu cerebro. A pesar de esto
funciona mejor si tienes otra persona para
Discútelo, las mascotas también funcionan. Así es como
Nuestro perro aprendió el polimorfismo.

usted está aquí 33


Machine Translated by Google

pensando en objetos

Cuando diseñes una clase, piensa en los objetos que se


crearán a partir de ese tipo de clase. Pensar en:
cosas que el objeto sabe
cosas que hace el objeto
Botón Alarma
Carro de la compra

alarma Hora
sabe
color de
carritoContenido sabe la etiqueta
sabe alarma Modo

setColor() setAlarmTime()
addToCart() hace setLabel()
hace getAlarmTime()
setAlarm() lo
hace
removeFromCart() isAlarmSet()
dePress()
retirar() posponer()
unDepress()

cosas un objeto sabe sobre sí mismo se llaman Canción

variables de instancia métodos de título


sabe
variables de artista

setTitle()
son llamados
Cosas que un objeto puede hacer
instancia (estado)setArtist() hace
(comportamiento) reproducir()
métodos

Afila tu lápiz

Piense en instancia como otra forma de decir objeto.

34 capítulo 2
Machine Translated by Google

clases y objetos

¿Cuál es la diferencia entre una clase y un


objeto?

Una clase no es un objeto. (pero se

usa para construirlos)

JVM

clase

Míralo de esta manera...

usted está aquí 35


Machine Translated by Google

haciendo objetos

Haciendo tu primer objeto


El operador de punto (.)

Prueba de conducción

cuerda elástica BungeeTestDrive


Prueba de conducción

1 Escribe tu clase
clase perro {
PERRO
variables
de instancia
tamaño entero; tamaño

criar
Raza de cuerda;
nombre
Nombre de cadena;
un método ladrar()

corteza vacía() {
[Link](“¡Ruff! ¡Ruff!”);
}
} 2 Escriba una clase de probador (TestDrive)

clase DogTestDrive {
público estático vacío principal (String[] args) {
solo un método principal
// El código de prueba del perro va aquí
(Vamos a ponerle código
en el siguiente paso) }
}

En su probador, cree un objeto y acceda a


3 las variables y métodos del objeto.
clase DogTestDrive {
público estático vacío principal (String[] args) {

Perro d = nuevo Perro(); hacer un objeto perro


[Link]ño = 40; use el operador de punto (.)
punto
[Link]();
operador para establecer el tamaño del perro Si ya tiene algunos conocimientos de
}
y llamar a su método bark() OO, sabrá que no utilizamos encapsulación.
} Llegaremos allí en el capítulo 4.

36 capítulo 2
Machine Translated by Google

clases y objetos

Crear y probar objetos de película


clase Película {
Título de cadena;
Género de cuerda;
calificación interna;

void playIt()
{ [Link](“Reproduciendo la película”);
}
}

clase pública MovieTestDrive { public static void


main(String[] args) { Película uno = nueva Película(); [Link] = “Se
fue con las acciones”; [Link] =
“Trágico”; [Link]ón = ­2; Película dos = nueva
película(); [Link] = “Perdido en el
espacio del cubículo”;
dos.género = “Comedia”; [Link]ón
= 5; [Link](); Película tres = nueva película(); tres.título =
“Club de bytes”; [Link] =
“Trágico pero, en última
instancia, edificante”;
[Link]ón = 127;

}
}

Afila tu lápiz

título
PELÍCULA

objeto 1 género
título

clasificación

clasificación de género playIt()


título

objeto 2 género

clasificación

título

objeto 3 género

clasificación

usted está aquí 37


Machine Translated by Google

sal de la principal

¡Rápido! ¡Sal de la principal!

Los dos usos de main:

para probar tu clase real


para iniciar/iniciar su aplicación Java

Lanzador de juegos

hace un

Objeto
principal (cadena [] argumentos)
GuessGame
y le dice
que inicieGame

El juego de adivinanzas Juego de adivinanzas

variables
p1 de instancia
p2

p3
para los tres
jugadores

empezar juego()

[Link] [Link].
el número de
Jugador
este jugador
adivinado
número

adivinar() método
para
hacer a
conjeturas

38 capítulo 2
Machine Translated by Google

clases y objetos

clase pública GuessGame {


GuessGame tiene tres variables
Jugador p1;
Jugador p2; de instancia para los tres objetos
Player
Jugador p3;

inicio del juego vacío público() {


p1 = nuevo jugador(); cree tres objetos Player y
p2 = nuevo jugador(); asígnelos a las
de instancia tres variables
Player
p3 = nuevo jugador();

int conjeturap1 = 0;
declarar tres variables para mantener las
int conjeturap2 = 0;
tres conjeturas que hacen los jugadores
int conjeturap3 = 0;

booleano p1isRight = falso;


declarar tres variables para mantener un verdadero o falso
booleano p2isRight = falso;
booleano p3isRight = falso; basado en la respuesta del jugador

int númerodestino = (int) ([Link]() * 10); Crea un número 'objetivo' que los jugadores
[Link](“Estoy pensando en un número entre 0 y 9...”); tienen que adivinar.

mientras (verdadero) {
[Link](“El número a adivinar es” + número de destino);

[Link]();
llamar al método adivinar() de cada jugador
[Link]();
[Link]();

adivinap1 = p1.número;
[Link](“El jugador uno adivinó” + adivinap1);

adivinap2 = p2.número; obtenga la conjetura de cada jugador (el resultado de la


[Link](“El jugador dos adivinó” + adivinap2);
ejecución de su método de conjetura()) accediendo a la
adivinap3 = p3.número; variable numérica de cada jugador
[Link](“El jugador tres adivinó” + adivinap3);

if (guessp1 == númerodestino) {
p1isRight = verdadero;
} verifique la suposición de cada jugador para ver si coincide con
if (guessp2 == númerodestino) { el número objetivo. Si un jugador tiene razón, entonces
p2isRight = verdadero; configure la variable de ese jugador como verdadera
}
(recuerde, la configuramos como falsa de forma predeterminada)
if (guessp3 == númerodestino) {
p3isRight = verdadero;
}

si (p1isDerecha || p2isDerecha || p3isDerecha) { si el jugador uno O el jugador dos O el jugador tres tiene razón... (el operador
|| significa O)

[Link](“¡Tenemos un ganador!”);
[Link](“¿El jugador uno lo hizo bien? “ + p1isRight);
[Link](“¿El jugador dos lo hizo bien? “ + p2isRight);
[Link](“¿El jugador tres lo hizo bien? “ [Link](“El juego + p3isDerecha);
ha terminado.”);
romper; // se acabó el juego, así que sal del circuito

} demás {
// ¡Debemos seguir adelante porque nadie lo hizo bien! de lo contrario, manténgase informado y pida a
los jugadores que adivinen otra vez.
[Link](“Los jugadores tendrán que intentarlo de nuevo.”);
} // terminar si/si no
} // finalizar bucle
} // método final
} // finalizar clase

usted está aquí 39


Machine Translated by Google

Juego de adivinanzas

Ejecutando el juego de adivinanzas


Jugador de clase pública {
número entero = 0; // adónde va la suposición

conjetura pública vacía() { número


= (int) ([Link]() * 10); [Link](“Supongo”
Ayuda de la ventana de edición de archivos

+ número); %java GameLauncher


}
} Estoy pensando en un número entre 0 y 9...
El número a adivinar es 7.

clase pública GameLauncher { principal vacío Supongo que 1


estático público (String [] argumentos) { Supongo que 9
Juego GuessGame = nuevo GuessGame();
[Link]();
Supongo que 9
} El jugador uno adivinó 1
}
El jugador dos adivinó 9.
El tercer jugador adivinó 9.
Los jugadores tendrán que intentarlo de nuevo.
Java elimina el
El número a adivinar es 7.
Basura
Supongo que 3
supongo que 0
Supongo que 9
El jugador uno adivinó 3.
El jugador dos adivinó 0
El tercer jugador adivinó 9.
Los jugadores tendrán que intentarlo de nuevo.
El número a adivinar es 7.
Supongo que 7
Supongo que 5
supongo que 0
El jugador uno adivinó 7.
El segundo jugador adivinó 5.
El jugador tres adivinó 0.
¡Tenemos un ganador!

¿El jugador uno lo entendió bien? cierto El


jugador dos lo entendió bien? FALSO
¿El jugador tres lo entendió bien? FALSO
El juego ha terminado.

40 capitulo 2
Machine Translated by Google

clases y objetos

no existen
Preguntas tontas

hazlo pegado

aleatorio()

público
estático
PUNTOS DE VIÑETA

La programación orientada a objetos le permite ampliar


un programa sin tener que tocar el código de trabajo

estática pública final previamente probado.


Todo el código Java se define en una clase.

Una clase describe cómo crear un objeto de ese tipo


de clase. Una clase es como un plano.

Un objeto puede cuidar de sí mismo; no es necesario


saber ni importarle cómo lo hace el objeto.

Un objeto sabe cosas y hace cosas.

Las cosas que un objeto sabe sobre sí mismo se


denominan variables de instancia. Representan el estado
de un objeto.

Las cosas que hace un objeto se llaman métodos.


Representan el comportamiento de un objeto.

aleatorio() Cuando crea una clase, es posible que también desee


crear una clase de prueba separada que usará para
Matemáticas crear objetos de su nuevo tipo de clase.
Una clase puede heredar variables de instancia y

métodos de una superclase más abstracta.

En tiempo de ejecución, un programa Java no es más


que objetos que "hablan" con otros objetos.

usted está aquí 41


Machine Translated by Google

ejercicio: Sea el compilador

Cada uno de los archivos Java en esta


página representa un archivo fuente completo.
Su trabajo es jugar al compilador y
determinar si cada uno de estos
archivos se compilará.
Si no se compilan, ¿cómo
los solucionaría y, si lo hacen,
cuál sería su resultado?

A
clase TapeDeck {

booleano canRecord = falso; B


clase reproductor de DVD {

anular reproducircinta() {
[Link](“reproducción de cinta”); booleano canRecord = falso;
}
anular registroDVD() {
cinta de registro vacía() { [Link](“grabación de DVD”);
[Link](“grabación en cinta”); }
} }
}
clase DVDPlayerTestDrive {
clase TapeDeckTestDrive {public público estático vacío principal (String [] argumentos) {
static void main(String [] args) {
Reproductor de DVD d = nuevo reproductor
[Link] = verdadero; de DVD(); [Link] =

[Link](); verdadero; [Link]();

si ([Link] == verdadero) { si ([Link] == verdadero) {


[Link](); [Link]();

} }

} }

} }

42 capitulo 2
Machine Translated by Google

clases y objetos

[Link]();

DrumKit d = nuevo DrumKit();

sombrero de copa booleano =

verdadero; trampa booleana = verdadero;

void playSnare()

{ [Link](“bang bang ba­bang”);

público estático vacío principal (String [] argumentos) {

if ([Link]
== verdadero)
{ [Link]();
}

[Link] = falso;

clase DrumKitTestDrive {

[Link]();
clase DrumKit {

void playTopHat ()
Ventana de edición de archivos Ayuda Dance
} { [Link](“ding ding da­ding”);
% java DrumKitTestDrive bang bang
ba­bang ding ding da­ding

usted está aquí 43


Machine Translated by Google

rompecabezas: rompecabezas de piscina

clase pública EchoTestDrive {


público estático vacío principal (String [] argumentos) {
Eco e1 = nuevo Eco();
__________________________
Rompecabezas de piscina
int x = 0;
mientras ( ___________ ) {

[Link]();
__________________________
si ( ____________ ) {
[Link] = [Link] + 1;
}
si ( ____________ ) {
[Link] = [Link] + [Link];

Implosión de ayuda de la ventana de edición de archivos }


%java EchoTestDrive x = x + 1;
holaaa... }
holaaa... [Link]([Link]);
holaaa... }
}
holaaa...
10
clase ____________ {
En t _________ = 0;
vacío ___________ {
[Link](“holaaaa... “);
}
}

44 capítulo 2
Machine Translated by Google

clases y objetos

¿Quién soy?

Estoy compilado a partir de un archivo .java. clase

Los valores de mis variables de instancia


pueden ser diferentes de los valores de
mi amigo.

Me comporto como una plantilla.

Me gusta hacer cosas.

Puedo tener muchos métodos.

Represento al "estado".

Tengo comportamientos.

Estoy ubicado en objetos.

Vivo en el montón.

Estoy acostumbrado a crear instancias de objetos.

Mi estado puede cambiar.

Declaro métodos.

Puedo cambiar en tiempo de ejecución.

usted está aquí 45


Machine Translated by Google

soluciones de ejercicio

Sea el compilador:

clase TapeDeck
{ booleano canRecord = false;
anular reproducircinta() {
[Link](“reproducción de cinta”);
A
} cinta de registro nula() {
[Link](“grabación en cinta”);
}
}

clase TapeDeckTestDrive {public


Imanes de código:
static void main(String [] args) {
clase DrumKit {

TapeDeck t = nuevo TapeDeck( );


sombrero de copa booleano = [Link] = verdadero;
verdadero; trampa booleana = verdadero; [Link]();

anular jugarTopHat() { if ([Link] == verdadero)


[Link](“ding ding da­ding”); { [Link]();
} }
} ¡Tenemos la plantilla, ahora tenemos
anular jugarSnare() { } que hacer un objeto!
[Link](“bang bang ba­bang”);
}
}
clase DVDPlayer
{ booleano canRecord = false;
clase DrumKitTestDrive {public static
anular registroDVD() {
void main(String [] args) {
[Link](“grabación de DVD”);

DrumKit d = nuevo DrumKit();


} void playDVD ( )
[Link](); [Link]
{ [Link](“Reproducción de DVD”);
= falso; [Link]();
}
}

if ([Link] == verdadero)
clase DVDPlayerTestDrive { public
{ [Link]();
static void main(String [] args) { DVDPlayer d = new
}
DVDPlayer(); [Link] = verdadero;
}
B [Link](); if
}
([Link]
== verdadero) { [Link]();
Ventana de edición de archivos Ayuda Dance

% java DrumKitTestDrive bang bang


}
ba­bang ding ding da­ding
} La línea: [Link]( ); ¡No
} compilaría sin un método!

46 capítulo 2
Machine Translated by Google

clases y objetos

Rompecabezas de piscina

clase pública EchoTestDrive {


público estático vacío principal (String [] argumentos) {
Eco e1 = nuevo Eco();
clase
Eco e2 = nuevo Eco( ); // La respuesta correcta Estoy compilado a partir de un archivo .java.
­o­
Los valores de mis variables de instancia pueden
Eco e2 = e1; // ¡es la respuesta extra! ser diferentes de los valores de mi amigo. objeto
int x = 0;
Me comporto como una plantilla. clase
mientras ( x < 4 ) {
[Link](); Me gusta hacer cosas. objeto, clase de
[Link] = [Link] + 1;
si ( x == 3 ) { Puedo tener muchos métodos. método, objeto

[Link] = [Link] + 1; Instancia variable


Represento al "estado".

Tengo comportamientos. objeto, clase


} si ( x > 0 ) {
[Link] = [Link] + [Link]; método, variable de instancia
Estoy ubicado en objetos.
}
Vivo en el montón. objeto
x = x + 1;
}
Estoy acostumbrado a crear instancias
[Link]([Link]); de objetos. clase
}
} objeto, variable de instancia
Mi estado puede cambiar.

Declaro métodos. clase


clase eco {
recuento int = 0; hola Puedo cambiar en tiempo de ejecución. objeto, variable de instancia

vacío ( ) {
[Link](“holaaaa... “); Nota: se dice que tanto las clases como los objetos tienen estado y comportamiento.
} Están definidos en la clase, pero también se dice que el objeto los "tiene". En
} este momento, no nos importa dónde técnicamente vivir.

Ventana de edición de archivos Ayuda para asimilar

%java EchoTestDrive
holaaa...
holaaa...
holaaa...
holaaa...
10

usted está aquí 47


Machine Translated by Google
Machine Translated by Google

3 primitivas y referencias

Conozca sus variables

Las variables vienen en dos tipos: primitivas y de referencia.


estado local

argumentos

tipos de devolución

primitivo En t

complejo tiene que haber

más a la vida

este es un nuevo capitulo 49


Machine Translated by Google

declarando una variable

Declarando una variable

brincar()

Tolva de conejo = nueva jirafa();


Java se preocupa por el tipo.

No puedes poner una jirafa en


una variable de conejo.

las variables deben tener un tipo

las variables deben tener un nombre

recuento int;

nombre
tipo

50 capitulo 3
Machine Translated by Google

primitivos y referencias

"Me gustaría un moca doble, no, que sea un int". Tipos primitivos
Tipo Profundidad de bits Rango de valores

booleano y char

numérico (todos están firmados)

entero

punto flotante

Declaraciones primitivas con


pequeño corto alto grande
asignaciones:

largo En t byte corto

Tenga en cuenta la 'f'. Tengo que tener


eso con un punto flotante, porque Java

piensa que cualquier cosa con un punto


byte corto int 8 16 32 largo flotador doble
flotante es doble, a menos que uses 'f'.
64 32 64

usted está aquí 51


Machine Translated by Google

asignación primitiva

Tú en realidad no quiero derramar eso...


Afila tu lápiz

entero x = 24;

byte b = x;
//¡¡no funcionará!!

[Link] = 34,5;

2. booleano boo = x;

3. int g = 17;

4. int y = gramo;

5. y = y + 10;

6. s cortas;

tamaño entero = 32; declara un tamaño int llamado , asígnale el valor 32 7.s = y;

carácter inicial = 'j'; declara un carácter llamado inicial, asígnale el valor 'j'
8. byte b = 3;
doble d = 456,709; declara un doble llamado d, asígnale el valor 456.709
9. byte v = b;
booleano es loco; declarar un booleano llamado isCrazy (sin asignación)
10. corto n = 12;
está loco = verdadero; asignar el valor verdadero al isCrazy previamente declarado
11. v = norte;
int y = x + 456; declara un int llamado y, asígnale el valor que es la suma
de lo que sea x ahora más 456
[Link] k = 128;

52 capítulo 3
Machine Translated by Google

primitivos y referencias

¡Aléjate de esa palabra clave!

hazlo pegado
Debe comenzar con una letra, un guión bajo (_) o un signo de dólar ($). No
puedes empezar un nombre con un número.

Después del primer carácter, también puedes usar números. Simplemente no


empieces con un número.

Puede ser lo que quieras, sujeto a esas dos reglas, siempre y cuando no sea una
de las palabras reservadas de Java.

No importa lo que
escuches, no, repito, no me
no uses ninguno dejes ingerir otro perro
para tus de
estos
propio peludo de gran tamaño.
vacío público estático
nombres.

booleano char byte short int long float doble

Esta mesa reservada.


booleano carbonizarse doble flotar En t corto público privado

protegido resumen de bytes final nativo estático estrictofp transitorio sincronizado largo volátil si

más hacer mientras cambiar caso predeterminado para pausa continuar afirmar

clase se extiende implementa el lanzamiento de en vez de interfaz nuevo paquete súper este

atrapar finalmente intentar


importación lanza devolver vacío constante
ir a enumeración

Palabras clave de Java y otras palabras reservadas (sin ningún orden útil). Si los usa para nombres, el compilador se enojará mucho, mucho .

usted está aquí 53


Machine Translated by Google

referencias de objetos

Controlando tu objeto Perro

Perro d = nuevo Perro();


[Link]();
En realidad, no existe nada parecido a una variable de objeto .

Sólo hay una variable de referencia de objeto . piensa en esto


Una variable de referencia de objeto contiene bits que representan
como esto
acceso un objeto.
manera de

No contiene el objeto en sí, pero contiene algo así como un


puntero. O una dirección. Excepto que en Java realmente no
sabemos que qué está dentro de una variable de referencia. Nosotros hacer
sea lo que sea, representa un solo objeto. Y la JVM sabe cómo
utilizar la referencia para llegar al objeto.

Piense en una

variable de referencia de

Perro como un control remoto de Perro.

Lo usas para conseguir que

el objeto haga algo (invocar

métodos).

[Link]();

54 capítulo 3
Machine Translated by Google

primitivos y referencias

Los 3 pasos de declaración,


creación y asignación de objetos.

1 2
3
referencia Perro miPerro = nuevo Perro();
byte corto int 16 32 largo
8 64 (la profundidad de bits no es relevante)

Una referencia de objeto es Declarar una variable de referencia

simplemente otro valor de variable. 1


Perro miPerro = nuevo Perro();

Mi perro
Variable primitiva
00000111
byte x = 7;
primitivo Perro
valor
byte

Variable de referencia 2 Crea un objeto


mi

Perro miPerro = nuevo Perro(); bj Perro miPerro = nuevo Perro();


D oh gramo
oh

referencia
valor
Perro Objeto de perro

Con variables primitivas, el valor de la variable es...


el valor (5, ­26,7, 'a'). 3 Vincular el objeto y la
Con variables de referencia, el valor de la referencia

variable es... bits que representan una forma de perro mi perro = nuevo Perro();
llegar a un objeto específico.

No sabe (ni le importa) cómo una JVM en particular


implementa referencias a objetos. Claro, pueden ser
un puntero a un puntero a... pero incluso si lo
sabes , todavía no puedes usar los bits para Objeto de perro
nada más que acceder a un objeto.
Mi perro

No nos importa cuántos unos y ceros haya en una variable de referencia. Depende de
cada JVM y de la fase de la luna.
Perro

usted está aquí 55


Machine Translated by Google

referencias de objetos

no existen
Preguntas tontas

La entrevista de esta semana:

Referencia de objeto

HeadFirst: Entonces, cuéntanos, ¿cómo es la vida de una referencia de objeto?

Referencia: Bastante simple, de verdad. Soy un control remoto y puedo programarlo para controlar
diferentes objetos.

HeadFirst: ¿Te refieres a diferentes objetos incluso mientras estás corriendo? Por ejemplo, ¿puedes
referirte a un perro y luego, cinco minutos después, referirte a un automóvil?

Referencia: Por supuesto que no. Una vez que me declaren, eso es todo. Si soy el control remoto de un perro,
entonces nunca podré señalar (ups, qué pena, se supone que no debemos decir señalar) , es decir, referirme a
cualquier cosa que no sea un perro.

HeadFirst: ¿Eso significa que puedes referirte a un solo perro?

Referencia: No. Puedo referirme a un Perro y luego, cinco minutos después, puedo referirme a otro Perro.
Siempre que sea un perro, puedo ser redirigido (como reprogramar el control remoto a un televisor diferente)
hacia él. A menos... no, no importa.

HeadFirst: No, dímelo. ¿Qué ibas a decir?

Referencia: No creo que quieras entrar en esto ahora, pero solo te daré la versión corta: si estoy marcado
como final, una vez que se me asigne un Perro, nunca podré ser reprogramado para cualquier otra cosa
menos ese único Perro. En otras palabras, no se me puede asignar ningún otro objeto.

HeadFirst: Tienes razón, no queremos hablar de eso ahora. Bien, a menos que seas definitivo, entonces
puedes referirte a un Perro y luego referirte a otro Perro diferente más tarde. ¿Alguna vez puedes referirte a
nada en absoluto? ¿Es posible no estar programado para nada?

Referencia: Sí, pero me molesta hablar de ello.

HeadFirst: ¿Por qué es eso?

Referencia: Porque significa que soy nulo y eso me molesta.

HeadFirst: ¿Quieres decir porque entonces no tienes valor?

Referencia: Oh, nulo es un valor. Sigo siendo un control remoto, pero es como si trajeras a casa un nuevo
control remoto universal y no tuvieras televisor. No estoy programado para controlar nada. Pueden presionar
mis botones todo el día, pero no pasa nada bueno. Me siento tan... inútil. Un desperdicio de bits. Por
supuesto, no tantos bits, pero aún así. Y esa no es la peor parte. Si soy la única referencia a un objeto en
particular y luego se me establece en nulo (desprogramado), significa que ahora nadie puede acceder a ese
objeto al que me estaba refiriendo.

HeadFirst: Y eso es malo porque...

Referencia: ¿Tienes que preguntar? Aquí he desarrollado una relación con este objeto, una conexión
íntima, y luego el vínculo se corta repentina y cruelmente. Y nunca volveré a ver ese objeto, porque ahora
es elegible para la recolección de basura [del productor, cue de música trágica].
Oler. ¿Pero crees que los programadores alguna vez consideran eso? Olfatear. ¿ Por qué no puedo ser
primitivo? Odio ser un referente. La responsabilidad, todos los apegos rotos...

56 capítulo 3
Machine Translated by Google

primitivos y referencias

La vida en el montón de basura recolectable


1
Libro b = nuevo Libro();

Libro c = nuevo Libro(); Bohohk bj miCt


oh
2

b Bohohk bj miCt
oh

Libro

Libro

Libro d = c;
1

Bohohk bj miCt
oh
2

b t
Ambos C y d referirse a lo mismo Bohohk bj miC
oh
objeto.
Las variables
C d
y contienen dos copias
Libro
diferentes del mismo valor. Dos controles
remotos programados para un televisor. C

Libro
d

Libro

c = segundo;

mi Ct 2
Bohohk ohbj
b t
Tanto b como c se refieren al mismo
objeto.
Bohohk bj miC
oh

Libro

d
usted está aquí 57
Machine Translated by Google

objetos en el montón

Vida y muerte en el montón


1
Libro b = nuevo Libro();

Libro c = nuevo Libro(); Bohohk bj miCt


oh
2

b Bohohk bj miCt
oh

Libro

Libro
segundo = c;
Este tipo está
1 acabado. cebo recolector de basura.

Bohohk bj miCtoh 2
Tanto b como c se refieren al mismo objeto. El
objeto 1 está abandonado y es elegible para la
recolección de basura (GC).
b t
Bohohk bj miC oh

Libro

Libro
c = nulo;
Todavía tostadas
nulo 1
Aún no tostado
(seguro siempre que
Bohohk bj miCt
oh
2 b se refiera a él)

El objeto 2 todavía tiene una referencia


b la tenga, el objeto no
activa () y, mientras b t
es elegible para GC. Bohohk bj miC
oh

Libro
referencia nula
C
(no programado para nada)

Libro
58 capítulo 3
Machine Translated by Google

primitivos y referencias

Un conjunto es como una bandeja de tazas.

Declarar una variable de matriz int. Una variable de matriz


1 es un control remoto de un objeto de matriz.
int[] números;

Cree una nueva matriz int con una longitud


2 de 7 y asígnela a los números de variable
int[] previamente declarados.

números = nuevo int[7];

7 variables internas
Asigne a cada elemento de la matriz
3 un valor int.
Recuerde, los elementos en un int
formación son solo int variables .

números[0] = 6; En t En t En t En t En t En t En t
números[1] = 19;
7 variables internas

números[2] = 44;
números[3] = 42;
objeto de matriz int (int [])
números[4] = 10; números

números[5] = 20;
números[6] = 1; En t[] Observe que la matriz en sí es un objeto, aunque los 7
elementos sean primitivos.

Las matrices también son objetos.

usted está aquí 59


Machine Translated by Google

una serie de objetos

Haz una variedad de perros

Declarar una variable de matriz Dog


1
Perro[] mascotas;

Cree una nueva matriz Dog con una


2 longitud de 7 y asígnela al Dog[]
previamente declarado.
mascotas variables

mascotas = nuevo Perro[7];

Perro Perro Perro Perro Perro Perro Perro


¿Qué falta?
mascotas

Objeto de matriz de perros (Perro [])


Perro[]

Cree nuevos objetos Dog y asígnelos


3 a los elementos de la matriz. oh bj mi
Ct oh bj mi
Doh Ct
gramo

Doh
gramo

Recuerde, los elementos de un Perro


son solo una referencia de
variables de Perro.
matriz ¡Todavía necesitamos perros!

mascotas[0] = nuevo Perro();


mascotas[1] = nuevo Perro();

Afila tu lápiz

Perro Perro Perro Perro Perro Perro Perro

mascotas

Objeto de matriz de perros (Perro [])


Perro[]

60 capitulo 3
Machine Translated by Google

primitivos y referencias

Perro Controla a tu perro


nombre (con una variable de referencia)

Perro fido = nuevo Perro();


ladrar() nombre
comer() [Link] = “Fido”;
perseguirgato()

Cadena

Ct
mi
Doh ohbj
gramo

fido

Perro
[Link]();
Java se preocupa por el tipo. [Link]();
Una vez que haya declarado una matriz, no
podrá poner nada en ella excepto cosas que ¿Qué sucede si el Perro está en una
sean del tipo de matriz declarada.
matriz de Perros?
Por ejemplo, no puedes poner un gato en un
grupo de perros (sería bastante horrible si
alguien pensara que solo hay perros en el
grupo, entonces le pide a cada uno que ladre y
luego, para su horror, descubre que hay un
gato al acecho). ) Y no puedes insertar un doble
en una matriz int (derrame, ¿recuerdas?).
Sin embargo, puedes poner un byte en una
matriz int, porque un byte siempre cabe en una taza de tamaño int.
Esto se conoce como ampliación implícita.
Entraremos en detalles más adelante, por
ahora solo recuerde que el compilador no le
Perro[] misPerros = nuevo Perro[3];
permitirá colocar algo incorrecto en una matriz, según
el tipo declarado de la matriz. misPerros[0] = nuevo Perro();
misPerros[0].nombre = “Fido”;
misPerros[0].bark();

*Sí, sabemos que no estamos demostrando la encapsulación aquí, pero


intentamos mantenerlo simple. Por ahora. Haremos la encapsulación en el capítulo 4.

usted está aquí 61


Machine Translated by Google

usando referencias

clase perro {
Un ejemplo de perro
Nombre de cadena;

público estático vacío principal (String[] args) { Perro

// crear un objeto Perro y acceder a él


nombre
Perro perro1 = nuevo Perro();

[Link](); ladrar()

comer()
[Link] = “Bart”;
perseguirgato()

// ahora creamos una matriz Dog

Perro[] misPerros = nuevo Perro[3];

// y ponle algunos perros Ventana de edición de archivos Ayuda Howl

misPerros[0] = nuevo Perro(); %java Perro


misPerros[1] = nuevo Perro(); nulo dice Ruff!
misPerros[2] = perro1; El último nombre del perro es Bart.

// ahora accede a los Perros usando la matriz ¡Fred dice Ruff!


// referencias ¡Marge dice Ruff!
misPerros[0].nombre = “Fred”; ¡Bart dice Ruff!
misPerros[1].nombre = “Marge”;

// Hmmmm... ¿cuál es el nombre de myDogs[2]?

[Link](“el último nombre del perro es “);


PUNTOS DE VIÑETA
[Link](misPerros[2].nombre);
Las variables vienen en dos tipos: primitivas y de
referencia.
// ahora recorremos la matriz
Las variables siempre deben declararse con un nombre y
// y dile a todos los perros que ladren
un tipo.
int x = 0;
Un valor de variable primitiva son los bits que representan el
while(x <[Link]) { valor (5, 'a', verdadero, 3,1416, etc.).
misPerros[x].bark(); Un valor de variable de referencia son los bits
Las matrices tienen una variable
x = x + 1; que representan una forma de llegar a un objeto en el
'longitud' que le proporciona el
montón.
} número de elementos en la matriz.
Una variable de referencia es como un control remoto.
}
Usar el operador de punto (.) en una variable de
referencia es como presionar un botón en el control remoto
corteza de vacío público () {
para acceder a un método o variable de instancia.

[Link](nombre + ¡dice Ruff!”); Una variable de referencia tiene un valor nulo cuando no
} hace referencia a ningún objeto.

comer vacío público () { } Una matriz es siempre un objeto, incluso si se declara

persecución pública vacía () { } que la matriz contiene primitivas. No existe una matriz
primitiva, solo una matriz que contiene primitivas.
}

62 capítulo 3
Machine Translated by Google

primitivos y referencias

Cada uno de los archivos Java en esta


página representa un archivo fuente completo.
Su trabajo es jugar al compilador y
determinar si cada uno de estos archivos se
compilará. Si no se compilan,
¿cómo los solucionarías?

A B
libros de clase { clase Hobbits {
Título de cadena;
Autor de cadena; Nombre de cadena;

}
público estático vacío principal (String [] argumentos) {
clase BooksTestDrive {public
static void main(String [] args) { Hobbits [] h = nuevos Hobbits[3]; int z =

Libros [] misLibros = nuevos Libros[3]; int x
= 0; mientras (z < 4) {
myBooks[0].title = “Las uvas de Java”; misLibros[1].title z = z + 1;
= “El Gatsby de Java”; myBooks[2].title = “El libro h[z] = nuevos Hobbits();
de cocina de Java”; misLibros[0].autor = “bob”; h[z].nombre = “bilbo”; if (z
misLibros[1].autor = “demandar”; == 1) { h[z].nombre
misLibros[2].autor = “ian”; = “frodo”;

} if (z == 2)
while (x < 3) { h[z].nombre = “sam”;
{ [Link](misLibros[x].título); }
[Link](“ por “); [Link](h[z].nombre + “es un”);
[Link](misLibros[x].autor); x = x + 1; [Link](“buen nombre Hobbit”);
}
} }
} }
}

usted está aquí 63


Machine Translated by Google

Ejercicio: Código Imanes

int y = 0;
ref = índice[y];

islas[0]
= “Bermudas”;
islas[1]
= “Fiyi”;
islas[2]
= “Azores”;
islas[3]
= “Cozumel”;
referencia interna;

mientras (y < 4) {

[Link](islas[ref]);

índice[0] = 1;
índice[1] = 3;
índice[2] = 0;
índice[3] = 2;

String [] islas = new String[4];

[Link](“isla = “);

int [] índice = nuevo int[4];


y = y + 1;

Ventana de edición de archivos Ayuda Bikini

clase matrices de prueba {


% java TestArrays isla
= Isla Fiji = Isla
Cozumel = Bermudas
público estático vacío principal (String [] argumentos) {
isla = Azores

64 capítulo 3
Machine Translated by Google

primitivos y referencias

clase Triángulo { (A veces no utilizamos una clase de


doble zona; prueba separada porque intentamos
altura interna; ahorrar espacio en la página)

Rompecabezas de piscina longitud interna;


público estático vacío principal (String [] argumentos) {
____________
________________________
mientras ( __________ ){
__________________________
________.altura = (x + 1) * 2;
________.longitud = x + 4;
__________________________
[Link](“triángulo “+x+”, área”);

[Link](“ = + _______.área);
Ventana de edición de archivos Ayuda Bermudas ________________
%java Triángulo
}
triángulo 0, área = 4,0
______________
triángulo 1, área = 10,0
x = 27;
triángulo 2, área = 18,0
Triángulo t5 = ta[2];
triángulo 3, área = ___
ta[2].área = 343;
y= ______________________ “
[Link](“y = +y);
[Link](“, área t5 = “+ área t5);
}
void setArea() {
____________ = (alto * largo) / 2;
}
}

usted está aquí sesenta y cinco


Machine Translated by Google

rompecabezas: Montón de problemas

clase MontónQuiz {
identificación interna = 0;

público estático vacío principal (String [] argumentos) {


int x = 0;
HeapQuiz [ ] hq = nuevo HeapQuiz [5]; mientras (x < 3) {

hq[x] = nuevo HeapQuiz();


hq[x].id = x;
x = x + 1;

} hq[3] = hq[1];
hq[4] = hq[1];
hq[3] = nulo;
hq[4] = hq[0];
hq[0] = hq[3];
hq[3] = hq[2];
hq[2] = hq[0];
// hacer cosas
}
}

identificación = 0

hq[0]
unir cada variable de
referencia con objeto(s)

coincidente(s)
sede[1]
Quizás no sea necesario
utilizar todas las referencias. identificación = 1

sede[2]

sede[3]
identificación = 2

sede[4]

66 capítulo 3
Machine Translated by Google

primitivos y referencias

El caso de las referencias robadas

Era una noche oscura y tormentosa. Tawny entró en el bullpen de los programadores como si fuera
la dueña del lugar. Sabía que todos los programadores seguirían trabajando duro y quería ayuda.
Necesitaba agregar un nuevo método a la clase fundamental que se iba a cargar en el nuevo teléfono celular
ultrasecreto habilitado para Java del cliente. El espacio en la memoria del teléfono móvil era tan reducido
como el de la camiseta de Tawny, y todo el mundo lo sabía. El normalmente estridente zumbido en el bullpen
se calló cuando Tawny se dirigió hacia el pizarrón blanco. Esbozó una rápida descripción general de la
funcionalidad del nuevo método y escaneó lentamente la habitación. “Bueno, muchachos, es hora de decidirse”, ronroneó.
"Quien cree la versión más eficiente en memoria de este método vendrá conmigo mañana a la fiesta de
Cinco minutos lanzamiento del cliente en Maui... para ayudarme a instalar el nuevo software".

Misterio A la mañana siguiente, Tawny entró en el bullpen con su vestido corto Aloha.
“Señores”, sonrió, “el avión sale en unas horas, ¡muéstrenme lo que tienen!”. Bob fue primero;
Mientras comenzaba a esbozar su diseño en la pizarra, Tawny dijo: "Vayamos al grano, Bob,
muéstrame cómo manejaste la actualización de la lista de objetos de contacto". Bob rápidamente
dibujó un fragmento de código en la pizarra:

Contacto [] ca = nuevo contacto[10];


mientras (x<10) { // crear 10 objetos de contacto
ca[x] = nuevo contacto();
x = x + 1;
}

// hacer complicadas listas de contactos actualizando cosas con ca

"Tawny, sé que tenemos poca memoria, pero tu especificación decía que teníamos que poder acceder
a la información de contacto individual de los diez contactos permitidos; este fue el mejor esquema que
pude idear", dijo Bob. Kent fue el siguiente, ya imaginando cócteles de coco con Tawny. "Bob", dijo, "tu
solución es un poco torpe, ¿no crees?" Kent sonrió, "Echa un vistazo a este bebé":

Contacto refc;
mientras (x<10) { // crea 10 objetos de contacto
refc = nuevo contacto();
x = x + 1;
}

// haz cosas complicadas para actualizar la lista de contactos con refc

“Guardé un montón de variables de referencia en memoria, Bob­o­rino, así que guarda tu protector
solar”, se burló Kent. “¡No tan rápido Kent!”, dijo Tawny, “has guardado un poco de memoria, pero Bob viene
conmigo”.

¿Por qué Tawny eligió el método de Bob en lugar del de Kent, cuando Kent usaba menos memoria?

usted está aquí 67


Machine Translated by Google

soluciones de ejercicio

libros de clase {
Soluciones de ejercicio
Título de cadena;
Autor de cadena;

} clase BooksTestDrive
{ public static void main(String [] args) { Libros []
myBooks = new Books[3]; int x = 0;
misLibros[0]
A = nuevos Libros(); Recuerde: tenemos que myBooks[1] =
new Books(); en realidad crea los Libros myBooks[2] = new
Imanes de código:
Books(); objetos ! myBooks[0].title = “Las
clase matrices de prueba { uvas de Java”; misLibros[1].title = “El Gatsby de Java”;
myBooks[2].title = “El libro de cocina de Java”;
público estático vacío principal (String [] argumentos) {
misLibros[0].autor = “bob”; misLibros[1].autor =
int [] índice = nuevo int[4];
“demandar”; misLibros[2].autor =
índice[0] = 1;
“ian”; while (x < 3)
índice[1] = 3; { [Link](misLibros[x].título);
índice[2] = 0; [Link](“ por
índice[3] = 2; “); [Link](misLibros[x].autor); x = x
+ 1;
String [] islas = new String[4];
islas[0] = “Bermuda”;
islas[1] = “Fiji”;
}
islas[2] = “Azores”; islas[3] = }
“Cozumel”; }
int y = 0;
clase Hobbits
referencia interna;
{ nombre de
mientras (y < 4) {
cadena; public static void main(String [] args) { Hobbits
ref = índice[y]; [] h = nuevos Hobbits[3]; int z = ­1;
[Link](“isla = “); Recuerde: las matrices comienzan con while (z < 2)
[Link](islas[ref]); { elemento 0 ! z = z + 1; h[z] =
y = y + 1; nuevos
Hobbits(); h[z].nombre =
}
“bilbo”; if (z == 1)
} B
{ h[z].nombre =
} Ventana de edición de archivos Ayuda Bikini
“frodo”;

% java TestArrays isla


} if (z == 2)
= Isla Fiji = Isla
Cozumel = Isla { h[z].nombre = “sam”;
Bermuda = Azores }
[Link](h[z].nombre + “es un”);
[Link](“buen nombre Hobbit”);
}
}
}

68 capítulo 3
Machine Translated by Google

primitivos y referencias

Soluciones de rompecabezas

El caso de las referencias robadas

Triángulo
clase Triángulo
{ área{doble;
clase
interna;
doble zona;
altura
altura
interna; longitud
vacío
interna;
estático
principal
público
args) { int
(String
x = 0;[]int
args)
x = {0;principal vacío estático público (String []

Triángulo [ ] ta = nuevo Triángulo[4];


(mientras
x < 4 ) { ( x < 4 ) { mientras

ta[x]
= nuevo
= nuevo
Triángulo();
Triángulo(); ta[x]
ta[x].altura
1) * 2; ta[x].longitud
= (x + 1) =
* 2;
x +ta[x].altura
4; ta[x].longitud
= (x +
=
ta[x].setArea();
x + 4; ta[x].setArea(); (El software fue un gran éxito y el cliente les dio a Tawny y Bob una semana adicional en
Hawaii. Nos gustaría decirles que al terminar este libro usted también obtendrá cosas como esas).

[Link](“triángulo
“+x+”, área”); “+x+”, área”); [Link](“triángulo
““
[Link](“ = x = x + 1; x = + ta[x].área); +
ta[x].área);
x + 1;

}int} int
y =yx;= xx;=
27; x = 27;
identificación = 0

Triángulo t5 = ta[2];
ta[2].área
= 343; = 343; ta[2].área hq[0]
““
[Link](“y = +y); +y);
[Link](“,
= “+ área t5); área t5 = “+ área t5); [Link](“, área t5
}} sede[1]
void
setArea()
setArea()
{ área
{ void
= (alto *
identificación = 1

largo) / 2; área = (alto * largo) / 2;


sede[2]
}}

}} Ventana de edición de archivos Ayuda Bermudas

%java Triángulo
triángulo 0, área = 4,0 triángulo
1, área = 10,0 sede[3]
triángulo 2, área = 18.0 triángulo identificación = 2

3, área = 28.0 y = 4, t5 área =


343
sede[4]

usted está aquí 69


Machine Translated by Google
Machine Translated by Google

4 métodos utilizan variables de instancia

Cómo se comportan los objetos


¡Esto debería
cambiar su estado!

El estado afecta el comportamiento, el comportamiento afecta al estado.

este es un nuevo capitulo 71


Machine Translated by Google

Los objetos tienen estado y comportamiento.

Recuerde: una clase describe lo que


un objeto sabe y lo que hace un objeto.
Canción

variables de título sabe


instancia artista
(estado)
setTitle()
métodos setArtist()
hace
(comportamiento) reproducir()
¿Puede cada objeto de ese tipo tener un comportamiento
de método diferente?

cinco instancias
de la clase Song
política

A mi manera
Coldplay
Sinatra

Estrella negra A mi manera

pistolas sexuales
Agradecido
Muerto
Cantar

travis

juego nulo() {

[Link](título);
}

s3

t2

Canción

Canción t2 = nueva canción(); Llamar a play() en esta instancia


[Link]();
[Link](“Travis”); hará que se reproduzca "Sing". Canción [Link]();
[Link](“Cantar”);

Canción s3 = nueva canción(); Llamar a play() en esta instancia


[Link](“Sex Pistols”);
hará que se reproduzca “My
[Link](“A mi manera”);
Way”. (pero no el de Sinatra)

*Sí, ¡otra respuesta sorprendentemente clara!

72 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

El tamaño afecta la corteza.

Perro
clase perro {
tamaño
tamaño entero;
nombre
Nombre de cadena;
ladrar()

corteza vacía() {

si (talla > 60) {

[Link](“¡Guau! ¡Guau!”);

} si no (talla > 14) {

[Link](“¡Ruff! ¡Ruff!”);

} demás {

[Link](“¡Ay! ¡Ay!”);

clase DogTestDrive {

público estático vacío principal (String[] args) {

Perro uno = nuevo Perro();

talla única = 70;

Perro dos = nuevo Perro();

[Link]ño = 8;

Perro tres = nuevo Perro();

[Link]ño = 35;
Ayuda de la ventana de edición de archivos Playdead

%java prueba de perro


[Link]();
¡Guau! ¡Guau!
[Link]();
¡Sí! ¡Sí!
[Link]();
¡Fallar! ¡Fallar!
}

usted está aquí 73


Machine Translated by Google

parámetros del método

Puedes enviar cosas a un método.

[Link](3);

Un método utiliza parámetros. Una persona que llama pasa argumentos.

Perro d = nuevo Perro();


Llame al método ladrar en la referencia Perro y
1 pase el valor 3 (como argumento del método).
[Link](3);
argumento

Los bits que representan el valor int


2 3 se entregan al método ladrar.

parámetro 00000011 3 Los bits aterrizan en el parámetro


numOfBarks (una variable de tamaño entero).
En t

corteza vacía (int numOfBarks) {


Utilice el parámetro
mientras (númDeBarcas > 0) { 4
numOfBarks como variable en
el código del método.
[Link](“ruff”);
numOfBarks = numOfBarks ­ 1;
}
}

74 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

puedes conseguir cosas atrás de un método.

vacío

ir vacío() {
} Lindo...

pero no exactamente lo que yo


Estaba esperando.
int darSecreto() {
devolver 42;

¡Lo que sea que decir


devuelvas, lo devolverás!
mejor

El compilador no le permitirá devolver el tipo de elemento incorrecto.

00101010

En t

int elSecreto = [Link]();

Estos tipos deben coincidir

Los bits que representan 42 se devuelven desde


int darSecreto() { el método GiveSecret() y aterrizan en la
variable denominada theSecret.
devolver 42;
esto debe encajar
} en un int!

usted está aquí 75


Machine Translated by Google

múltiples argumentos

Puedes enviar más de una cosa


a un método.

Llamar a un método de dos parámetros y enviarle


dos argumentos.
ir vacío() {

TestStuff t = nuevo TestStuff();

[Link](12, 34);

} Los argumentos
orden en que los que pasas aterrizan en el mismo
pasó. Primer argumento tierras
en el primer parámetro, el segundo argumento en el
segundo parámetro,
etcétera.

vacío tomar dos (int x, int y) {

int z = x + y;

[Link](“El total es” +z);

Puede pasar variables a un método, siempre que


el tipo de variable coincida con el tipo de parámetro.

ir vacío() {
Los valores de foo y bar aterrizan en
int foo = 7; los parámetros xey. Entonces ahora
los bits en x son idénticos a los bits en
barra interna = 3;
foo (el patrón de bits para el entero '7') y
[Link](foo, barra); los bits en y son idénticos a los bits en bar.
}

vacío tomar dos (int x, int y) {


¿Cuál es el valor de z? Es el mismo
int z = x + y;
resultado que obtendrías si agregas
[Link](“El total es” +z); foo + bar en el momento en que los
pasas al método takeTwo
}

76 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

Java es paso por valor.

Eso significa pasar por copia.

00000111

X Declare una variable int y asígnele el


entero x = 7; 1 valor '7'. El patrón de bits de 7 va a
En t la variable denominada x.

z Declare un método con un


vacío ir(int z){ } 2
parámetro int llamado z.
En t

copia de x

3 Llame al método go(), pasando


00000111
00000111 la variable x como argumento.
X z Los bits en x se copian y la
copia llega a z.
En t En t

[Link](x); vacío ir(int z){ }

x y z no están 4 Cambie el valor de z dentro del


x no cambia, 00000000 método. ¡El valor de x no
incluso
si z lo hace. 00000111 conectados
z cambia! El argumento pasado al
X parámetro z era solo una copia de
En t
En t x.
vacío ir(int z){
El método no puede cambiar los
z = 0; bits que estaban en la variable
de llamada x.
}

usted está aquí 77


Machine Translated by Google

argumentos y valores de retorno

no existen
Preguntas tontas
Recordatorio: Java
¡Se preocupa por el tipo!
No puedes devolver una jirafa cuando el tipo de
devolución se declara como conejo. Lo
mismo con los parámetros. No puedes pasar
un
Jirafa en un método que requiere un
Conejo.

PUNTOS DE VIÑETA

Las clases definen lo que un objeto sabe y lo que hace.

Lo que un objeto sabe son sus variables de instancia


(estado).

Las cosas que hace un objeto son sus métodos (comportamiento).

Los métodos pueden utilizar variables de instancia para que los objetos

del mismo tipo puedan comportarse de manera diferente.

Un método puede tener parámetros, lo que significa que


puede pasar uno o más valores al método.

El número y tipo de valores que pase deben coincidir


con el orden y tipo de los parámetros declarados
por el método.

Los valores pasados dentro y fuera de los métodos pueden

promocionarse implícitamente a un tipo más grande o convertirse

explícitamente a un tipo más pequeño.

El valor que pasa como argumento a un método puede


ser un valor literal (2, 'c', etc.) o una variable del tipo de
parámetro declarado (por ejemplo, x donde x es una
variable int). (Hay otras cosas que puedes pasar como
argumentos, pero aún no hemos llegado a ese punto).

Un método debe declarar un tipo de retorno. Un tipo de


devolución nulo significa que el método no devuelve nada.

Si un método declara un tipo de retorno no nulo, debe


devolver un valor compatible con el tipo de retorno
declarado.

78 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

Cosas interesantes que puedes hacer con


parámetros y tipos de retorno

Guitarra electrica

marca

numOfPickups
rockStarUsesIt

Nota: El uso de estas


convenciones de
obtenerMarca()
nomenclatura
establecerMarca() significa que seguirás una

getNumOfPickups() ¡Importante
estándar Java!
setNumOfPickups()

getRockStarUsesIt()

setRockStarUsesIt()
clase Guitarra eléctrica {

Marca de cuerdas;
int numOfPickups; roca
booleanaStarUsesIt;

String getBrand() { devolver


marca;
}

void setBrand(String unaMarca) { marca =


unaMarca;
}

int getNumOfPickups() { return


numOfPickups;
}

void setNumOfPickups(int num) { numOfPickups =


num;
}

booleano getRockStarUsesIt() { return


rockStarUsesIt;
}

void setRockStarUsesIt(boolean síOrNo) { rockStarUsesIt = síOrNo;

}
}

usted está aquí 79


Machine Translated by Google

desarrolladores reales encapsulan

Encapsulación
Hazlo o corre el riesgo de ser humillado y

ridiculizado.
Jen dice que
estás bien encapsulado...

la altura del gato = 27;

Al obligar a todos a llamar a un método de


¡Ay! ¡No podemos establecimiento, podemos proteger al gato de

la altura del gato = 0; permitir que esto suceda! cambios de tamaño inaceptables.

conjunto vacío públicoHeight(int ht) {


si (ht > 9) {

altura = altura; Ponemos cheques


para garantizar a
} mínimo
altura del gato.
}

80 capitulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

Ocultar los datos


La entrevista de esta semana:

Un objeto se muestra sincero acerca de la encapsulación.

HeadFirst: ¿Cuál es el problema con la encapsulación?

Objeto: Bueno, ¿conoces ese sueño en el que estás dando una charla ante 500 personas y de repente te
das cuenta de que estás desnudo?

HeadFirst: Sí, ya lo hemos tenido. Está a la altura del de la máquina Pilates y... no, no iremos allí. Bien,
entonces te sientes desnudo. Pero además de estar un poco expuesto, ¿existe algún peligro?
público privado

Objeto: ¿Existe algún peligro? ¿Hay algún peligro? [empieza a reír] Oye, ¿todos los demás casos
público
escucharon eso: "¿Hay algún peligro?" ¿él pide? [cae al suelo riendo]

HeadFirst: ¿Qué tiene de gracioso eso? Parece una pregunta razonable.

Objeto: Está bien, lo explicaré. Es [se echa a reír de nuevo, sin control]

HeadFirst: ¿Puedo traerte algo? ¿Agua?

Objeto: ¡Uf! Oh chico. No, estoy bien, de verdad. Lo haré en serio. Respiracion profunda. OK adelante.

HeadFirst: Entonces, ¿de qué te protege la encapsulación?

Objeto: La encapsulación coloca un campo de fuerza alrededor de mis variables de instancia, para que nadie
pueda configurarlas, digamos, en algo inapropiado.

HeadFirst: ¿Puedes darme un ejemplo?

Objeto: Aquí no se requiere un doctorado. La mayoría de los valores de las variables de instancia están
codificados con ciertas suposiciones sobre los límites de los valores. Piense en todas las cosas que se
estropearían si se permitieran números negativos. Número de baños en una oficina. Velocidad de un avión.
Cumpleaños. Peso con barra. Números de teléfonos móviles. Potencia del horno microondas.
Marcar las variables HeadFirst: Ya veo lo que quieres decir. Entonces, ¿cómo te permite la encapsulación establecer límites?
de instancia como privadas.
Objeto: obligando a otro código a pasar por métodos de establecimiento. De esa manera, el método de
establecimiento puede validar el parámetro y decidir si es factible. Tal vez el método lo rechace y no haga
nada, o tal vez arroje una excepción (como si fuera un número de seguro social nulo para una solicitud
Marcar captadores y de tarjeta de crédito), o tal vez el método redondeará el parámetro enviado al valor aceptable más

definidores públicos. cercano. El punto es que puedes hacer lo que quieras en el método de establecimiento, mientras que no
puedes hacer nada si tus variables de instancia son públicas.

HeadFirst: Pero a veces veo métodos de establecimiento que simplemente establecen el valor sin verificar
nada. Si tiene una variable de instancia que no tiene un límite, ¿ese método de establecimiento no crea
una sobrecarga innecesaria? ¿Un éxito en el rendimiento?
"Lamentablemente, Bill se
olvidó de resumir su clase de Gato Objeto: El objetivo de los establecedores (y también de los captadores) es que puedes cambiar de opinión
y terminó con un gato plano". más tarde, ¡sin romper el código de nadie más! Imagínese si la mitad de las personas de su empresa

(escuchado en el enfriador de agua). usaran su clase con variables de instancia públicas y un día de repente se diera cuenta: "Ups, hay algo
que no planeé con ese valor, voy a tener que cambiar a una método de establecimiento ". Rompes el código
de todos. Lo bueno de la encapsulación es que puedes cambiar de opinión. Y nadie sale herido. La ganancia
de rendimiento derivada del uso directo de variables es minúscula y rara vez (o nunca) valdría la pena.

usted está aquí 81


Machine Translated by Google

cómo se comportan los objetos

clase BuenPerro {
Encapsulando el
Buen perro
Clase GoodDog tamaño int privado;
tamaño

Haga que la variable de instancia sea privada.

público int getSize() {

tamaño de retorno; obtenerTamaño( )

} establecerTamaño( )

ladrar( )

Haga públicos los conjunto vacío público (int s) {


métodos getter y setter. tamaño = s;

corteza vacía() {

si (talla > 60) {


Aunque los métodos realmente no
[Link](“¡Guau! ¡Guau!”);
agregan nuevas funciones, lo bueno es
} si no (talla > 14) {
que puedes cambiar de opinión
más tarde. puedes regresar y crear un [Link](“¡Ruff! ¡Ruff!”);
mejor .
método más seguro, más rápido,
} demás {

[Link](“¡Ay! ¡Ay!”);

}
Cualquier lugar donde se
pueda utilizar un valor particular,
clase GoodDogTestDrive {
un llamada al
método que devuelve ese tipo
público estático vacío principal (String[] args) {
poder ser usado. BuenPerro uno = nuevo BuenPerro();

[Link](70);

BuenPerro dos = nuevo BuenPerro();


en lugar de:
[Link](8);
entero x = 3 + 24; “
[Link](“Perro uno: + [Link]());

puedes decir: [Link](“Perro dos: + [Link]());

int x = 3 + [Link](); [Link]();

[Link]();

82 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

¿Cómo se comportan los objetos en


una matriz?

1 Declare y cree una matriz Dog para


contener 7 referencias Dog.

Perro[] mascotas;
mascotas = nuevo Perro[7];

Perro Perro Perro Perro Perro Perro Perro

mascotas

Objeto de matriz de perros (Perro [])


Perro[]

2 Cree dos nuevos objetos Dog y


asígnelos a los dos primeros oh bj mi oh bj mi
Ct
Doh Ct
gramo

Doh
gramo

elementos de la matriz. 30
8
mascotas[0] = nuevo Perro();
mascotas[1] = nuevo Perro(); tamaño
tamaño

3 Llame a métodos en los dos objetos


Dog.

mascotas[0].setSize(30);
int x = mascotas[0].getSize();
mascotas[1].setSize(8);

Perro perro Perro Perro Perro Perro Perro

mascotas

Objeto de matriz de perros (Perro [])


Perro[]

usted está aquí 83


Machine Translated by Google

inicializando variables de instancia

Declarar e inicializar
variables de instancia
Las variables de instancia
siempre obtienen
tamaño entero; un valor predeterminado.
Nombre de cadena;
Si no asigna explícitamente
un valor a una variable
de instancia, o no
tamaño entero = 420;
Nombre de cadena = "Donny"; llama a un método de
establecimiento, la variable
de instancia

todavía tiene un valor!


clase perro pobre { declarar dos variables de instancia,
pero no asignar un valor números enteros 0
tamaño int privado; nombre
de cadena privada; puntos flotantes 0.0

¿Qué devolverán estos? booleanos FALSO


público int getSize() {
tamaño de retorno;
referencias nulo

} cadena pública getName() {


nombre de retorno;
}

clase pública PoorDogTestDrive { ¿Qué opinas? ¿Se


público estático vacío principal (String[] args) { compilará esto siquiera?
PobrePerro uno = nuevo PobrePerro();
[Link](“El tamaño del perro es “ + [Link]());
[Link](“El nombre del perro es “ + [Link]());
}
}
No es necesario inicializar las variables de instancia, porque
Ventana de edición de archivos Ayuda CallVet siempre tienen un valor predeterminado. Las primitivas numéricas

% java PoorDogTestDrive (incluido el carácter) obtienen 0, los booleanos se vuelven falsos y


las variables de referencia de objetos se vuelven nulas.
El tamaño del perro es 0.
(Recuerde, nulo solo significa un control remoto que no controla ni
programa nada. Una referencia, pero no un objeto real.
El nombre del perro es nulo.

84 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

La diferencia entre variables de


instancia y locales.

1 Las variables de instancia se declaran


¡Las variables locales NO
dentro de una clase pero no dentro de un método.

clase caballo { obtienen un valor


doble altura privada = 15,2; predeterminado! El compilador
raza de cuerda privada ;
// más código... se queja si intenta utilizar
} una variable local antes de
que se inicialice la
variable.
2 Las variables locales se declaran dentro de un método.

clase Agregar cosa {


ent a;
int b = 12;
no existen
Preguntas tontas
público int agregar() {
entero total = a + b;
total de retorno;
}
}

3 ¡ Las variables locales DEBEN inicializarse antes de su uso!

clase Foo {
¡¡No se compilará!!
vacío público ir () {
Puedes declarar x sin un
intx ;
valor, pero tan pronto
int z = x + 3; como intentas USArlo, el
} compilador se asusta.
}

Ayuda de la ventana de edición de archivos

% javac [Link]

[Link]: es posible que la variable x no se haya


inicializado

int z = x + 3;
1 error ^

usted está aquí 85


Machine Translated by Google

igualdad de objetos

Comparar variables (primitivas o referencias)

Utilice == para comparar dos


primitivas o para ver si
dos referencias se
refieren al objeto.
mismo

Utilice el método equals()


para ver si dos objetos
son diferente
iguales.
(Como dos diferentes
Objetos de cadena que
representan los personajes
de “Fred”)
Para comparar dos primitivas, use el operador ==

los patrones de bits son los


lo mismo, entonces

estos dos son


igual usando ==

00000011 00000011
int a = 3; (hay más ceros en el
lado izquierdo del int,
byte b = 3; pero no nos importa a == segundo

si (a == b) { // verdadero } eso aquí) En t byte

Para ver si dos referencias son iguales (lo que significa que se refieren al mismo objeto
en el montón), use el operador ==

mismo
los patrones de bits son para

igualesausando
y c, por lo==
que son

Foo a = nuevo Foo();


Foo b = nuevo Foo();
a
Foo c = a;
si (a == b) { // falso } foo
a == c es cierto b
si (a == c) { // verdadero } C
a == b es falso foo
si (b == c) { // falso }
foo

86 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

Siempre
mantengo mis variables
privadas. Si quieres verlos,
tienes que hablar con mis
métodos.

hazlo pegado
privado

Afila tu lápiz
int a = áreacalc(7, 12);
¿Qué es legal? corta c = 7;
Dado el método siguiente, ¿cuáles de
las llamadas a métodos enumeradas a la calcÁrea(c,15);

derecha son legales? int d = áreacalc(57);


Marque las casillas que sean
áreacalc(2,3);
legales. (Algunas declaraciones
están ahí para asignar valores t larga = 42;
utilizados en las llamadas a métodos).
int f = áreacalc(t,17);

int g = áreacalc();

int calcArea(int alto, int ancho) {


áreacalc();

retorno altura * ancho;


byte h = calcArea(4,20);
}
int j = áreacalc(2,3,5);

usted está aquí 87


Machine Translated by Google

ejercicio: Sea el compilador

Cada uno de los archivos Java en esta


página representa un archivo fuente completo.
Su trabajo es jugar al compilador y
determinar si cada uno de estos archivos se
compilará. Si no se compilan,
¿cómo los solucionaría y, si
lo hacen, cuál sería su
resultado?

A B

clase XCopiar { reloj de clase {


tiempo de cadena;
público estático vacío principal (String [] argumentos) {

void setTime(String t) {
origen int = 42;
tiempo = t;

XCopy x = nueva XCopy(); }

int y = [Link](origen); void getTime()


{ tiempo de retorno;
““
[Link](orig + +y);
}
}
}

int ir(int arg) {


clase Unidad de prueba del reloj {
argumento = argumento * 2; público estático vacío principal (String [] argumentos) {

devolver argumento;
Reloj c = nuevo Reloj();
}
}
[Link](“1245”);
Cadena tod = [Link]();
[Link](“hora: “ + tod);
}
}

88 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

¿Quién soy?

Una clase puede tener cualquier número de estos.

Un método sólo puede tener uno de estos.

Esto puede promoverse implícitamente.

Prefiero que mis variables de instancia sean privadas.

Realmente significa "hacer una copia".

Sólo los configuradores deben actualizarlos.

Un método puede tener muchos de estos.

Devuelvo algo por definición.

No debería ser utilizado con variables de instancia.

Puedo tener muchos argumentos.

Por definición, tomo un argumento.

Estos ayudan a crear encapsulación.

Siempre vuelo solo.

usted está aquí 89


Machine Translated by Google

rompecabezas: mensajes contradictorios

clase pública Mix4 {


contador int = 0;
público estático vacío principal (String [] argumentos) {
recuento int = 0;
Mix4 [] m4a =nuevo Mix4[20]; int x = 0;

mientras ( ) {

m4a[x] = nuevo Mix4();


m4a[x].contador = m4a[x].contador + 1;
contar = contar + 1;
contar = contar + m4a[x].maybeNew(x);
x = x + 1;
}
““
[Link](cuenta +
+ m4a[1].contador);
}

x<9 14 7 público int tal vezNuevo(índice int) {

índice < 5 si ( ) {
95
Mezcla4 m4 = nueva Mezcla4();
[Link] = [Link] + 1;
x<20 19 1
devolver 1;
índice < 5
14 1
} devolver 0;
}
x<7 25 1
}

índice < 7 77

x<19 20 1

índice < 1 20 5

90 capitulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

clase pública Puzzle4 { principal


vacío estático público (String [] args) {
___________________________________
int y = 1; int x
Rompecabezas de piscina
= 0; resultado
entero = 0; mientras (x
< 6) {

___________________________

___________________________
y=y * 10;

_________________

} x = 6;
mientras (x > 0) {
_________________
resultado = resultado + ___________________
}
Ventana de edición de archivos Ayuda BellyFlop [Link](“resultado” + resultado);
}
%java rompecabezas4
}
resultado 543345
clase ___________ {
int ívar;

________ ______ hacer cosas(int _________) {


si (ivar > 100) {
devolver __________________________
} demás {
devolver __________________________
}
}
}

usted está aquí 91


Machine Translated by Google

rompecabezas: Misterio de cinco minutos

Tiempos rápidos en Stim­City

Cuando Buchanan clavó su arma de contracción en el costado de Jai, Jai se quedó helado. Jai sabía que
Buchanan era tan estúpido como feo y no quería asustar al grandullón. Buchanan ordenó a Jai que fuera a la oficina
de su jefe, pero Jai no había hecho nada malo (últimamente), por lo que pensó que una pequeña charla con el
jefe de Buchanan, Leveler, no podía ser tan mala. Últimamente había estado moviendo muchos estimuladores
neuronales en el lado oeste y supuso que Leveler estaría contento. Los estimuladores del mercado negro no eran la
mejor bomba de dinero que existía, pero eran bastante inofensivos. La mayoría de los adictos a los estimulantes
que había visto dejaron de funcionar después de un tiempo y volvieron a la vida, tal vez un poco menos concentrados que antes.

Cinco minutos La 'oficina' de Leveler era un skimmer de aspecto asqueroso, pero una vez que Buchanan lo empujó, Jai pudo
ver que había sido modificada para proporcionar toda la velocidad y armadura extra que un jefe local como Leveler
Misterio podía esperar. “Jai, muchacho”, siseó Leveler, “un placer verte de nuevo”. "Del mismo modo, estoy seguro...", dijo Jai,
sintiendo la malicia detrás del saludo de Leveler, "Deberíamos ser honestos, Leveler, ¿me he perdido algo?"
"¡Ja! Lo estás haciendo lucir bastante bien Jai, tu volumen está alto, pero he estado experimentando, digamos, una
pequeña 'brecha' últimamente…” dijo Leveler.

Jai hizo una mueca de dolor involuntariamente, había sido un pirata informático de primer nivel en su época. cada vez que alguien
Cuando descubrió cómo romper la seguridad de un guardia callejero, la atención no deseada se volvió hacia Jai.
“De ninguna manera soy yo”, dijo Jai, “no vale la pena el inconveniente. Estoy retirado del hacking, solo me muevo
mis cosas y ocuparme de mis propios asuntos”. "Sí, sí", se rió Leveler, "Estoy seguro de que estás limpio en
este caso, ¡pero perderé grandes márgenes hasta que excluyan a este nuevo pirata informático!"
"Bueno, mucha suerte, Nivelador, tal vez podrías dejarme aquí e iré a mover algunas 'unidades' más
para ti antes de terminar hoy", dijo Jai.

"Me temo que no es tan fácil Jai, aquí Buchanan me dice que estás al día en J37NE", insinuó
Leveler. “¿Edición neuronal? Seguro que juego un poco, ¿y qué?”, respondió Jai sintiéndose un poco
mareado. "La edición neuronal es la forma en que les hago saber a los adictos a los estímulos dónde estará la
próxima gota", explicó Leveler. El problema es que algunos adictos a los estimulantes se mantuvieron el tiempo
suficiente como para descubrir cómo hackear mi base de datos de WareHousing. “Necesito que un pensador
rápido como tú, Jai, eche un vistazo a mi clase de StimDrop J37NE; métodos, variables de instancia, toda la
enchilada, y descubrir cómo entran. Debería…”, “¡HEY!”, exclamó Buchanan, “¡No quiero que ningún hacker
escoria como Jai husmee en mi código! " “Tranquilo, grandullón”, Jai vio su oportunidad, “Estoy seguro de que
hiciste un trabajo de primer nivel con tu modo de acceso... “¡No me digas, un poco tonto!”, gritó Buchanan, “Dejé a
todos esos drogadictos. Los métodos de nivel son públicos, para que puedan acceder a los datos del sitio de
entrega, pero marqué todos los métodos críticos de WareHousing como privados. ¡Nadie en el exterior puede
acceder a esos métodos amigo, nadie!

"Creo que puedo detectar tu fuga, Nivelador, ¿qué tal si dejamos a Buchanan aquí en la esquina y damos
una vuelta alrededor de la cuadra?", sugirió Jai. Buchanan tomó su pistola de contracción pero el aturdidor de
Leveler ya estaba en el cuello de Buchanan, "Déjalo Buchanan", se burló Leveler, "Suelta el twitcher y sal afuera,
creo que Jai y yo tenemos algunos planes que hacer".

¿Qué sospechaba Jai?

¿Saldrá del skimmer de Leveler con todos sus huesos intactos?

92 capítulo 4
Machine Translated by Google

Los métodos utilizan variables de instancia.

reloj de clase {
Soluciones de ejercicio
tiempo de
cadena; void setTime(String t)
{ tiempo = t;
B }
String getTime() { tiempo
de retorno;
}
}

clase Unidad de prueba del reloj {

público estático vacío principal (String [] argumentos) {


Reloj c = nuevo Reloj();
[Link](“1245”);
Cadena tod = [Link]();
[Link](“hora: “ + tod);
}
} Nota: Los métodos 'Getter' tienen un tipo de

¡Una clase 'XCopy' se compila y ejecuta tal como está! El retorno por definición.
resultado es: '42 84'. Recuerde que Java se pasa por valor (lo
que significa pasar por copia), la variable 'orig' no se cambia
con el método go().

Una clase puede tener cualquier número de estos. variables de instancia, getter, setter, método
Un método sólo puede tener uno de estos. devolver

Esto puede promoverse implícitamente. retorno, argumento


Prefiero que mis variables de instancia sean privadas. paso de
Realmente significa "hacer una copia". encapsulación por valor
Sólo los configuradores deben actualizarlos. variables de instancia

Un método puede tener muchos de estos. argumento


Devuelvo algo por definición. adquiridor
No debería ser usado con variables de instancia.
público
Puedo tener muchos argumentos. método

Por definición, tomo un argumento. setter

Estos ayudan a crear encapsulación. captador, definidor, público, privado


Siempre vuelo solo. devolver

usted está aquí 93


Machine Translated by Google

respuestas del rompecabezas

Soluciones de rompecabezas

Respuesta al misterio de 5 minutos...

clase pública Puzzle4 { principal vacío


Jai sabía que Buchanan no era el lápiz más afilado
estático público (String [] args) { de la caja. Cuando Jai escuchó a Buchanan hablar
Puzzle4b [ ] obs = nuevo Puzzle4b[6]; sobre su código, Buchanan nunca mencionó sus variables
int y = 1; int x = de instancia. Jai sospechaba que, si bien
0; resultado Buchanan manejaba sus métodos correctamente, no
entero = 0;
marcaba sus variables de instancia como privadas. Ese
mientras (x < 6) { obs[x] =
error fácilmente podría haberle costado miles a Leveler.
nuevo Puzzle4b( ); obs[x] . ivar =

y=y * 10; x
= x + 1;

} x = 6;
mientras (x > 0) { x = x ­ 1;

resultado = resultado + obs[x].doStuff(x);


}
[Link](“resultado” + resultado); x<9 14 7
}
}
índice < 5
clase Puzzle4b { int ivar;
95
público int

hacer cosas (factor int) { x<20 19 1


if (ivar > 100) { return ivar *
factor; índice < 5
14 1
} demás {
devolver ivar * (5 ­ factor);
} x<7 25 1
} Ventana de edición de archivos Ayuda BellyFlop

} %java rompecabezas4 índice < 7 77


resultado 543345

x<19 20 1

índice < 1 20 5

94 capítulo 4
Machine Translated by Google

5 escribiendo un programa

Métodos extrafuertes
Puedo
levantar objetos pesados.

Pongamos algo de fuerza en nuestros métodos.

este es un nuevo capitulo 95


Machine Translated by Google

construyendo un juego real

Construyamos un juego estilo


Battleship: "Sink a Dot Com"

Vas a construir el juego Sink a Dot


Com, con una cuadrícula de 7 x 7 y tres
Dot Com. Cada Punto Com ocupa
tres celdas.

parte de una interacción de juego

Ventana de edición de archivos Ayuda a vender

%java DotComBust

Ingrese una suposición A3

extrañar

Ingrese una suposición B2

extrañar

Introduzca una suposición C4

extrañar

Introduzca una suposición D2

golpear
cada caja
Cuadrícula de 7 X 7 es una “celda” Ingrese una suposición D3

golpear

Introduzca una suposición D4

¡Ay! Has hundido [Link]: (

matar

Ingrese una suposición B4

extrañar

Ingrese una suposición G3

golpear

Ingrese una suposición G4

golpear

Ingrese una suposición G5

¡Ay! Has hundido [Link] : (


comienza en cero, como las matrices de Java
matar
96 capítulo 5 Ingrese una suposición A7

extrañar
Machine Translated by Google

escribiendo un programa

Primero, un diseño de alto nivel.

Un círculo significa
comenzar o terminar.

Comenzar
Se utiliza un
rectángulo para
1
representar una acción.

1 usuario inicia el juego


configuración del juego
AB
A El juego crea tres Dot Coms

B Juego coloca los tres puntos. 2 Obtener usuario

Llega a una red virtual adivinar


A

2 Comienza el juego extrañar


Controlar
golpear
eliminar celda de
ubicación
Repita lo siguiente hasta que no queden más adivinar
Dot Coms: B

A Solicitar al usuario una suposición matar

(“A2”, “C0”, etc.)


eliminar
Punto Com
B Verifique la suposición del usuario con todos los
Dot Coms para buscar aciertos, fallos o
muertes. Tome las medidas adecuadas:
Un diamante
si acierta, elimine la celda (A2, D4, etc.). Si
¿Todavía quedan representa un
mata, elimine Dot Com. Sí
algunos Dot punto de decisión.
Coms vivos?

3 finales del juego No

Otorgue al usuario una calificación basada


3 mostrar puntuación/

calificación del usuario


en la cantidad de conjeturas.

juego
terminado

Vaya. Un diagrama de flujo real.

usted está aquí 97


Machine Translated by Google

una versión más simple del juego

El “juego simple de las punto com”


una introducción más suave El juego comienza, crea ONE DotCom y le
1 asigna una ubicación en tres celdas en una
sola fila de siete celdas.

En lugar de “A2”, “C4”, etc., las ubicaciones


son solo números enteros (por ejemplo: 1,2,3
son las ubicaciones de las celdas en
esta imagen:

Comienza el juego. Solicite al usuario


2 una suposición y luego verifique si llegó
a alguna de las tres celdas del DotCom.
Si es un acierto, incremente la variable
numOfHits.

SimpleDotComJuego 3 El juego termina cuando se han alcanzado las tres


celdas (el valor de la variable numOfHits es
3) y le dice al usuario cuántas conjeturas
SimpleDotCom fueron necesarias para hundir el DotCom.
int [] ubicaciónCeldas
vacío principal
int número de visitas

Una interacción de juego completa.


Ventana de edición de archivos Ayuda Destruir

String checkYourself (Conjetura de cadena)


%java SimpleDotComGame
void setLocationCells(int[] loc)
introduce un numero 2
golpear

introduce un número 3
golpear

introduce un número 4
extrañar

introduce un número 1
matar

Hiciste 4 conjeturas

98 capítulo 5
Machine Translated by Google

escribiendo un programa

Desarrollando una clase Las tres cosas que escribiremos


para cada clase:

preparación del código de prueba del código código real

Clase SimpleDotCom

código
código de preparación
de preparación código de prueba código real

código de preparación
Una forma de pseudocódigo que le ayuda a centrarse en
la lógica sin preocuparse por la sintaxis.

código de prueba
Una clase o métodos que probarán el código real.
y validar que está haciendo lo correcto.

código real
La implementación real de la clase. Aquí es donde escribimos
código Java real.

Hacer:
Clase SimpleDotCom
escribir código de preparación

escribir código de prueba

escribir el código Java final

SimpleDotComJuego
clase
escribir código de preparación

escribir código de prueba [no]

escribir el código Java final

usted está aquí 99


Machine Translated by Google

Clase SimpleDotCom
código de preparación código de preparación código de prueba código real

SimpleDotCom

int [] ubicaciónCeldas
int numOfHits

String checkYourself (Conjetura de cadena)

void setLocationCells(int[] loc)


DECLARAR una matriz int para contener las celdas de ubicación. Llámalo celdas de ubicación.

DECLARAR un int para contener el número de visitas. Llámelo numOfHits y configúrelo en 0.

DECLARAR un método checkYourself() que toma una Cadena para la suposición del usuario (“1”, “3”, etc.), la verifica y devuelve un resultado

que representa un “acierto”, un “fallo” o una “muerte”.

DECLARAR un método de establecimiento setLocationCells() que toma una matriz int (que tiene las tres ubicaciones de celda como ints (2,3,4, etc.).

MÉTODO: String checkYourself(String userGuess)

OBTÉN la suposición del usuario como un parámetro de cadena

CONVERTIR la suposición del usuario a un int

REPETIR con cada una de las celdas de ubicación en la matriz int

// COMPARA la suposición del usuario con la celda de ubicación

SI la conjetura del usuario coincide

AUMENTAR el número de visitas

// DESCUBRE si fue la última celda de ubicación:

SI el número de golpes es 3, REGRESA “matar” como resultado

DE LO CONTRARIO , no fue una muerte, así que REGRESAR “golpear”

TERMINARA SI

DE LO CONTRARIO, la suposición del usuario no coincidió, por lo que REGRESAR “falla”

TERMINARA SI

FINALIZAR REPETIR

MÉTODO FINAL

MÉTODO: void setLocationCells(int[] cellLocations)

OBTENER las ubicaciones de las celdas como un parámetro de matriz int

ASIGNAR el parámetro de ubicaciones de celdas a la variable de instancia de ubicaciones de celdas

MÉTODO FINAL

100 capitulo 5
Machine Translated by Google

escribiendo un programa
código de preparación código de prueba código de prueba código real

Escribir las
implementaciones del método.
¡Oh mi! Por un momento
escribamos el código pensé que no ibas a
escribir tu código de prueba
del método real ahora y hagamos
primero. ¡Vaya!
que este cachorro funcione. No me asustes así.

Programación extrema (XP)

usted está aquí 101


Machine Translated by Google

Clase SimpleDotCom

código de preparación código de prueba código de prueba código real

Escribir código de prueba para la clase SimpleDotCom

Basado en este código previo: Esto es lo que debemos probar:

MÉTODO String checkYourself(String userGuess) 1. Cree una instancia de un objeto SimpleDotCom.

OBTÉN la suposición del usuario como un parámetro de cadena 2. Asígnale una ubicación (una matriz de 3 entradas, como {2,3,4}).

CONVERTIR la suposición del usuario a un int

3. Cree una cadena para representar una suposición del usuario (“2”, “0”, etc.).
REPETIR con cada una de las celdas de ubicación en la matriz int

// COMPARA la suposición del usuario con la celda de ubicación


4. Invoque el método checkYourself() pasándole la suposición del usuario falso.
SI la conjetura del usuario coincide

INCREMENTAR el número de visitas 5. Imprime el resultado para ver si es correcto.

// DESCUBRE si fue la última celda de ubicación: (“aprobado” o “reprobado”).

SI el número de golpes es 3, REGRESA “Matar” como resultado

DE LO CONTRARIO , no fue una muerte, así que REGRESAR“Golpear”

TERMINARA SI

DE LO CONTRARIO, la suposición del usuario no coincidió, así que REGRESE “Señorita”

TERMINARA SI

FINALIZAR REPETIR

MÉTODO FINAL

102 capítulo 5
Machine Translated by Google

escribiendo un programa

código de preparación código de prueba código de prueba código real

Código de prueba para la clase SimpleDotCom


no existen
Preguntas tontas
clase pública SimpleDotComTestDrive {
crear una instancia de SimpleDotCom

público estático vacío principal (String[] args) { objeto

Punto SimpleDotCom = nuevo SimpleDotCom();

haga una matriz int


para la ubicación del
punto com (3 enteros
int[] ubicaciones = {2,3,4}; consecutivos de 7 posibles).

[Link](ubicaciones);
invocar el método
setter en
el punto com.
hacer que un
Cadena usuarioGuess = “2”;
usuario falso adivine

Resultado de cadena = [Link](userGuess);

Resultado de la prueba de cadena = "fallido"; invocar el checkYourself()


método en
el objeto
punto com y pasarle la
si ([Link] ("golpe")) { suposición falsa.

resultadodeprueba = “aprobado”;
si la suposición falsa (2) devuelve
un "acierto", está funcionando
}

[Link](resultadodeprueba);
imprimir el resultado de la prueba
(aprobado o reprobado”)
}

Afila tu lápiz

usted está aquí 103


Machine Translated by Google

Clase SimpleDotCom
código de preparación código de prueba código real código real

El método checkYourself()

cadena pública checkYourself(String stringGuess) {


OBTENER el usuario

adivinar 1
int adivinar = [Link](stringGuess); convertir la cadena a un
CONVERTIR int
el usuario adivina un int
Resultado de cadena = “fallo”;
cree una variable para contener el resultado que
devolveremos. ponga "fallo" como valor
predeterminado (es decir, asumimos un "fallo")

REPETIR con cada


2
celda del int
para (int celda: ubicaciónCells) {
formación
formación
repita con cada celda en la ubicaciónCells

SI la conjetura del usuario


si (adivina == celda) { (la ubicación de cada celda del objeto)
coincide
comparar el elemento a esto
resultado = “golpe”;
adivinado por el usuario (celda) en la matriz
INCREMENTO 3 ¡Tenemos un éxito!
el número de visitas número de visitas++;

4
romper;
salga del circuito, no es
necesario probar las otras celdas
} // terminara si

} // fin para
// DESCUBRE si fue la
última celda
if (numOfHits == ubicació[Link]) {
SI el número de visitas

es 3,
estamos fuera del circuito, pero veamos si estamos
resultado = “matar”; ahora
REGRESAR “matar” 'muerto' (golpeado 3 veces) y cambia la
como resultado
cadena de resultados a "Matar"
} // terminara si
DE LO CONTRARIO, no

fue una muerte, así que

VOLVER“golpear”
[Link](resultado); mostrar el resultado al usuario

DEMÁS (“Señorita”, a menos que se haya cambiado a “Golpear” o “Matar”)


resultado de devolución;
REGRESAR
“señorita” devolver el resultado al método de
} // método final llamada

104 capítulo 5
Machine Translated by Google

escribiendo un programa

código de preparación código de prueba código real código real

Solo las cosas nuevas

Un método de la
clase Integer que
sabe cómo "analizar"
Una clase
una cadena en el int
que viene con Java. Toma una cuerda.
que representa.

1 Convertir un
1
Cadena a un int [Link](“3”)

Lea esta declaración de bucle for como


"repetir para cada elemento de la matriz
el
Los dos puntos (:) significan “en”,
por lo que todo significa
'locationCells': tome el siguiente elemento valor EN
“para cada int
de la matriz y asígnelo a la variable int 'celda'". celdas de ubicación...”

2
2 El para bucle
para (int celda: ubicaciónCells) { }

Declare una variable que contendrá un elemento La matriz sobre la que se va a iterar en el bucle.
de la matriz. Cada vez que se realiza el ciclo, Cada vez que se realice el ciclo, el siguiente
esta variable (en este caso una variable int elemento de la matriz se asignará a la variable
llamada “celda”) contendrá un elemento diferente "celda". (Más sobre esto en el
final de este capítulo.)
de la matriz, hasta que no haya más elementos (o
el código haga una “ruptura”... ver # 4 abajo).

++ significa agregar 1 a
lo que haya allí (en otras
3 El operador post­
palabras, incrementar en 1).
incremento
número de visitas++
numOfHits++ es lo mismo (en
este caso) que decir numOfHits =
numOfHits + 1, excepto que es
un poco más eficiente.

4
4 declaración de ruptura
romper;
Te saca de un bucle. Inmediatamente. Aquí mismo.
Sin iteraciones, sin pruebas booleanas, ¡sal ahora!

usted está aquí 105


Machine Translated by Google

Clase SimpleDotCom
código de preparación código de prueba código real código real

Código final para SimpleDotCom y SimpleDotComTester


no existen
Preguntas tontas
clase pública SimpleDotComTestDrive {

público estático vacío principal (String[] args) {

Punto SimpleDotCom = nuevo SimpleDotCom();

int[] ubicaciones = {2,3,4};

[Link](ubicaciones);

Cadena usuarioGuess = “2”;

Resultado de cadena = [Link](userGuess);

clase pública SimpleDotCom {

int[] ubicaciónCeldas;
int número de visitas = 0;

setLocationCells vacío público (int [] locomotoras) {


ubicaciónCells = locs;
}

cadena pública checkYourself(String stringGuess) {


int adivinar = [Link](stringGuess);
Resultado de cadena = “fallo”;
para (int celda: ubicaciónCells) {
si (adivina == celda) {
resultado = “golpe”;
número de visitas++;
romper;
}
} // fuera de la lupa

si (númDeAccesos ==
ubicació[Link]) {
resultado = “matar”;
}
[Link](resultado);
resultado de devolución;
} // cerrar método } // cerrar
clase

Java SimpleDotComTestDrive
Hay un pequeño error acechando aquí. Se compila y se golpear

ejecuta, pero a veces... no te preocupes por eso por ahora, pero


tendremos que afrontarlo un poco más tarde.

106 capítulo 5
Machine Translated by Google

escribiendo un programa

código de preparación código de preparación código de prueba código real

Afila tu lápiz

MÉTODO público estático vacío principal (String [] args)

DECLARAR una variable int para contener el número de conjeturas del usuario, denominada numOfGuesses

CALCULE un número aleatorio entre 0 y 4 que será la posición inicial de la celda

Una interacción de juego completa.


Ventana de edición de archivos Ayuda Runaway

%java SimpleDotComGame
MIENTRAS las punto com todavía están vivas:
introduce un numero 2
OBTENER información del usuario desde la línea de comando
golpear

introduce un número 3
golpear

introduce un número 4
extrañar

introduce un número 1
matar

Hiciste 4 conjeturas

usted está aquí 107


Machine Translated by Google

Clase SimpleDotCom
código de preparación código de preparación código de prueba código real

Código de preparación para la clase SimpleDotComGame

Todo sucede en principal()

principal público estático vacío (String [] args)

DECLARE una variable int para contener el número de conjeturas del usuario, denominada numOfGuesses, configúrala en 0.

HACER una nueva instancia de SimpleDotCom

CALCULE un número aleatorio entre 0 y 4 que será la posición inicial de la celda

HAGA una matriz int con 3 ints usando el número generado aleatoriamente, ese número incrementado en 1 y ese número incrementado en 2 (ejemplo: 3,4,5)

INVOCAR el método setLocationCells() en la instancia de SimpleDotCom

DECLARAR una variable booleana que representa el estado del juego, denominada isAlive. Póngalo en verdadero

MIENTRAS el punto com todavía está vivo (isAlive == true):

OBTENER información del usuario desde la línea de comando

// COMPROBAR la suposición del usuario

INVOCAR el método checkYourself() en la instancia de SimpleDotCom

INCREMENT numOfGuesses variable

// VERIFICAR si hay muerte de punto com

SI el resultado es "matar"

SET isAlive a falso (lo que significa que no volveremos a ingresar al bucle)

IMPRIMIR el número de conjeturas del usuario

TERMINARA SI

TERMINAR MIENTRAS

MÉTODO FINAL No trabajes una parte del cerebro durante demasiado tiempo a la vez.
Trabajar sólo el lado izquierdo del cerebro durante más de 30 minutos es como
trabajar sólo el brazo izquierdo durante 30 minutos. Dale un descanso a cada
lado de tu cerebro cambiando de lado a intervalos regulares.
Cuando te mueves hacia un lado, el otro lado descansa y
recuperar. Las actividades del cerebro izquierdo incluyen cosas como
secuencias paso a paso, resolución de problemas lógicos y análisis, mientras
que el cerebro derecho se activa para metáforas, resolución creativa de
problemas, coincidencia de patrones y visualización.

108 capítulo 5
Machine Translated by Google

escribiendo un programa

PUNTOS DE VIÑETA

Su programa Java debería comenzar con un diseño de Elija bucles for en lugar de bucles while cuando sepa cuántas

alto nivel. veces desea repetir el código del bucle.

Normalmente escribirás tres cosas cuando crees una


nueva clase: Utilice el operador de incremento previo/posterior para

agregar 1 a una variable (x++;)


código de preparación

código de prueba Utilice el decremento previo/posterior para restar 1 de una

variable (x­­;)
código real (Java)
Utilice [Link]() para obtener el valor int de una
El código previo debe describir qué hacer, no cómo
cadena.
para hacerlo. La implementación viene más tarde.
[Link]() funciona solo si la cadena representa un
Utilice el código de preparación para ayudar a diseñar el código
dígito (“0”, “1”, “2”, etc.)
de prueba.

Utilice break para salir de un bucle antes de tiempo (es decir, incluso
Escriba el código de prueba antes de implementar los
si la condición de prueba booleana sigue siendo verdadera).
métodos.

¿Cuántas
visitas recibiste el mes
pasado? ¿Incluidos
los visitantes habituales? 3

Sí...

Hola desde el pueblo fantasma

usted está aquí 109


Machine Translated by Google

Clase SimpleDotComGame
código de preparación código de prueba código real código real

El método main() del juego.

público estático vacío principal (String [] argumentos) { crear una variable para rastrear
cuántas conjeturas hace el usuario
DECLARAR una variable int númeroDeGuesses = 0;
capaz de retener al usuario

conteo de conjeturas, Ayudante de GameHelper = nuevo GameHelper(); Esta es una clase especial que escribimos y que
configúrelo en 0
tiene el método para obtener la entrada del
usuario. Por ahora, finge que es parte de Java.

HACER un SimpleDot
SimpleDotCom theDotCom = nuevo SimpleDotCom(); hacer que el punto com sea un objeto
Objeto común
1
CALCULAR un int númeroaleatorio = (int) ([Link]() * 5); cree un número aleatorio para la primera
número aleatorio celda y utilícelo para crear la matriz de
entre 0 y 4
ubicaciones de celdas
HAGA una matriz int con
las ubicaciones de las 3 int[] ubicaciones = {NumAleatorio, NumAleatorio+1, NumAleatorio+2};
celdas y
[Link](ubicaciones); dale al punto com sus ubicaciones (la matriz)
INVOCAR setLoca­
tionCells en el punto
booleano está vivo = verdadero;
objeto com
cree una variable booleana para rastrear si el juego todavía
DECLARAR un bool­ean
está activo, para usarla en la prueba del bucle while. repita
isAlive
mientras el juego aún esté vivo.
MIENTRAS el punto mientras (está vivo == verdadero) {
com sigue vivo obtener cadena de entrada del usuario
2
OBTENER entrada del usuario
Conjetura de cadena = [Link] ("ingrese un número");

// Revisalo
Resultado de cadena = [Link](guess);
pídale al punto com que verifique
INVOCAR checkYo­
la suposición;
urself() en punto com númeroDeGuesses++; guardar el resultado
incrementar el conteo de conjeturas
devuelto en una cadena
INCREMENTAR
númeroDeConjeturas si ([Link](“matar”)) {
¿Fue una “muerte”? Si es así, establezca isAlive en falso (para que no volvamos a
SI el resultado es "matar"
está vivo = falso; ingresar al bucle) e imprima el recuento de conjeturas del usuario.
SET gameAlive a falso

[Link](“Tomaste” + númeroDeConjeturas + " suposiciones");


IMPRIMIR el número de

conjeturas del usuario } // cerrar si

} // cerrar mientras

} // cerrar principal

110 capitulo 5
Machine Translated by Google

escribiendo un programa

código de preparación código de prueba código real código real

aleatorio() y getUserInput()

Esto es un 'cast', y obliga a la cosa


inmediatamente después a El método [Link]
convertirse en el tipo del cast (es decir, devuelve un número de cero a
el tipo en los parens). [Link] poco menos de uno. Entonces, esta
devuelve un doble, por lo que tenemos fórmula (con la conversión) devuelve
que convertirlo en un int (queremos un número del 0 al 4 (es decir, 0 ­
un buen número entero entre 0 y 4). En 4,999..., convertido a un int).
este caso, el yeso corta la parte fraccionaria del doble.
2 Haz un 1 al azar
número

int número aleatorio = (int) ([Link]() * 5)

Declaramos una variable int para contener el


Una clase que viene con Un método de la clase
número aleatorio que obtenemos. Java. de Matemáticas.

Este argumento
del método
toma una cadena
el usuario que utiliza.
para solicitar
en la línea de comando.
Una instancia que creamos
anteriormente, de una clase Cualquier cosa que pases aquí se
se muestra en la terminal justo antes
que creamos para ayudar con el de que el método comience a
Obtener información del
1
2 juego. Se llama GameHelper y buscar la entrada del usuario.
usuario usando la clase
aún no lo has visto (lo verás).
GameHelper

Conjetura de cadena = [Link] ("ingrese un número");

Un método de la clase GameHelper para


Declaramos una variable de cadena para
solicita la entrada de comando, que
contener la cadena de entrada del
usuario que obtenemos (“3”, “5”, etc.). la línea del usuario, la lee después de
que el usuario presiona RETURN y
devuelve el resultado como una cadena.

usted está aquí 111


Machine Translated by Google

Clase GameHelper (Listo para hornear)

código de preparación código de prueba código real código real

Una última clase: GameHelper

Preparé un
código para que no
tengas que hacerlo tú
mismo.

importar [Link].*;
clase pública GameHelper {
cadena pública getUserInput (solicitud de cadena) {
Cadena inputLine = nulo;
[Link](mensaje + “ “);
intentar {

BufferedReader es = nuevo BufferedReader(


nuevo InputStreamReader([Link]));
inputLine = [Link]();
si ([Link]() == 0) devuelve nulo;
} captura (IOException e) {
[Link](“IOException: “ + mi);
}
devolver línea de entrada;
}
}

*Sabemos lo mucho que disfrutas escribir, pero para esos


raros momentos en los que prefieres hacer otra cosa, hemos
puesto a disposición el Código Ready­bake en [Link].

112 capítulo 5
Machine Translated by Google

escribiendo un programa

Vamos a jugar ¿Qué es esto? ¡Un bicho ?


suspiro!
Esto es lo que sucede cuando lo Esto es lo que sucede cuando
ejecutamos e ingresamos los
ingresamos 1,1,1.
números 1,2,3,4,5,6. Luce bien.

Una interacción de juego completa. Una interacción de juego diferente

Ventana de edición de archivos Ayuda Sonrisa Ayuda de la ventana de edición de archivos débil

%java SimpleDotComGame %java SimpleDotComGame


introduce un número 1 introduce un número 1

extrañar golpear

introduce un numero 2 introduce un número 1

extrañar golpear

introduce un número 3 introduce un número 1

extrañar matar

introduce un número 4 Hiciste 3 conjeturas


golpear

introduce un número 5

Afila tu lápiz
golpear

introduce un número 6
matar

Hiciste 6 conjeturas

usted está aquí 113


Machine Translated by Google

para bucles

Más sobre bucles for

Bucles for regulares (no mejorados)


el código a
repetir va aquí
operador post­incremento (el cuerpo)

para(int i = 0; i < 100; i++){ } repita durante 100 repeticiones:

inicialización prueba booleana


expresión de iteración

*
*
*

114 capítulo 5
Machine Translated by Google

escribiendo un programa

producción:
Viajes a través de un bucle
Repetir ayuda de la ventana de edición de archivos

para (int i = 0; i < 8; i++) { Prueba %java


[Link](i); 0
} 1
2
[Link](“hecho”);
3
4
declarar i
colocar i int a 0 5
6
7
hecho
es i<8? verdadero

(la prueba booleana) entrar al cuerpo

++­­
del bucle

FALSO

imprimir el valor
de i
imprimir "hecho"
(saltar debajo del bucle)
x++;
incremento i
(la expresión
de iteración)
x = x + 1;

Diferencia entre para y mientras

X­­;

x = x ­ 1;

int yo = 0; tenemos que declarar


e inicializar el contador int x = 0; intz = ++x;
mientras (yo < 8) {

[Link](i);
nosotros
yo ++;
tener que incrementar int x = 0; intz = x++;
el contador
}

[Link](“hecho”);

usted está aquí 115


Machine Translated by Google

mejorado para

El bucle for mejorado

El código a
Declare una variable de El colon (:) repetir va aquí (el
iteración que contendrá un solo medio "EN".
cuerpo).
elemento en la matriz.

para (nombre de cadena: nameArray) { }


Con cada iteración, La colección de elementos sobre los que desea iterar.
Los elementos de la se asignará un
matriz DEBEN Imagínese que en algún lugar antes, el código decía:
elemento
ser compatibles con
diferente de la String[] nameArray = {“Fred”, “Mary”, “Bob”};
matriz a la variable "nombre".
el tipo de variable declarado.
Con la primera iteración, la variable de nombre tiene el valor de
“Fred”, y con la segunda iteración, un valor de “Mary”, etc.

Nota: dependiendo del

* lenguaje de programación que


hayan usado en el pasado, algunas
* personas se refieren al bucle
mejorado como “para cada” o
* “para en”, porque así es como se

* lee: “para CADA cosa EN el


recopilación..."

116 capítulo 5
Machine Translated by Google

escribiendo un programa

Lanzamiento

int adivinar = [Link](stringGuess); de primitivas

largo corto
se puede lanzar a
Se
cortaron trozos
del lado
01011101 izquierdo.
pero podrías 1101
perder algo

operador == no se puede aplicar a int,[Link]


En el capítulo 3 hablamos sobre los tamaños de las distintas primitivas y sobre cómo

si (x == número) { } no se puede meter algo grande directamente en uno

^ pequeño: long y = 42;


int x = y; Un long // no compilará
es mayor que un int y el compilador no puede estar seguro de dónde ha estado ese
tiempo . Podría haber sido salir a beber con los otros anhelos y asumir valores realmente
importantes. Para forzar al compilador a introducir el valor de una variable primitiva más
grande en una más pequeña, puede utilizar el operador de conversión . Se parece a esto:

larga y = 42; // Hasta ahora, todo bien

int x = (int) y; // x = 42 ¡ genial!

Poner el elenco le dice al compilador que tome el valor de y, lo corte a tamaño


int y establezca x igual a lo que quede. Si el valor de y era mayor que el valor
máximo de x, entonces lo que quedará será un número extraño (pero calculable*):

una clase que largo y = 40002;


viene con Java toma una cuerda
// 40002 excede el límite de 16 bits de un corto

corto x = (corto) y; // ¡x ahora es igual a ­25534!

[Link](“3”) Aún así, el punto es que el compilador te permite hacerlo. Y digamos que
tienes un número de coma flotante y solo quieres obtener la parte entera (int) :

flotador f = 3,14f;

un método en la clase intx = (int)f; // x será igual a 3


Integer que sabe cómo Y ni se te ocurra convertir nada en un valor booleano o viceversa,
"analizar" una cadena en simplemente aléjate.
el int que representa.
*Involucra bits de signos, binario, 'complemento a dos' y otras técnicas, todo
lo cual se analiza al comienzo del apéndice B.

usted está aquí 117


Machine Translated by Google

ejercicio: Sea la JVM

El archivo Java en esta página


representa un archivo fuente
completo. ¿Su trabajo es reproducir
JVM y determinar cuál sería el
resultado cuando se
ejecute el programa?

Ayuda de la ventana de edición de archivos OM

% java Salida 12
14
clase Salida {

público estático vacío principal (String [] argumentos) {

Salida o = nueva Salida();

[Link](); ­o­
}
Ventana de edición de archivos Ayuda Incienso

ir vacío() { % java Salida 12


14 x = 6
int y = 7;

para(int x = 1; x < 8; x++) {

y++;

si (x > 4) {

[Link](++y + “ “); ­o­


}
Ventana de edición de archivos Ayuda Suspender
a creer

si (y > 14) {
“ java
% java
TestArrays
Salida %13 15
[Link](“ x = +x);
x = Fiji
Isla 6 isla =
= Isla
romper; Cozumel = Isla
Bermuda = Azores
}

118 capítulo 5
Machine Translated by Google

escribiendo un programa

x++;

si (x == 1) {

““
[Link](x + +y);

clase
MultiFor {

for(int y = 4; y > 2; y­­) {

para(int x = 0; x < 4; x++) {

público

principal vacío estático (cadena


Incursión de ayuda en la ventana de edición de archivos
[] argumentos) {

% java MultiFor
04
03
14
13
34
33

usted está aquí 119


Machine Translated by Google

rompecabezas: JavaCross

JavaCruz

120 capitulo 5
Machine Translated by Google

escribiendo un programa

clase MezclaPara5 {
público estático vacío principal (String [] argumentos) {
int x = 0; int y =
30; for (int externo
= 0; externo < 3; externo++) {
for(int interior = 4; interior > 1; interior­­) {

El código candidato
y = y ­ 2; si (x == va aquí.
6) { romper;

} x = x + 3;

} y = y ­ 2;
}
““
[Link](x + +y);
}
}

x = x + 3; 45 6 Relacionar
cada candidato
x = x + 6; 36 6 con uno de

los posibles resultados.


x = x + 2; 54 6

x++; 60 10

X­­; 18 6

x = x + 0; 6 14

12 14

usted está aquí 121


Machine Translated by Google

soluciones de ejercicio

Sea la JVM: Imanes de código:


clase Salida { clase MultiFor {

público estático vacío principal (String [] argumentos) { público estático vacío principal (String [] argumentos) {

Salida o = nueva Salida();


para(int x = 0; x < 4; x++) {
[Link]();

}
for(int y = 4; y > 2; y­­) {
ir vacío() { [Link](x +
““
+y);
int y = 7; }

para(int x = 1; x < 8; x++) {


if (x == 1) { ¿Qué pasaría si este bloque de código
y++;
x++; viniera antes del bucle for 'y'?
si (x > 4) {
}
[Link](++y + “ “); }
} }

si (y > 14) { }
Ventana de edición de archivos Ayuda Monopole

[Link](“ x = +x);
% java MultiFor 0 4
romper; 03
14
}
13
} 34
33
}

} ¿Recordaste tener en cuenta la declaración


de descanso? ¿Cómo fue eso?

¿Afecta la salida?

Ventana de edición de archivos Ayuda Suspender


Mantenimiento de motocicletas

%
javajava TestArrays
Salida isla = %
Fiji
isla13 15 x = 6
= Isla
Cozumel = Isla
Bermuda = Azores

122 capítulo 5
Machine Translated by Google

escribiendo un programa

IMPLEMENTAR METRO

R PARA mi

EXTREMO PAG

XLSRETURNH
PSEUDOCODEIO R
EROTCASTTD
VARIABLE EICAPIJTSTRAOSELEMENT I
A

IRMARÍ
OAEJAVA. LANGZ
NTNE
IIIINTEGEROPM
OTBOOLEAN
ALEATORIO
SUNPARSEINTH
NBREAKL

x = x + 3; 45 6

x = x + 6; 36 6

x = x + 2; 54 6

x++; 60 10

X­­; 18 6

x = x + 0; 6 14

12 14

usted está aquí 123


Machine Translated by Google
Machine Translated by Google

6 conozca la API de Java

Usando la biblioteca Java


¿Por lo que es cierto?
Puedo
levantar No tenemos
que objetos pesados.
¿Construirlo nosotros mismos?

Java viene con cientos de clases prediseñadas.

este es un nuevo capitulo 125


Machine Translated by Google

todavía tenemos un error

En nuestro último capítulo, los


dejamos con el suspenso. Un insecto.

como se supone que debe verse como se ve el error

Esto es lo que sucede cuando lo Esto es lo que sucede cuando


ejecutamos e ingresamos los ingresamos 2,2,2.
números 1,2,3,4,5,6. Luce bien.

Una interacción de juego completa. Una interacción de juego diferente

Ventana de edición de archivos Ayuda Sonrisa Ayuda de la ventana de edición de archivos débil

%java SimpleDotComGame %java SimpleDotComGame


introduce un número 1 introduce un numero 2
extrañar golpear

introduce un numero 2 introduce un numero 2


extrañar golpear

introduce un número 3 introduce un numero 2


extrañar matar
introduce un número 4 Hiciste 3 conjeturas
golpear

introduce un número 5

golpear
En la versión actual, una vez
introduce un número 6
que recibes un golpe, ¡simplemente
matar puedes repetir ese golpe dos
Hiciste 6 conjeturas veces más para matar!

126 capítulo 6
Machine Translated by Google

Conozca la API de Java

¿Entonces qué pasó?

cadena pública checkYourself(String stringGuess) {

int adivinar = [Link](stringGuess); Convierta la cadena en un


int.

Resultado de cadena = “fallo”; Cree una variable para contener el resultado que

devolveremos. Introduzca "fallo" como valor


predeterminado (es decir, asumimos un "fallo").

para (int celda: ubicaciónCells) { Repita con cada


Aquí es donde elemento de la matriz.
si (adivina == celda) { Compare la suposición
sale mal. Contamos
del usuario con este elemento
un acierto cada vez que resultado = “golpe”;
el usuario adivina (celda) en la matriz.
¡Tenemos un éxito!
la ubicación de número de visitas++;
una celda, ¡incluso
si esa ubicación ya romper;
Salga del circuito, no es
había sido acertada! necesario probar las otras celdas.
} // terminara si

Necesitamos una
forma de saber que } // fin para

cuando un
if (numOfHits == ubicació[Link]) {
usuario acierta, no Estamos fuera del ciclo, pero si lo hacemos
ha acertado previamente vamos a ver ahora (presionamos
resultado = “matar”; 'muerto'
en esa celda. Si es así,
3 veces) y cambiamos la cadena de
entonces no
} // terminara si resultados a "matar".
queremos contarlo como un éxito.

[Link](resultado); Mostrar el resultado para el usuario.

(“fallar”, a menos que se haya cambiado a “golpear” o “matar”).


resultado de devolución;

Devuelve el resultado al método de


} // método final llamada.

usted está aquí 127


Machine Translated by Google

arreglando el error

¿Cómo lo arreglamos?

Necesitamos una forma de saber si una célula ya ha sido atacada. Repasemos algunas
posibilidades, pero primero, veremos lo que sabemos hasta ahora...

Tenemos una fila virtual de 7 celdas y un DotCom ocupará tres celdas consecutivas
en algún lugar de esa fila. Esta fila virtual muestra un DotCom ubicado en las
ubicaciones de las celdas 4, 5 y 6.

La fila virtual, 3
con el
ubicaciones de celdas
para el objeto DotCom.

DotCom tiene una variable de instancia (una matriz int) que contiene las ubicaciones
de las celdas de ese objeto DotCom.

La variable
de instancia de matriz que
locationCells contiene las ubicaciones de las celdas de DotCom.
(variable de instancia de 0 1 2 Este DotCom contiene los 3 valores de 4, 5 y 6.
DotCom) Esos son los números que el usuario debe
adivinar.

1 Opcion uno
Podríamos crear una segunda matriz, y cada vez que el usuario haga un acierto,
almacenaremos ese acierto en la segunda matriz y luego verificaremos esa matriz cada
vez que obtengamos un acierto, para ver si esa celda ha sido acertada antes.

Un 'verdadero' en un índice particular en la matriz significa que


la ubicación
formación de la celda en ese mismo índice en el OTRO
(locationCells) ha sido afectado.

matriz hitCells Esta matriz contiene tres valores que representan


el "estado" de cada celda en la matriz de celdas
(esta sería una 0 1 2 de ubicación de DotCom. Por ejemplo, si se
nueva variable de
instancia de matriz alcanza la celda en el índice 2, establezca el
índice 2 en la matriz "hitCells" en "verdadero".
booleana de DotCom)

128 capítulo 6
Machine Translated by Google

Conozca la API de Java

La opción uno es demasiado torpe


La opción uno parece más trabajo de lo que cabría esperar. Significa que cada vez que el
usuario hace un hit, tienes que cambiar el estado de la matriz (la matriz segundo
'hitCells'), oh, pero primero tienes que COMPROBAR la matriz 'hitCells' para ver si esa celda
ya ha sido golpear de todos modos. Funcionaría, pero tiene que haber algo mejor...

2 Opción dos
Podríamos simplemente mantener la matriz original, pero cambiar el valor de cualquier celda
de acierto a ­1. De esa manera, solo tenemos UNA matriz para verificar y manipular.

un ­1 en una ubicación de celda particular significa que la


celda ya ha sido alcanzada, por lo que solo buscamos
números no negativos en la matriz.

locationCells
(variable de instancia de 0 1 2
DotCom)

La opción dos es un poco mejor, pero sigue


siendo bastante complicada.

La opción dos es un poco menos complicada que la opción uno, pero no es muy eficiente. Aún tendría
que recorrer las tres ranuras (posiciones de índice) de la matriz, incluso si una o más ya no son
válidas porque han sido "accesionadas" (y tienen un valor ­1).
Tiene que haber algo mejor...

usted está aquí 129


Machine Translated by Google

código de preparación

código de preparación código de preparación código de prueba código real

3 Opción tres
Eliminamos la ubicación de cada celda a medida que llega y luego modificamos la matriz para que sea más pequeña. Excepto que las

matrices no pueden cambiar su tamaño, por lo que tenemos que crear una nueva matriz y copiar las celdas restantes de la matriz

anterior a la nueva matriz más pequeña.

matriz de celdas de ubicación


La matriz
comienza con un tamaño de 3 y
ANTES de que cualquier célula
haya sido atacada 2 recorremos las 3 celdas (posiciones en la matriz)
0 1
para buscar una coincidencia entre la suposición
del usuario y el valor de la celda (4,5, 6).

matriz de celdas de ubicación Cuando se alcanza la celda '5', creamos una


matriz nueva y más pequeña con solo las
DESPUÉS de que se haya
alcanzado la celda '5', que ubicaciones de las celdas restantes y la asignamos a la
original
estaba en el índice 1 de la matriz UbicaciónReferencia de celdas.
0 1

La opción tres sería mucho mejor si la matriz pudiera reducirse, de modo que no tuviéramos
que crear una nueva matriz más pequeña, copiar los valores restantes y reasignar la referencia.

El código de preparación original para parte La vida sería buena si pudiéramos


del método checkYourself(): cambiarla a:

REPETIR con cada una de las celdas de ubicación en la matriz int REPETIR con cada una de las celdas de ubicación restantes

// COMPARA la suposición del usuario con la celda de ubicación // COMPARA la suposición del usuario con la celda de ubicación

SI la conjetura del usuario coincide SI la conjetura del usuario coincide

INCREMENTAR el número de visitas


QUITAR esta celda de la matriz

// DESCUBRE si fue la última celda de ubicación: // DESCUBRE si fue la última celda de ubicación:

SI el número de golpes es 3, REGRESAR “matar” SI la matriz ahora está vacía, DEVOLVER "matar"

DE LO CONTRARIO , no fue una muerte, así que REGRESAR “golpear” DE LO CONTRARIO , no fue una muerte, así que REGRESAR “golpear”

TERMINARA SI TERMINARA SI

ELSE la suposición del usuario no coincidió, por lo tanto DEVOLVER “miss” ELSE la suposición del usuario no coincidió, por lo tanto DEVOLVER “miss”

TERMINARA SI TERMINARA SI

FINALIZAR REPETIR FINALIZAR REPETIR

130 capitulo 6
Machine Translated by Google

Conozca la API de Java

Si tan solo pudiera encontrar una


matriz que pudiera reducirse cuando se elimina
algo. Y uno que no tenía que recorrer para
verificar cada elemento, sino que simplemente
podía preguntarle si contiene
Que estas buscando. Y te permitiría sacar cosas
de él, sin tener que saber exactamente en qué
ranura están.
Eso sería un sueño. Pero sé que es sólo
una fantasía...

usted está aquí 131


Machine Translated by Google

cuando las matrices no son suficientes

Despierta y huele la biblioteca

Como por arte de magia, realmente hay es tal cosa.

Pero no es un formación, se trata de un Lista de arreglo.

Una clase en la biblioteca central de Java (la API).

Una de los millones de clases de


la biblioteca Java.

Puede usarlo en su código como


si lo hubiera escrito usted mismo.

(Nota: el método add(Object elem) en


realidad parece un poco más extraño que
el que hemos mostrado aquí... llegaremos
al método real más adelante en el libro. Por
Esto es sólo una muestra de ALGUNOS
ahora, considérelo como un add( )
de los métodos en ArrayList.
método que toma el objeto que desea agregar).

132 capítulo 6
Machine Translated by Google

Conozca la API de Java

Algunas cosas que puedes hacer con ArrayList


No se preocupe por esta nueva sintaxis de corchetes angulares de <Egg>

ahora mismo; simplemente significa "hacer de esto una lista de objetos Huevo".
1 Haz uno
ArrayList<Huevo> miLista = new ArrayList<Huevo>(); Se crea un nuevo objeto
ArrayList en el montón. Es
pequeño porque está vacío.
2 Pon algo en él
Huevo s = nuevo Huevo();
Ahora ArrayList crece como un "cuadro"
para contener el objeto Egg.
[Link](s);

3 Ponle otra cosa


Huevo b = nuevo Huevo(); ArrayList vuelve a crecer para contener
el segundo objeto Egg.

[Link](b);
b
s

4 Descubre cuántas cosas hay en él. ArrayList contiene 2 objetos, por lo


int theSize = [Link](); que el método size() devuelve 2

5 Descubre si contiene algo ArrayList SÍ contiene el objeto Egg al que hace


referencia 's', por lo que contiene () devuelve verdadero
booleano isIn = [Link](s);

ArrayList tiene base cero (significa que el primer índice es


6 Descubra dónde está algo (es decir, su índice)
0) y dado que el objeto al que hace referencia 'b' era
int idx = [Link](b); el segundo elemento en la lista, indexOf() devuelve 1

7 Averigua si está vacío


definitivamente NO está vacío, por lo que
isEmpty() devuelve falso
booleano vacío = [Link]();

8 Quitarle algo Oye, mira, ¡se encogió!

[Link](s);
b
usted está aquí 133
Machine Translated by Google

cuando las matrices no son suficientes

Afila tu lápiz

Lista de arreglo matriz regular

ArrayList<String> miLista = nuevo


Cadena [] miLista = nueva Cadena [2];
ArrayList<Cadena>();

Cadena a = nueva cadena ("whoohoo");


Cadena a = nueva cadena ("whoohoo");
[Link](a);

Cadena b = nueva cadena ("Rana");


Cadena b = nueva cadena ("Rana");
[Link](b);

int theSize = [Link]();

Objeto o = [Link](1);

[Link](1);

booleano isIn = [Link](b);

134 capítulo 6
Machine Translated by Google

Conozca la API de Java

no existen
Preguntas tontas
La entrevista de esta semana:

ArrayList, en matrices
HeadFirst: Entonces, las ArrayLists son como matrices, ¿verdad?

ArrayList: ¡En sus sueños! Soy un objeto muchas gracias.

HeadFirst: Si no me equivoco, las matrices también son objetos. Viven en el montón allí mismo con todos los
demás objetos.

ArrayList: Seguro que las matrices se acumulan, claro, pero una matriz sigue siendo una aspirante a
ArrayList. Un impostor. Los objetos tienen estado y comportamiento, ¿verdad? Lo tenemos claro. ¿Pero
realmente has intentado llamar a un método en una matriz?

HeadFirst: Ahora que lo mencionas, no puedo decir que sí. Pero, de todos modos, ¿qué método llamaría?
Sólo me importa llamar a métodos sobre las cosas que pongo en la matriz, no la matriz en sí. Y puedo usar
la sintaxis de matriz cuando quiero poner y sacar cosas de la matriz.

ArrayList: ¿Es así? ¿Quieres decirme que realmente eliminaste algo de una matriz? (Dios, ¿dónde los
entrenan ? ¿En McJava?)

HeadFirst: Por supuesto que saco algo del conjunto. Digo Dog d = dogArray[1] y obtengo el objeto Dog en el
índice 1 de la matriz.

ArrayList: Muy bien, intentaré hablar despacio para que puedas seguirme. No estabas , repito , no
eliminando a ese Perro de la matriz. Todo lo que hizo fue hacer una copia de la referencia al Perro y asignarla
a otra variable Perro.

HeadFirst: Oh, ya veo lo que estás diciendo. No, en realidad no eliminé el objeto Perro de la matriz.
Todavía está ahí. Pero supongo que puedo establecer su referencia en nula.

ArrayList: Pero soy un objeto de primera clase, así que tengo métodos y puedo, ya sabes, hacer cosas
como eliminar la referencia del Perro de mí mismo, no solo establecerla como nula.
Y puedo cambiar mi talla, dinámicamente (búsquelo). ¡Intenta conseguir una matriz para hacer eso!

HeadFirst: Vaya, odio mencionar esto, pero el rumor es que no eres más que un grupo glorificado pero
menos eficiente. Que, de hecho, eres solo un contenedor para una matriz, agregando métodos
adicionales para cosas como cambiar el tamaño que yo mismo habría tenido que escribir. Y ya que estamos
en eso, ¡ni siquiera puedes mantener primitivas! ¿No es eso una gran limitación?

ArrayList: No puedo creer que creas esa leyenda urbana. No, no soy sólo una matriz menos eficiente.
Admito que hay algunas situaciones extremadamente raras en las que una matriz puede ser un poco,
repito, un poco más rápida para ciertas cosas. Pero, ¿vale la pena la minúscula ganancia de rendimiento para
renunciar a todo este poder? Aún así, observe toda esta flexibilidad. Y en cuanto a las primitivas, por supuesto,
puedes poner una primitiva en una ArrayList, siempre y cuando esté envuelta en una clase contenedora
primitiva (verás mucho más sobre eso en el capítulo 10).
Y a partir de Java 5.0, ese ajuste (y desenvolvimiento cuando se vuelve a sacar la primitiva) ocurre
automáticamente. Y está bien, reconoceré que sí, si estás usando una ArrayList de primitivas, probablemente
sea más rápido con una matriz, debido a todo el empaquetado y desenvolvimiento, pero aún así... ¿quién usa
realmente primitivos hoy en día?

¡Oh, mira la hora! Llego tarde a Pilates. Tendremos que hacer esto de nuevo alguna vez.

usted está aquí 135


Machine Translated by Google

diferencia entre ArrayList y matriz

Comparando ArrayList con una matriz normal

Lista de arreglo matriz regular

ArrayList<String> miLista = nuevo Cadena [] miLista = nueva Cadena [2];


ArrayList<Cadena>();

Cadena a = nueva cadena ("whoohoo"); Cadena a = nueva cadena ("whoohoo");


[Link](a); miLista[0] = a;

Cadena b = nueva cadena ("Rana"); Cadena b = nueva cadena ("Rana");


[Link](b); miLista[1] = b;

int theSize = [Link](); int elTamaño = [Link];


Aquí es donde

Objeto o = [Link](1); Cadena o = miLista[1];


empieza a verse
realmente diferente...

[Link](1); miLista[1] = nulo;

booleano isIn = [Link](b); booleano isIn = falso;

para (elemento de cadena: miLista) {

si ([Link](elemento)) {

está en = verdadero;

romper;

136 capítulo 6
Machine Translated by Google

Conozca la API de Java

Comparando ArrayList con una matriz normal

1 Una matriz antigua y simple debe conocer su tamaño 3 Las matrices utilizan una sintaxis de matriz que
en el momento de su creación. no se utiliza en ningún otro lugar de Java.

miLista[1]

nueva cadena[2] Necesita una talla. Los corchetes de matriz [] son una sintaxis

especial que se usa solo para matrices.


nueva ArrayList<Cadena>()

No se requiere tamaño (aunque


puedes darle un tamaño si lo deseas).

4 Las ArrayLists en Java 5.0 están


2 Para colocar un objeto en una matriz normal, debe asignarlo parametrizadas.
a una ubicación específica.

(Un índice de 0 a uno menor que la longitud de la


matriz).
miLista[1] = b;
ListaMatriz<Cadena>

Necesita un índice.
La <Cadena> entre corchetes angulares es un
"parámetro de tipo". ArrayList<String> significa
simplemente "una lista de cadenas", a diferencia de
ArrayList<Dog> que significa "una lista de perros".

[Link](b);

Sin índice.

usted está aquí 137


Machine Translated by Google

el código DotCom con errores

código de preparación código de prueba código real código real

Arreglemos el código DotCom.

Recuerde, así es como se ve la versión con errores:


Hemos cambiado el nombre de la clase DotCom ahora (en
clase pública DotCom { lugar de SimpleDotCom), para la nueva versión avanzada, pero
este es el mismo código que vio en el capítulo anterior.

int[] ubicaciónCeldas;
int número de visitas = 0;

setLocationCells vacío público (int [] locomotoras) {


ubicaciónCells = locs;
}

cadena pública checkYourself(String stringGuess) {


int adivinar = [Link](stringGuess);
Resultado de cadena = “fallo”;

para (int celda: ubicaciónCells) {


si (adivina == celda) {

Donde todo salió mal. contó cada Nosotros

resultado = “golpe”; conjetura como un acierto, sin comprobar


si esa celda ya había sido
número de visitas++; acertada.

romper;
}

} // fuera de la lupa

if (numOfHits == ubicació[Link]) {
resultado = “matar”;
}

[Link](resultado);
resultado de devolución;
} // cerrar método
} // cerrar clase

138 capítulo 6
Machine Translated by Google

Conozca la API de Java

código de preparación código de prueba código real código real

Clase DotCom nueva y mejorada

Ignora esta línea


ahora; nosotros
importar [Link]; para hablar de
eso al final del
capítulo .
clase pública DotCom {

private ArrayList<String> celdas de ubicación;


// privado int numOfHits; // no necesito
eso ahora Cambie la matriz de cadenas a una ArrayList que contenga cadenas.

setLocationCells vacío público (ArrayList<String> loc) {


ubicaciónCeldas = loc; Nombre de argumento nuevo y mejorado.
}

Descubra si la suposición del usuario


cadena pública checkYourself (String entrada de usuario) {
está en ArrayList, preguntando por su índice.
Si no está en la lista, entonces indexOf()
Resultado de cadena = “fallo”; devuelve un ­1.

int índice = ubicació[Link](userInput);

si (índice >= 0) {
cero,
Si el índice es mayor o igual a
ubicació[Link](índice); lista, así la
que él.
elimine del usuario definitivamente está en el
suposición

Si la lista está vacía,


si (ubicació[Link]()) { ¡este fue el golpe mortal!
resultado = “matar”;
} demás {
resultado = “golpe”;
} // cerrar si

} // cerrar exterior si

resultado de devolución;
} // cerrar método
} // cerrar clase

usted está aquí 139


Machine Translated by Google

haciendo el DotComBust

Construyamos el juego REAL:


"Hundir una punto com"

Vas a construir el juego Sink a Dot


Com, con una cuadrícula de 7 x 7 y tres
Dot Com. Cada Punto Com ocupa
tres celdas.

parte de una interacción de juego

Ventana de edición de archivos Ayuda a vender

%java DotComBust

Ingrese una suposición A3

extrañar

Ingrese una suposición B2

extrañar

Introduzca una suposición C4

extrañar

cada caja Introduzca una suposición D2


Cuadrícula de 7 X 7 es una “celda”
golpear

Ingrese una suposición D3

golpear

Introduzca una suposición D4

¡Ay! Has hundido [Link] : (

matar

Ingrese una suposición B4

extrañar

Ingrese una suposición G3

golpear

Ingrese una suposición G4

golpear

comienza en cero, como las matrices de Java Ingrese una suposición G5

¡Ay! Has hundido [Link]: (

matar

140 capítulo 6 Ingrese una suposición A7

extrañar
Machine Translated by Google

Conozca la API de Java

¿Qué necesita cambiar? La clase DotComBust continúa...

Una clase DotCom

Clase B DotComBust (el juego)

a dt oh a kmi Doht Co
i nupt
metro
norte

ay r
metro yo
mi
yo oh
Ca
Fr ti
pag
oh
mis
ens
tus mis un
d lays w it
3 clases: crmiat h
pag

DotComBusto puntocom Ayudante del juego

La clase de juego. Los objetos La clase auxiliar


Crea DotComs, recibe DotCom reales. (Ready­Bake).
comentarios de los Los DotCom conocen su Sabe cómo aceptar

usuarios, reproduce hasta nombre, ubicación y cómo la entrada de la línea


que todos los Dot­Coms mueren comprobar si un usuario adivina de comandos del
una coincidencia.
usuario y crear
ubicaciones DotCom.

Más 4
ArrayLists: 1 para
DotComBust y 1
5 objetos: para cada uno de
los 3 objetos DotCom.

puntocom
DotComBusto puntocom Ayudante del juego
puntocom

usted está aquí 141


Machine Translated by Google

estructura detallada del juego

¿Quién hace qué en el juego DotComBust?


(y cuando)

DotComBusto El método main() en la


La clase de instancias clase DotComBust crea
1 juego. una instancia del objeto
DotComBust que hace todas
las cosas del juego.
Objeto
DotComBust

instancias

Objeto
El objeto DotComBust (juego)
ayudante
GameHelper
crea una instancia de
2 GameHelper, el objeto que
ayudará al juego a hacer su
Objeto trabajo.
DotComBust

El objeto DotComBust crea


una instancia de ArrayList que
3 contendrá los 3 objetos DotCom.
Objeto
ayudante dotComsList
GameHelper

Objeto
DotComBust

Objeto ArrayList (para


contener objetos DotCom)

142 capítulo 6
Machine Translated by Google

Conozca la API de Java

El objeto DotComBust crea tres


4 objetos DotCom (y los coloca
células
en ArrayList)

Objeto
células
GameHelper
ayudante dotComsList

puntoCom puntocom
puntoCom
células
0 2
1

Objeto
DotComBust Objeto ArrayList para Objetos
contener objetos DotCom
DotCom

El objeto DotComBust solicita al objeto El objeto DotComBust le da a cada uno de los objetos Dot­
auxiliar una ubicación para un Com una ubicación (que DotComBust obtuvo del objeto
DotCom (hace esto 3 veces, una por cada auxiliar) como “A2”, “B2”, etc. Cada objeto DotCom coloca
DotCom) sus propias tres celdas de ubicación en un ArrayList
ohC
yo ati en
akmi
metro

aquí lo tienes
Objeto ArrayList (para
5 Objeto
GameHelper células
celúla

0
celúla
celúla contener ubicaciones
de celdas DotCom)
2
1
ayudante dotComsList

células
objeto
Objeto celúla

0
celúla
celúla

2
ArrayList
puntoCom puntocom 1
puntoCom
DotComBust 0 2
células
1

objeto
Objeto ArrayList para Objetos celúla
celúla
celúla ArrayList
0 2

contener objetos DotCom


1

DotCom

El objeto DotComBust solicita al objeto auxiliar una El objeto DotComBust recorre la lista de DotCom y pide a
suposición del usuario (el asistente solicita al cada uno que verifique la suposición del usuario para encontrar
usuario y obtiene información desde la línea de una coincidencia. DotCom comprueba sus ubicaciones ArrayList y
comandos)
uess devuelve un resultado ("acierto", "fallo", etc.)
tusmir
gramo

gramo
mit

6 aquí lo tienes
tumiss Objeto ArrayList (para
Objeto s
t hi
gramo

contener ubicaciones
GameHelper miCk
celúla celúla
celúla
células

hC
02

ayudante dotComsList "golpear" 1


de celdas DotCom)

células
objeto
Objeto celúla

0
celúla
celúla

2
ArrayList
puntoCom puntocom 1
puntocom
DotComBust 0 2
células
1

Y así el juego continúa... recibiendo objeto


información del usuario, pidiendo a cada Objeto ArrayList para ArrayList
Objetos celúla
celúla
celúla

DotCom que verifique una coincidencia y


0 2

contener objetos DotCom


1

continuando hasta que todos los DotCom estén muertos. DotCom

usted está aquí 143


Machine Translated by Google

la clase DotComBust (el juego)


código de preparación código de preparación código de prueba código real

DotComBusto Preparar código para la clase DotComBust real


Ayudante de GameHelper
ArrayList dotComsList int
numOfGuesses

configurarJuego()

empezar a jugar()

comprobarUserGuess()

terminarJuego()

DECLARAR y crear una instancia de la variable de instancia de GameHelper , denominada ayudante.

DECLARAR y crear una instancia de un ArrayList para contener la lista de DotComs (inicialmente tres). Llámelo
dotComsList.
Variable
DECLARAR una variable int para contener el número de conjeturas del usuario (para que podamos darle al usuario una
Declaraciones puntuación al final del juego). Nómbrelo numOfGuesses y configúrelo en 0.

DECLARAR un método setUpGame() para crear e inicializar los objetos DotCom con nombres y ubicaciones. Mostrar
instrucciones breves al usuario.

Método DECLARAR un método startPlaying() que le pide al jugador que adivine y llama al método checkUserGuess()
hasta que todos los objetos DotCom sean eliminados del juego.
Declaraciones DECLARAR un método checkUserGuess() que recorre todos los objetos DotCom restantes y llama al método checkYourself()
de cada objeto DotCom.

DECLARAR un método finishGame() que imprime un mensaje sobre el rendimiento del usuario, en función de cuántas
conjeturas fueron necesarias para hundir todos los objetos DotCom.

MÉTODO: anular setUpGame()

// crear tres objetos DotCom y nombrarlos CREAR tres

Método objetos DotCom.

ESTABLEZCA un nombre para cada DotCom.

Implementaciones AGREGUE los DotCom a dotComsList (ArrayList).

REPETIR con cada uno de los objetos DotCom en la matriz dotComsList

LLAME al método placeDotCom() en el objeto auxiliar para obtener una ubicación seleccionada aleatoriamente
para este DotCom (tres celdas, alineadas vertical u horizontalmente, en una cuadrícula de 7 X 7).

ESTABLEZCA la ubicación de cada DotCom según el resultado de la llamada placeDotCom() .

FINALIZAR REPETIR

MÉTODO FINAL

144 capítulo 6
Machine Translated by Google

Conozca la API de Java


código de preparación código de preparación código de prueba código real

Las implementaciones de métodos continuaron:

MÉTODO: void startPlaying()

REPETIR mientras existan DotComs

OBTÉN la entrada del usuario llamando al método auxiliar getUserInput()

EVALUAR la suposición del usuario mediante el método checkUserGuess()

FINALIZAR REPETIR

MÉTODO FINAL

MÉTODO: void checkUserGuess (String userGuess)

// descubre si hay un impacto (y muerte) en cualquier DotCom

INCREMENTAR el número de conjeturas del usuario en la variable numOfGuesses

CONFIGURA la variable de resultado local (una cadena) en "fallo", suponiendo que la suposición del usuario será un error.

REPETIR con cada uno de los DotObjects en la matriz dotComsList

EVALUAR la suposición del usuario llamando al método checkYourself() del objeto DotCom

ESTABLEZCA la variable de resultado para "golpear" o "matar" si corresponde

SI el resultado es "matar", ELIMINAR el DotCom de la lista dotComs

FINALIZAR REPETIR

MOSTRAR el valor del resultado al usuario

MÉTODO FINAL

MÉTODO: void finishGame()

MUESTRA un mensaje genérico de "juego terminado", luego:

SI el número de conjeturas de los usuarios es pequeño,

MOSTRAR un mensaje de felicitación

DEMÁS

MOSTRAR uno insultante

TERMINARA SI

MÉTODO FINAL

Afila tu lápiz

usted está aquí 145


Machine Translated by Google

el código DotComBust (el juego)

código de preparación código de prueba código real código real


Afila tu lápiz
importar [Link].*;
¡Anota el código tú mismo!
clase pública DotComBust {

ayudante privado de GameHelper = nuevo GameHelper();


Haga coincidir
1 privado ArrayList<DotCom> dotComsList = nuevo ArrayList<DotCom>(); privado int numOfGuesses = 0;
las anotaciones en la parte
inferior de cada página con los
private void setUpGame() { // primero crea números del código. Escriba

algunas punto com y dales ubicaciones el número en la ranura


frente al
DotCom uno = nuevo DotCom();
[Link](“[Link]”);
anotación
DotCom dos = nuevo DotCom(); correspondiente.
[Link](“[Link]”); 2
DotCom tres = nuevo DotCom(); Usarás cada uno

[Link](“[Link]”); anotación solo una vez y


necesitará todas las anotaciones.
[Link](uno);
[Link](dos);
[Link](tres);

[Link](“Tu objetivo es hundir tres punto com.”); 3


[Link](“[Link], [Link], [Link]”);
[Link](“Intenta incluirlos todos en el menor número de conjeturas”);

para (DotCom dotComToSet: dotComsList) { 4


ArrayList<String> newLocation = [Link](3); 5
[Link](nuevaUbicación);
6
} // cerrar bucle for
} // cerrar el método setUpGame

inicio vacío privado jugando () {


mientras(![Link]()) { 7
8
String userGuess = [Link](“Ingrese una suposición”); checkUserGuess(usuarioGuess);
9
} // cerrar mientras
terminarJuego(); 10
} // cerrar el método startPlaying

Pídale al ayudante una ubicación de DotCom

obtener entrada del usuario


declarar e inicializar las repetir con cada DotCom en la lista
variables que necesitaremos
llame al método setter para llamar a nuestro
este puntocom propio método checkUserGuess
imprimir breves
instrucciones para darle
del la ubicación que acaba de obtener
ayudante
usuario
cree tres objetos DotCom, siempre y cuando la lista DotCom
NO esté vacía
llamar a nuestro propio método FinishGame
asígneles nombres y péguelos en ArrayList

146 capítulo 6
Machine Translated by Google

Conozca la API de Java


código de preparación código de prueba código real código real
Hagas lo que hagas,
NO gires el
¡página!
checkUserGuess vacío privado (String userGuess) {

númeroDeGuesses++; 11 No hasta que hayas


terminado este
Resultado de cadena = “fallo”; 12 ejercicio.

para (DotCom dotComToTest: dotComsList) { 13


Nuestra versión está encendida.
resultado = [Link](userGuess); si 14
la página siguiente.
([Link](“golpear”)) {
romper; 15
}
if ([Link](“matar”))
{ [Link](dotComToTest); dieciséis

romper;

} } // cerrar para
[Link](resultado); 17
} // cerrar método

juego de acabado vacío privado () {


[Link](“¡Todos los Dot Coms están muertos! Sus acciones ahora no tienen valor.”);
si (númDeGuesses <= 18) {
“ + númeroDeConjeturas +
[Link](“Solo te tomó [Link](“ Saliste " suposiciones."); 18
antes de que tus opciones se hundieran.”);
} demás {
[Link](“Te tomó bastante tiempo. “+ numOfGuesses + [Link](“Los peces " suposiciones.");
bailan con tus opciones.”);
}
} // cerrar método

público estático vacío principal (String[] args) {


Juego DotComBust = nuevo DotComBust(); 19
[Link](); 20
[Link]();
21
} // cerrar método
}

repetir con todos los DotComs en la lista imprimir el


imprimir un mensaje diciéndole resultado
Este tipo está muerto, así que sácalo del
al usuario cómo le fue en el juego para el usuario
La lista DotComs luego sale del circuito decirle al objeto del
incrementar el número de conjeturas que ha realizado el usuario juego que configure el juego
asumir que es un 'error', a menos que se indique lo contrario

Pídale a DotCom que verifique la suposición del usuario,


Salga del circuito decirle al objeto del juego que inicie el ciclo
principal del juego (sigue pidiendo la entrada buscando un acierto (o muerte)
temprano, no tiene sentido
probar a los demás. del usuario y comprobando la suposición)
crear el objeto del juego

usted está aquí 147


Machine Translated by Google

el código DotComBust (el juego)

código de preparación código de prueba código real código real

importar [Link].*; Declare e inicialice las


clase pública DotComBust { variables que necesitaremos.

ayudante privado de GameHelper = nuevo GameHelper();


privado ArrayList<DotCom> dotComsList = nuevo ArrayList<DotCom>(); privado int numOfGuesses = 0; Cree una ArrayList de
objetos DotCom (en otras
palabras, una lista que
contendrá SÓLO objetos
private void setUpGame() { // primero crea
DotCom, tal como
algunas punto com y dales ubicaciones DotCom[] significaría una
DotCom uno = nuevo DotCom();
matriz de objetos DotCom).
[Link](“[Link]”);
DotCom dos = nuevo DotCom(); Crea tres objetos DotCom, dales

[Link](“[Link]”); nombres y pégalos


en la lista de matrices.
DotCom tres = nuevo DotCom();
[Link](“[Link]”);
[Link](uno);
[Link](dos);
[Link](tres); Imprimir breves
instrucciones para el usuario.

[Link](“Tu objetivo es hundir tres punto com.”);


[Link](“[Link], [Link], [Link]”);
[Link](“Intenta incluirlos todos en el menor número de conjeturas”);

para (DotCom dotComToSet: dotComsList) { Repita con cada DotCom de la lista.


Pídale al ayudante una
ubicación de DotCom
ArrayList<String> newLocation = [Link](3);
(una ArrayList de cadenas).

[Link](nuevaUbicación);
Llame al método de este
} // cerrar bucle for
establecimiento en DotCom para darle la
} // cerrar el método setUpgame ubicación que acaba de obtener del asistente.

inicio vacío privado jugando () {


Siempre que la lista DotCom NO esté vacía (! significa NO, es lo mismo que
mientras(![Link]()) { ([Link]() == false).

String userGuess = [Link](“Ingrese una suposición”); checkUserGuess(usuarioGuess); Obtenga información del usuario.

Llame a nuestro
propio método checkUserGuess.
} // cerrar mientras
terminarJuego(); Llame a nuestro propio método FinishGame.

} // cerrar el método startPlaying

148 capítulo 6
Machine Translated by Google

Conozca la API de Java


código de preparación código de prueba código real código real

checkUserGuess vacío privado (String userGuess) {

incrementar el número de conjeturas que ha realizado el usuario


númeroDeGuesses++;

asumir que es un 'error', a menos que se indique lo contrario


Resultado de cadena = “fallo”;

repetir con todos los DotComs en la lista


para (DotCom dotComToTest: dotComsList) {

resultado = [Link](userGuess); Pídale a DotCom que verifique la suposición del

usuario, buscando un acierto (o muerte)


si ([Link](“golpear”)) {

romper; Salga del circuito temprano, no tiene


sentido probar a los demás.
}
si ([Link](“matar”)) {

[Link](puntoComToTest); romper; Este tipo está muerto, así que sácalo del

La lista DotComs luego sale del circuito


}

} // cerrar para

imprimir el resultado para el usuario


[Link](resultado);
} // cerrar método imprimir un mensaje diciéndole
al usuario cómo le fue en el juego

juego de acabado vacío privado () {


[Link](“¡Todos los Dot Coms están muertos! Sus acciones ahora no tienen valor.”);
si (númDeGuesses <= 18) {
“ + númeroDeConjeturas +
[Link](“Solo te tomó [Link](“ Saliste " suposiciones.");
antes de que tus opciones se hundieran.”);
} demás {
[Link](“Te tomó bastante tiempo. “+ numOfGuesses + [Link](“Los peces bailan " suposiciones.");
con tus opciones”);
}
} // cerrar método

público estático vacío principal (String[] args) {


Juego DotComBust = nuevo DotComBust();
[Link](); crear el objeto del juego
[Link]();
decirle al objeto del juego que se configure
} // cerrar método el juego
}
decirle al objeto del juego que inicie el ciclo
principal del juego (sigue pidiendo la entrada
del usuario y comprobando la suposición)

usted está aquí 149


Machine Translated by Google

el código DotCom

código de preparación código de prueba código real código real

La versión final del


clase puntocom

importar [Link].*;

Variables de instancia de DotCom:


clase pública DotCom {
­ una ArrayList de ubicaciones de celdas
private ArrayList<String> celdas de ubicación;
­ el nombre del DotCom
nombre de cadena privada;

Un método de establecimiento que


setLocationCells vacío público (ArrayList<String> loc) {
actualiza la ubicación de DotCom.
ubicaciónCeldas = loc; (Ubicación aleatoria proporcionada
por el método GameHelper
}
placeDotCom( ).)

setName público vacío (Cadena n) { Su método de configuración básico

nombre = n;

} ¡El método ArrayList indexOf() en acción! Si la


suposición del usuario es una de las entradas en
ArrayList, indexOf() devolverá su ubicación de
cadena pública checkYourself (String entrada de usuario) { ArrayList. De lo contrario, indexOf() devolverá ­1.

Resultado de cadena = “fallo”;

int índice = ubicació[Link](userInput);

si (índice >= 0) {
Usar el método remove() de ArrayList para eliminar una entrada.
ubicació[Link](índice);

si (ubicació[Link]()) { Usar el método isEmpty( ) para ver si se


han adivinado todas las ubicaciones
resultado = “matar”;

+ nombre +
“ :
[Link](“¡Ay! Te hundiste” ( “);

} demás {

resultado = “golpe”;
Avisa al usuario cuando
} // cerrar si se ha hundido un DotCom.

} // cerrar si

resultado de devolución;

Retorno: 'fallar' o 'golpear' o


'matar'.
} // cerrar método

} // cerrar clase

150 capitulo 6
Machine Translated by Google

Conozca la API de Java

Expresiones booleanas súper poderosas


No es igual ( != y ! )
si

si (modelo! = 2000) {
// hacer cosas que no sean del modelo 2000

}
Operadores 'Y' y 'O' ( &&, || )

si (![Link](“X”)) {
// hacer cosas X que no sean de marca
}

Operadores de Corto Circuito ( && , || )

if (precio >= 300 && precio < 400) {


cámara = “X”;
}

if ([Link](“A”) || [Link](“B”) ) {
// hacer cosas para marca A marca B
}

si (refVar! = nulo &&


si (([Link](“óptico”) &&
[Link]()) {
(grado de zoom >= 3 && grado de zoom <= 8)) ||
// hacer cosas de 'tengo un tipo válido'
([Link](“digital”) &&
}
(grado de zoom >= 5 && grado de zoom <= 12))) {
// hacer cosas de zoom apropiadas Operadores sin cortocircuito ( & ,|)
}

usted está aquí 151


Machine Translated by Google

Listo para hornear: GameHelper

Esta es la clase auxiliar del juego. Además del método de entrada del usuario (que avisa al usuario y
lee la entrada desde la línea de comandos), el gran servicio del ayudante es crear las ubicaciones de
las celdas para los DotCom.
Si fuéramos usted, nos alejaríamos lentamente de este código, excepto para escribirlo y compilarlo.
Intentamos mantenerlo bastante pequeño para que no tuvieras que escribir tanto, pero eso significa
que no es el código más legible. Y recuerda, no podrás compilar la clase del juego DotComBust
importar [Link].*; hasta que tengas clase.
importar [Link].*; este

clase pública GameHelper {

Nota: Para obtener crédito adicional,


Alfabeto de cadena final estático privado = “abcdefg”;
privado int gridLength = 7; puede intentar "descomentar"
tamaño de cuadrícula int privado = 49; los [Link](ln) en el
private int [] grid = new int[gridSize]; método placeDotCom( ), ¡solo
privado int comCount = 0; para verlo funcionar! Estas
declaraciones impresas le
cadena pública getUserInput (solicitud de cadena) {
Cadena inputLine = nulo; permitirán "hacer trampa" al
[Link](mensaje + prueba { “ “); proporcionarle la ubicación de los DotCom, pero le ayudarán

BufferedReader es = nuevo BufferedReader(


nuevo InputStreamReader([Link]));
inputLine = [Link]();
si ([Link]() == 0) devuelve nulo; } captura (IOException e) {

[Link](“IOException: “ + mi);
}
devolver [Link]();
}

pública ArrayList<Cadena> placeDotCom(int comSize) {


ArrayList<String> alphaCells = nueva ArrayList<String>();
Cadena [] alphacoords = nueva cadena [comSize]; // contiene coordenadas de tipo 'f6'
Temperatura de cadena = nula; // Cadena temporal para concat
int [] coords = nuevo int[comSize]; intentos enteros = 0; // coordenadas de candidatos actuales
éxito booleano = falso; // contador de intentos actuales
// bandera = ¿encontraste una buena ubicación?
ubicación interna = 0; // ubicación inicial actual

comCount++; int // enésimo punto com para colocar


incr = 1; if ((comCount // establecer incremento horizontal
% 2) == 1) { incr = gridLength; // si punto com es impar (colocar verticalmente)
// establecer incremento vertical
}

while (!éxito e intentos++ < 200) { // bucle de búsqueda principal (32)


ubicación = (int) ([Link]() * gridSize); // obtener un punto de partida aleatorio

//[Link](“ prueba int x = 0; + ubicación);
// enésima posición en puntocom para colocar
éxito = verdadero; while // asumir el éxito
(éxito && x < comSize) { if (grid[ubicación] == 0) { // busca puntos adyacentes no utilizados
// si aún no se usa

152 capítulo 6
Machine Translated by Google

Conozca la API de Java

El código de la clase GameHelper continúa...

coords[x++] = ubicación; ubicación += // guardar dirección


incr; if (ubicación >= gridSize) // prueba 'siguiente' adyacente
{ éxito = false; // fuera de límites ­ 'abajo'
// falla
}
if (x>0 && (ubicación % gridLength == 0)) { // fuera de límites ­ borde derecho
éxito = falso; // falla
}
} else { // // encontré una ubicación ya utilizada
[Link](“ usado “ éxito = falso; + ubicación);
// falla
}
}
} // terminar mientras

int x = 0; fila // convierte la ubicación en coordenadas alfa


interna = 0;
columna entera = 0;
// [Link](“\n”);
mientras (x <comSize) {
cuadrícula[coords[x]] = 1; fila = // marcar puntos de la cuadrícula maestra. como de costumbre'
(int) (coords[x] / gridLength); columna = coordenadas[x] % //obtener valor de fila
gridLength; temperatura = // obtener el valor de la columna numérica
[Link]([Link](columna)); // convertir a alfa

[Link]([Link]([Link](fila)));
x++; Esta es la declaración que le

// [Link](“ coord “+x+” = + [Link](x­1)); indica exactamente dónde
}
se encuentra DotCom.

// [Link](“\n”);

devolver células alfa;


}
}

usted está aquí 153


Machine Translated by Google

Paquetes API

Usando la biblioteca (la API de Java)

En la API de Java, las clases se


agrupan en paquetes.

Para usar una clase en la API, debes saber en


qué paquete se encuentra la clase.

[Link]

[Link]

[Link]

154 capítulo 6
Machine Translated by Google

Conozca la API de Java

Debes saber el nombre completo* de la clase que no existen


Preguntas tontas
deseas utilizar en tu código.

[Link]

Nombre del paquete nombre de la clase

Tienes que decirle a Java qué ArrayList quieres usar.


Tienes dos opciones:

A IMPORTAR
Coloque una declaración de importación en la parte superior de su archivo de código fuente:

importar [Link];
clase pública MiClase {... }
O

B TIPO
Escriba el nombre completo en todas partes de su código. Cada vez que lo uses.
Dondequiera que lo uses.

Cuando lo declaras y/o creas una instancia:


[Link]<Perro> lista = new [Link]<Perro>();

Cuando lo usas como tipo de argumento:


public void go([Link]<Dog> lista) { }

Cuando lo usas como tipo de devolución:


público [Link]<Perro> foo() {...}

*A menos que la clase esté en el paquete [Link].

usted está aquí 155


Machine Translated by Google

cuando las matrices no son suficientes

PUNTOS DE VIÑETA

ArrayList es una clase en la API de Java.


¿De dónde vino esa 'x'?
Para poner algo en una ArrayList, use add().
(o ¿qué significa cuando un paquete comienza con
java?) X Para eliminar algo de un ArrayList use remove().

Para saber dónde está algo (y si está) en una ArrayList,


utilice indexOf().

Para saber si un ArrayList está vacío, use


isEmpty().

Para obtener el tamaño (número de elementos) en


un ArrayList, use el método size() .

Para obtener la longitud (número de elementos) en una


matriz antigua normal, recuerde que debe utilizar la variable
de longitud.

Una ArrayList cambia de tamaño dinámicamente al


tamaño que sea necesario. Crece cuando se
agregan objetos y se reduce cuando se eliminan
objetos.

El tipo de matriz se declara mediante un parámetro de


tipo, que es un nombre de tipo entre paréntesis
angulares. Ejemplo: ArrayList<Button> significa que
ArrayList podrá contener solo objetos de tipo Button (o
subclases de Button, como aprenderá en los próximos
capítulos).

Aunque una ArrayList contiene objetos y no primitivos,


el compilador automáticamente “envolverá” (y
“desenvolverá” cuando la saque) una primitiva en
un Objeto, y colocará ese objeto en ArrayList en lugar
de la primitiva. (Más información sobre esta característica
más adelante en el libro).

Las clases se agrupan en paquetes.

Una clase tiene un nombre completo, que es una


combinación del nombre del paquete y el nombre de la clase.
La clase ArrayList es en realidad [Link].

Para utilizar una clase en un paquete que no sea java.


lang, debes decirle a Java el nombre completo de la
clase.

Puede utilizar una declaración de importación en la parte


superior de su código fuente o puede escribir el nombre
completo en cada lugar donde use la clase en su código.

156 capítulo 6
Machine Translated by Google

Conozca la API de Java

no existen
Preguntas tontas

importar

hazlo pegado
importar
incluye

importar

importar

importar

Una vez más, en el improbable caso de que aún


no lo tengas escrito:

importar
o

usted está aquí 157


Machine Translated by Google

conociendo la API

­ Julia, 31 años, modelo de mano.

Cómo jugar con la API


Dos cosas que quieres saber:

1 ¿Qué clases hay en la biblioteca?

2 Una vez que encuentras una clase,


¿cómo sabes lo que puede hacer?

1 buscar un libro

2 Utilice los documentos de la API HTML

158 capítulo 6
Machine Translated by Google

Conozca la API de Java

1 buscar un libro
Hojear un libro de
referencia es la mejor
manera de descubrir
qué hay en la biblioteca
de Java. Puedes tropezar
fácilmente con una clase
que parezca útil,
simplemente navegando por las páginas.

nombre de la clase

Nombre del paquete

descripción de clase

métodos (y otras cosas de las que hablaremos


más adelante)

usted está aquí 159


Machine Translated by Google

utilizando la documentación de la API de Java

2 Utilice los documentos de la API HTML

Desplácese por los paquetes


y seleccione (Pinchalo)
uno para restringir la lista en
el marco inferior solo a clases Aquí es donde está todo
de ese paquete.
lo bueno. Puede desplazarse
por los métodos para
2 obtener un breve resumen
Desplácese por las clases y
o hacer clic en un método
seleccione una (haga clic en
para obtenerlo completo.
ella) para elegir la clase que
detalles.
llenará el marco principal del navegador.

160 capítulo 6
Machine Translated by Google

Conozca la API de Java

[Link](2); imprimirAL(a);

imprimirAL(a);
[Link](0,”cero”);
[Link](1,”uno”);

printAL vacío estático público (ArrayList<String> al) {

if ([Link](“dos”)) {
}
[Link](“2.2”);

[Link](2,”dos”);

público estático vacío principal (String[] args) {

[Link](elemento + } “ “);

[Link](“ “);

if ([Link](“tres”)) { [Link](“cuatro”);

} clase pública ArrayListMagnet {

if ([Link](“cuatro”) != 4) {
[Link](4, “4.2”);
}

} }
importar [Link].*;
}
imprimirAL(a);

ArrayList<String> a = nueva ArrayList<String>();

Ventana de edición de archivos Ayuda Dance


para (elemento de cadena: al) {
% java ArrayListMagnet cero uno
dos tres
cero uno tres cuatro
cero uno tres cuatro 4.2
[Link](3,”tres”);
cero uno tres cuatro 4.2 imprimirAL(a);

usted está aquí 161


Machine Translated by Google

rompecabezas: crucigrama

JavaCross 7.0

162 capítulo 6
Machine Translated by Google

Conozca la API de Java

importar [Link].*;

clase pública ArrayListMagnet {

público estático vacío principal (String[] args) {

ArrayList<String> a = nueva ArrayList<String>();

Ventana de edición de archivos Ayuda Dance


[Link](0,”cero”);
[Link](1,”uno”);
% java ArrayListMagnet cero uno
dos tres
[Link](2,”dos”);
cero uno tres cuatro
cero uno tres cuatro 4,2 cero uno tres cuatro
4,2
[Link](3,”tres”);
imprimirAL(a);

if ([Link](“tres”)) {
[Link](“cuatro”);
}

[Link](2);

imprimirAL(a);

if ([Link](“cuatro”) != 4) {
[Link](4, “4.2”);
}

imprimirAL(a);

if ([Link](“dos”)) {
[Link](“2.2”);
}
imprimirAL(a);
}

printAL vacío estático público (ArrayList<String> al) {

para (elemento de cadena: al) {

[Link](elemento + } “ “);

[Link](“ “);
}
}

usted está aquí 163


Machine Translated by Google

respuestas del rompecabezas

PRIMITIVO S

D mi l h
ÍNDICE DE OBJETOS DE
JavaCruz Ud. h SEÑOR
B SI
respuestas
PAG oh hora del este C

l AGREGAR LARGO oh

OBTENER Antiguo Testamento norte

k V A EN T
LISTA DE ARREGLO l S A

GRAMO
R TAMAÑO I
A LONGITUD SM norte

PAG oh Ud. TAPAS


IMPORTAR A t
PAG
BIBLIOTECA

Afila tu lápiz

164 capítulo 6
Machine Translated by Google

7 herencia y polimorfismo

Éramos programadores mal

Vivir mejor en pagados y con exceso de trabajo hasta que

Probé el Plan de Polimorfismo. Pero gracias al

VillaObjeto Plan, nuestro futuro está

brillante. ¡El tuyo también puede serlo!

Planifique sus programas pensando en el futuro.

este es un nuevo capitulo 165


Machine Translated by Google

el poder de la herencia

La guerra de las sillas revisitada...

1
Cuadrado Círculo Triángulo Ameba
Miré lo que los cuatro
girar() girar() girar() girar() las clases tienen en común.
reproducir sonido() reproducir sonido() reproducir sonido() reproducir sonido()

2
Forma
Son formas y todas giran y
reproducir sonido. Así que abstraje el
características comunes y ponerlas en un
girar()
reproducir sonido() 3
nueva clase llamada Forma. Forma Luego vinculé las otras
cuatro clases de forma
superclase girar()
reproducir sonido() a la nueva clase Forma,
en una relación llamada
herencia.
Puede leer esto como "El cuadrado hereda de la forma",
"El círculo hereda de la forma", etc. Eliminé rotar() y subclases
reproducirSound() de las otras formas, por lo que ahora
solo hay una copia que mantener.
Cuadrado Círculo Triángulo Ameba
La clase Shape se denomina superclase de las otras cuatro
clases. Las otras cuatro son las subclases de Shape. Las
subclases heredan los métodos de la superclase. En otras
palabras, si la clase Shape tiene la funcionalidad, entonces
las subclases obtienen automáticamente esa misma funcionalidad.

166 capítulo 7
Machine Translated by Google

herencia y polimorfismo

¿Qué pasa con la rotación de ameba ()?

mir r
i d mi
ohv
norte
oh
w
Ask w
METRO
mi h oh

superclase
(más abstracto)
Forma
4
girar()
reproducir sonido()
HiceHice la clase
que la anulación de laanulara
Amoeba clase Amoeba
el método
rotar() del
Forma de superclase de los métodos
de larotar() y playSound()
superclase .
Forma. Anular simplemente
subclases
significa que una subclase
simplemente redefine
significa que una Anular
(mas especifico) uno de sus métodos heredados cuando la
subclase redefine uno de sus
necesita cambiar
heredados o ampliar
cuando sea los métodos
necesario
Cuadrado Círculo Triángulo Ameba
comportamiento de ese método.
cambiar o ampliar el comportamiento
girar() de ese método.
// específico de ameba
// rotar código
Métodos primordiales
reproducir sonido()
// específico de ameba
// código de sonido

usted está aquí 167


Machine Translated by Google

cómo funciona la herencia

Entendiendo la herencia
Cuando diseñas con herencia, pones código común en una
clase y luego le dices a otras clases más específicas que
la clase común (más abstracta) es su superclase. Cuando
una clase hereda de otra, la subclase hereda de la superclase.

En Java decimos que la subclase extiende la superclase.


Una relación de herencia significa que la subclase hereda los miembros de la
superclase. Cuando decimos "miembros de una clase" nos referimos a las
variables y métodos de instancia.
Por ejemplo, si PantherMan es una subclase de SuperHero, la
clase PantherMan hereda automáticamente las variables de instancia
y los métodos comunes a todos los superhéroes, incluidos ,
, , () ,y
pronto. Pero la subclase PantherMan puede agregar nuevos métodos
y variables de instancia propias, y puede anular los métodos que hereda de
la superclase SuperHero.

superclase superhéroe

(más abstracta) traje


variables de instancia
medias
(estado, atributos)
especialesPower

métodos
utilizarSpecialPower()
putOnSuit() (comportamiento)

subclases
(más específicas)
panterahombre
hombrehuevofrito Métodos
utilizar potencia especial()
primordiales

ponerEnTraje()

FriedEggMan no necesita ningún comportamiento que sea


único, por lo que no anula ningún método. Los métodos y
variables de instancia en SuperHero son suficientes.
PantherMan, sin embargo, tiene requisitos específicos para su traje y
poderes especiales, por lo que y
ambos son anulados en PantherMan
clase.
Las variables de instancia no se anulan porque no es necesario. No definen
ningún comportamiento especial, por lo que una subclase puede dar a una
variable de instancia heredada cualquier valor que elija. PantherMan puede
establecer su color morado heredado, mientras que a
FriedEggMan lo establece en blanco.

168 capítulo 7
Machine Translated by Google

herencia y polimorfismo

Un ejemplo de herencia:
Heredé mis
Doctor de clase pública { procedimientos, así que
no me molesté en estudiar medicina.
trabajos booleanos en el hospital; Relájate, esto no te dolerá nada.
(Ahora, ¿dónde puse esa
tratamiento vacíoPaciente() { sierra eléctrica...?)
// realizar un chequeo

}
}

clase pública FamilyDoctor extiende Doctor {

booleano haceHouseCalls; void


darAdvice() { // dar consejos
caseros
}

Cirujano de clase pública extiende Doctor{

void treatPatient() { // realizar cirugía

void makeIncision() { // hacer la


incisión (¡ay!)
}
}

superclase
Afila tu lápiz
Doctor
¿Cuántas variables de instancia tiene
trabajaEnElHospital
una variable de instancia
Cirujano?

tratar al paciente () un método ¿Cuántas variables de instancia tiene


FamilyDoctor?

¿Cuántos métodos tiene Doctor?


subclases
¿Cuántos métodos tiene el Cirujano?

¿Cuántos métodos tiene FamilyDoctor?


Cirujano Médico de familia
Agrega una nueva
Anula el método heredado hace llamadas a domicilio
variable de instancia
TreatPatient() tratar al paciente ()
¿Puede un médico de familia tratar al paciente ()?
dar consejos () Agrega un nuevo método
Agrega un nuevo método hacerIncisión()
¿Puede un FamilyDoctor hacer makeIncision()?

usted está aquí 169


Machine Translated by Google

diseñando para la herencia

Diseñemos el árbol de herencia para un


programa de simulación de animales.

1 Busque objetos que tengan atributos y


comportamientos comunes.

¿Qué tienen estos seis tipos en


común? Esto le ayuda a abstraer
comportamientos. (paso 2)

¿Cómo se relacionan estos tipos? Esto


le ayuda a definir las relaciones del
árbol de herencia (paso 4­5)

170 capítulo 7
Machine Translated by Google

herencia y polimorfismo

Usar la herencia para


evitar duplicar código en subclases
2
Diseñe una clase que represente
el estado y el comportamiento común.

Todos estos objetos son animales, por lo


que crearemos una superclase común
llamada Animal.

Pondremos métodos y variables de


instancia que todos los animales puedan
necesitar.

Animal
imagen
límites
del
hambre
alimentaria ubicación

hacer ruido()

comer()
dormir() deambular()

León
tamaño

Lobo
de la imagen

de la comida tamaño

presa de la imagen

de la comida
Gato
presa
Tigre tamaño
Hipopótamo
tamaño
de la imagen
tamaño
de la imagen Perro de la comida
de la imagen
de la comida tamaño presa
de la comida
presa de la imagen
presa
de la comida

presa

usted está aquí 171


Machine Translated by Google

diseñando para la herencia

¿Todos los animales comen de la misma manera?

3 Decida si una subclase


necesita comportamientos
(implementaciones de métodos) que sean
específicos de ese tipo de subclase en particular.

¿Qué métodos deberíamos anular? Mirando la clase Animal,


decidimos que eat() y
makeNoise() deben ser anulados por
las subclases individuales.

En la
comunidad canina, el ladrido
es una parte importante de nuestra
Soy un herbívoro identidad cultural. Tenemos un sonido
muy malo. único y queremos que esa diversidad
sea reconocida y respetada.

Animal
imagen
alimento

hambre
límites Es mejor que anulemos estos dos métodos, eat() y
ubicación makeNoise(), para que cada tipo de animal pueda definir
su propio comportamiento específico para comer y hacer
hacer ruido() ruido. Por ahora, parece dormir() y
comer() roam() puede seguir siendo genérico.

dormir()
vagar()

172 capítulo 7
Machine Translated by Google

herencia y polimorfismo

Buscando más oportunidades


de herencia 4
Busque más oportunidades para utilizar la
abstracción, encontrando dos o más que
subclases puedan necesitar elementos comunes.
comportamiento.

Observamos nuestras clases y vemos


que el Lobo y el Perro pueden tener algún
comportamiento en común, y lo mismo ocurre con
el León, el Tigre y el Gato.

Animal
imagen
alimento

hambre
límites
ubicación

hacer ruido()
comer()

dormir()
vagar()
Hmmm... Me pregunto tal vez y el perro son ambos caninos...
El lobo
si León, Tigre y Gato hay algo que AMBASeso
tendrían algo en común. clases podrían usar...

León
tamaño
Lobo
imagen
alimento tamaño
hacer ruido()
presa
comer() imagen
alimento
hacer ruido()
Gato
presa
comer()
Tigre tamaño
Hipopótamo
tamaño imagen
tamaño
imagen Perro alimento
imagen hacer ruido()
alimento presa
alimento hacer ruido() tamaño
comer()
hacer ruido() presa imagen
comer()
presa
comer() alimento
hacer ruido()
presa
comer()

usted está aquí 173


Machine Translated by Google

diseñando para la herencia

5 Terminar la jerarquía de clases


Dado que los animales ya tienen una jerarquía Animal
organizacional (todo el reino, género, phylum),
podemos usar el nivel que tenga más sentido para el imagen
diseño de clases. Usaremos las “familias” biológicas límites

para organizar los animales creando una clase Felina del


y una clase Canina. hambre
alimentaria ubicación
Decidimos que los caninos podrían usar un método
roam() común, porque tienden a moverse en manadas. hacer ruido()
También vemos que los felinos podrían usar un método
roam() común, porque tienden a evitar a otros de su comer()
propia especie. Dejaremos que Hippo continúe usando su dormir() deambular()
método roam() heredado, el genérico que obtiene de
Animal.
Así que por ahora hemos terminado con el diseño;
Volveremos a ello más adelante en el capítulo.

Felino

Canino

vagar()

Hipopótamo

vagar()
tamaño

imagen comida
makeNoise() presa
comer()
León
tamaño

imagen
comida
makeNoise() presa
comer()

Perro
Gato

tamaño
Tigre
tamaño
imagen comida
imagen comida Lobo makeNoise() presa
comer()
tamaño
makeNoise() presa comer() tamaño
imagen comida
imagen
makeNoise() presa comer() comida
makeNoise() presa
comer()

174 capítulo 7
Machine Translated by Google

herencia y polimorfismo

¿Qué método se llama?

Animal

hacer ruido()

comer()
dormir() deambular()
Hacer una nueva Lobo w = nuevo Lobo();
Objeto lobo

llama a la versión en Wolf [Link]();

Canino
llama a la versión en Canine [Link]();

vagar()
llama a la versión en Wolf comer();

llama a la versión en Animal [Link]();

Lobo

tamaño
makeNoise() imagen comer() comida
presa

usted está aquí 175


Machine Translated by Google

Practica el diseño de un árbol de herencia.

Dibuja un diagrama de herencia aquí.

no existen
Preguntas tontas

176 capítulo 7
Machine Translated by Google

herencia y polimorfismo

Usando IS­A y HAS­A

¿Tiene sentido decir que una

bañera es un baño? ¿O una bañera


IS­A para baño? Bueno, no es así

a mí. La relación entre mi Tina y mi Baño es


HAS­A. Baño TIENE Tina. Eso significa que
el baño tiene una variable de instancia
de bañera.

Bañera

tamaño entero;

Baño Burbujas b;

Bañera de hidromasaje;
Burbujas
Hundirse el fregadero;
radio interno;

int colorAmt;

Baño HAS­A Bañera y Bañera HAS­A Burbujas.


Pero nadie hereda (extiende) a nadie más.

usted está aquí 177


Machine Translated by Google

explotando el poder de los objetos

¡Pero espera! ¡Hay más!

Si la clase B extiende la clase A, la clase B ES­A clase A.


Esto es cierto en cualquier parte del árbol de herencia. Si la clase C
extiende la clase B, la clase C pasa la prueba IS­A para ambos B
y A.

Canino extiende Animal Animal

Lobo extiende canino hacer ruido()

Lobo extiende Animal comer()


dormir() deambular()

Canino ES­Un animal

Lobo es un canino
Canino
El lobo es un animal

vagar()

Lobo

tamaño
makeNoise() imagen comer() comida
presa

178 capítulo 7
Machine Translated by Google

herencia y polimorfismo

hazlo pegado

¿Cómo saber si has


acertado con tu herencia?

Marque las relaciones que


tener sentido.

El horno extiende la cocina


¡Tenga en cuenta que la relación
de herencia IS­A funciona en una única Guitarra extiende instrumento

dirección! uno
Persona extiende Empleado

Ferrari amplía el motor

FriedEgg amplía la comida

Beagle extiende mascota

El contenedor extiende el tarro.

El metal extiende el titanio.

GratefulDead amplía banda

Rubia extiende Inteligente

La bebida amplía el Martini

Consejo: aplique la prueba IS­A

usted está aquí 179


Machine Translated by Google

quien hereda que

no existen
Preguntas tontas

súper

esto llama a la versión heredada de


itinerancia pública vacía () { roam(), luego regresa para hacer
[Link]();
// mis propias cosas deambulando
su propio código específico de subclase
}

¿Quién se queda con el Porsche y quién con la porcelana? Los niveles de acceso controlan quién ve qué y son cruciales
(cómo
(cómo saber
saber qué
qué puede
puede hacer una
heredar subclase
una a tener un código Java robusto y bien diseñado. Por ahora vamos a
subclasededesususuperclase)
heredar superclase) centrarse sólo en lo público y lo privado. Las reglas son simples para
esos dos:

Una subclase hereda miembros de la los miembros públicos se heredan


superclase. Los miembros incluyen instancia. los miembros privados no se heredan
variables y métodos, aunque más adelante
En este libro veremos otros miembros heredados. A
Cuando una subclase hereda un miembro, es como si el
La superclase puede elegir si quiere o no una
La subclase definió el miembro mismo. En la forma
subclase para heredar un miembro particular por el nivel de
Por ejemplo, Square heredó el y
acceso que se le otorga al miembro en particular.
métodos y al mundo exterior (otros
Hay cuatro niveles de acceso que cubriremos en este libro. código) la clase Square simplemente tiene un y
Pasando del más restrictivo al menos restrictivo, los cuatro accesos método.
los niveles son: Los miembros de una clase incluyen las variables y
métodos definidos en la clase más cualquier cosa heredada
predeterminado privado protegido público
de una superclase.

Nota: obtenga más detalles sobre default y protected en el capítulo


16 (implementación) y el apéndice B.

180 capitulo 7
Machine Translated by Google

herencia y polimorfismo

Al diseñar con herencia,


¿Estás usando o abusando?

HACER

HACER
PUNTOS DE VIÑETA

Una subclase extiende una superclase.

Una subclase hereda todas las variables y


métodos de instancia públicos de la superclase, pero
no hereda las variables y métodos de instancia
privados de la superclase.

Los métodos heredados se pueden anular; las


variables de instancia no se pueden anular (aunque
se pueden redefinir en la subclase, pero eso no
es lo mismo y casi nunca es necesario hacerlo).

Utilice la prueba IS­A para verificar que


su jerarquía de herencia sea válida. Si X extiende a
Y, entonces X ES­A Y debe tener sentido.
NO
La relación IS­A funciona en una sola dirección.
Un hipopótamo es un animal, pero no todos los
animales son hipopótamos.

Cuando se anula un método en una subclase y ese


método se invoca en una instancia de la subclase,
se llama a la versión anulada del método. (El más
bajo gana).

Si la clase B extiende a A y C extiende a B, la clase


B ES­A clase A, y la clase C ES­A clase B, y la clase
C también ES­A clase A.
NO

usted está aquí 181


Machine Translated by Google

explotando el poder de los objetos

Entonces, ¿qué te
aporta realmente toda esta herencia?

1 Evitas el código duplicado.

Coloque el código común en un solo lugar


y deje que las subclases hereden ese código
de una superclase. Cuando quieras cambiar ese
comportamiento, tienes que modificarlo en
un solo lugar y todos los demás (es decir, todas
las subclases) verán el cambio.

2 Defines un común
Protocolo para un grupo de clases.

Um, ¿qué
diablos significa
ESO?

182 capítulo 7
Machine Translated by Google

herencia y polimorfismo

La herencia le permite garantizar que todas las


clases agrupadas bajo un determinado
supertipo tengan todos los métodos que tiene el
supertipo.* En otras
palabras, define un protocolo común para un Y me importa porque...
conjunto de clases relacionadas mediante herencia.

Lo cual me importa porque...

Animal
Le estás diciendo al mundo que
Y eso significa para mí...
hacer ruido() cualquier animal puede hacer estas
comer()
cuatro cosas. Eso incluye los argumentos
dormir()
vagar() del método y los tipos de retorno.

*Cuando decimos “todos los métodos” nos referimos a “todos los métodos heredables ”, que
por ahora en realidad significa “todos los métodos públicos ”, aunque más adelante refinaremos
esa definición un poco más.

usted está aquí 183


Machine Translated by Google

cómo funciona el polimorfismo

Los 3 pasos de la
declaración y asignación de objetos.

1 2
Para ver cómo funciona el polimorfismo, 3
tenemos que dar un paso atrás y observar la Perro miPerro = nuevo Perro();
forma en que declaramos una
normalmente referencia.
y crear un objeto... 1
Declarar una variable de
referencia

Perro miPerro = nuevo Perro();

Mi perro

Perro

2 Crea un objeto

Perro miPerro = nuevo Perro();

Objeto de perro

3 Vincular el objeto y
la referencia

perro mi perro = nuevo Perro();

Objeto de perro

Mi perro

Perro

184 capítulo 7
Machine Translated by Google

herencia y polimorfismo

El punto importante es que el tipo de


referencia Y el tipo de objeto son los
mismos.
En este ejemplo, ambos son Perro.

Mi perro
Doh bj miCt
gramo
oh

Perro

Estos dos son del mismo tipo. El tipo de variable


de referencia se declara como Perro y el objeto se
crea como nuevo Perro().

Pero con el polimorfismo, la referencia y el


objeto pueden ser
diferente .
Animal miPerro = nuevo Perro();

Mi perro
Doh bj miCt
gramo
oh

Animal

Estos dos NO son del mismo tipo. El tipo


de variable de referencia se declara como
Animal, pero el objeto se crea como nuevo Perro().

usted está aquí 185


Machine Translated by Google

polimorfismo en acción

Con polimorfismo, el tipo de referencia


puede ser una superclase del tipo de
objeto real. eh... no.
Todavía no lo entiendo.

Declarar una matriz de tipo Animal. En otras palabras,


Vale, vale, tal vez un ejemplo ayude.
una matriz que contendrá objetos de tipo Animal.

Animal[] animales = nuevo Animal[5];

animales [0] = nuevo Perro();

animales [1] = nuevo Gato();


Pero mira lo que puedes hacer... ¡puedes poner CUALQUIER subclase
de Animal en la matriz Animal!
animales [2] = nuevo Lobo();

animales [3] = nuevo hipopótamo();

animales [4] = nuevo León();


razón
Y aquí está la mejor parte polimórfica (la
(d'être para todo el ejemplo),
puedes recorrer la matriz de y llama a uno
for (int i = 0; i < [Link]; i++) {
los métodos de la clase Animal, ¡y
cada objeto hace lo correcto!

animales[yo].comer();

Cuando 'i' es 0, un Perro está en el índice 0 en la matriz, por lo que obtienes

animales[i].vagar(); el método eat() del Perro. Cuando 'i' es 1, obtienes el método eat() del gato

}
Lo mismo con deambular().

186 capítulo 7
Machine Translated by Google

herencia y polimorfismo

¡Pero espera! ¡Hay más!

Puede tener argumentos


polimórficos y tipos de retorno.

a
clase veterinaria {

darShot vacío público (Animal a) {

// hacerle cosas horribles al animal en El parámetro Animal puede tomar


CUALQUIER tipo de Animal como Y cuando
// el otro extremo del parámetro 'a'
argumento. el veterinario termina de aplicar la
[Link](); inyección, leestá
Realmente diceahí
al animal que haga ruido (), y cualquier animal
el montón, eso es
} quién se ejecutará el método makeNoise().

clase propietario de mascota {

inicio público vacío() { El método GiveShot() del veterinario puede aceptar


cualquier animal que le des. Siempre que el
Veterinario v = nuevo Veterinario();
objeto que pase como argumento sea una subclase de
Perro d = nuevo Perro(); Animal, funcionará.

Hipopótamo h = nuevo hipopótamo();


Se ejecuta makeNoise() del perro
[Link](d);

[Link](h); Se ejecuta makeNoise() de Hippo

usted está aquí 187


Machine Translated by Google

explotando el poder del polimorfismo

¡Ahora lo entiendo! Si escribo mi

código usando argumentos polimórficos, donde declaro

el parámetro del método como un tipo de superclase, puedo

pasar cualquier objeto de subclase en tiempo de ejecución. Fresco. Porque

eso también significa que puedo escribir mi código, irme de vacaciones y

alguien más puede agregar nuevos tipos de subclases al programa y mis

métodos

todavía trabajo... (el único inconveniente es que sólo estoy haciendo la vida

más fácil para ese idiota de Jim).

Con el polimorfismo, puedes escribir código que no


tenga que cambiar cuando introduces nuevos tipos
de subclases en el programa.

188 capítulo 7
Machine Translated by Google

herencia y polimorfismo

no existen
Preguntas tontas

privado

público

final

final

privado

usted está aquí 189


Machine Translated by Google

métodos primordiales

Mantener el contrato: reglas para anular

Aparato

activación booleana()

apagado booleano()

Tostadora

activación booleana (nivel int)

¡Esto NO es una anulación!

¡No se pueden
cambiar los
argumentos en un método primordial!

En realidad, esto es una


sobrecarga legal, pero no
una SOBRERIDE.
1 Los argumentos deben ser los mismos y los tipos de
devolución deben ser compatibles.
El contrato de superclase define cómo otro código puede utilizar un método.
Cualquiera que sea la superclase que tome como argumento, la subclase
que anula el método debe usar ese mismo argumento. Y cualquier cosa que
la superclase declare como tipo de retorno, el método primordial debe declarar Aparato
el mismo tipo o un tipo de subclase. Recuerde, se garantiza que un objeto de
subclase podrá hacer cualquier cosa que declare su superclase, por lo que es activación booleana pública()
seguro devolver una subclase donde se espera que se encuentre la superclase.
activación booleana pública()

2 El método no puede ser menos accesible.


Eso significa que el nivel de acceso debe ser el mismo o más amigable. Eso
significa que no puedes, por ejemplo, anular un método público y convertirlo en
privado. Qué shock sería para el código que invoca lo que (en tiempo de
piensa compilación) es un método público, si de repente en tiempo de ejecución
¡ILEGAL! Tostadora
¡La JVM cerró la puerta de golpe porque la versión principal llamada en tiempo
de ejecución es privada! No es una
anulación legal
Hasta ahora hemos aprendido acerca de dos niveles de acceso: privado y público. encendido booleano privado()
porque restringiste el
Los otros dos se encuentran en el capítulo de implementación (Liberar su código) y
nivel de acceso.
en el apéndice B. También hay otra regla sobre anulación relacionada con el manejo
Tampoco es una
de excepciones, pero esperaremos hasta el capítulo sobre excepciones
(Comportamiento riesgoso) para cubrir eso. sobrecarga legal,
porque no cambiaste argumentos.

190 capítulo 7
Machine Translated by Google

herencia y polimorfismo

Sobrecargar un método

Un método sobrecargado
es simplemente un método
diferente que tiene el
mismo nombre de método. No
tiene nada que ver con la
herencia y el polimorfismo. Un
método sobrecargado NO es
lo mismo que un método anulado.

1 Los tipos de devolución pueden ser Ejemplos legales de sobrecarga de


diferentes. métodos:
Eres libre de cambiar los tipos de retorno en Sobrecargas de clase pública {
métodos sobrecargados, siempre que las listas de argumentos
sean diferentes. Cadena ID única;

public int addNums(int a, int b) {


2 No puedes cambiar SÓLO el tipo de
devolver a + b;
devolución. }
Si solo el tipo de retorno es diferente, no es una
sobrecarga válida; el compilador asumirá que estás public double addNums(doble a, doble b) {
intentando anular el método. E incluso eso no será legal a devolver a + b;
menos que el tipo de devolución sea un subtipo del tipo }
de devolución declarado en la superclase. Para
sobrecargar un método, DEBE cambiar la lista de public void setUniqueID(String theID) {
argumentos, aunque puede // mucho código de validación y luego:
cambie el tipo de devolución a cualquier cosa. ID único = el ID;
}

3 Varías lospoder
niveles de acceso en setUniqueID vacío público (int ssNumber) {
“”
cualquier dirección. Cadena numString = + ssNumber;
setUniqueID(numString);
Eres libre de sobrecargar un método con un método que sea
}
más restrictivo. No importa, ya que el nuevo método no está
}
obligado a cumplir el contrato del método sobrecargado.

usted está aquí 191


Machine Translated by Google

ejercicio: mensajes contradictorios

fijo
esge
a = 6; 56
segundo 11
= 5; a = 5; sesenta y cinco

el programa:

clase A { clase C extiende B { void


intivar = 7; m3()
void m1() { [Link](“C's m3, “+(ivar + 6));
{ [Link](“A's m1, “); }
} }
void m2()
{ [Link](“A's m2, “); clase pública Mixta2 {
} público estático vacío principal (String [] argumentos) {
vacío m3() { A a = nueva A();
[Link](“A's m3, “); B b = nuevo B();
} Cc = nuevo C();
} A a2 = nuevo C(); El código
candidato va aquí.
la clase B extiende A {
(tres líneas)
void m1()
{ [Link](“B's m1, “);
} }
} }

b.m1();

}
producción:
c.m2();
candidatos de código:
a.m3(); A es m1, A es m2, C es m3, 6

m1 de B, m2 de A, m3 de A,

}
c.m1();
c.m2(); A es m1, B es m2, A es m3,
c.m3();
B es m1, A es m2, C es m3, 13

}
a.m1();
M1 de B, m2 de C, m3 de A,
b.m2();
c.m3(); B es m1, A es m2, C es m3, 6

}
a2.m1(); A es m1, A es m2, C es m3, 13
a2.m2();
a2.m3();

192 capítulo 7
Machine Translated by Google

herencia y polimorfismo

¿Cuál de los pares AB de métodos enumerados a la derecha,


si se insertara en las clases de la izquierda, compilaría y
produciría el resultado que se muestra? (El método A insertado
en la clase Monstruo, el método B insertado en la clase Vampiro).

clase pública MonsterTestDrive {


miedo booleano (int d) {
público estático vacío principal (String [] argumentos) { 1
[Link](“arrrgh”);
Monstruo [] ma = nuevo Monstruo[3]; A
devolver verdadero;
ma[0] = nuevo Vampiro(); }
ma[1] = nuevo Dragón(); miedo booleano (int x) {
ma[2] = nuevo Monstruo(); B [Link](“¿un bocado?”);

para(int x = 0; x < 3; x++) { falso retorno;

ma[x].asustar(x); }

}
miedo booleano (int x) {
} 2
[Link](“arrrgh”);
}
A
devolver verdadero;

clase monstruo { } int asustar(int f) {

B [Link](“¿un bocado?”);
A devolver 1;

} }

miedo booleano (int x) {


clase Vampiro extiende Monstruo { 3
[Link](“arrrgh”); falso retorno;
A
B
}
} susto booleano (int x) {
[Link](“¿un bocado?”);
B
clase Dragón extiende Monstruo { devolver verdadero;
miedo booleano (int grado) { }

[Link](“aliento de fuego”);
devolver verdadero; miedo booleano (int z) {
4
[Link](“arrrgh”);
} A
Ventana
Ayuda dede
la edición
ventanade
dearchivos
edición Ayuda Suspender
de archivos SaveYourself devolver verdadero;
}
% java
java TestArrays % ¿un
MonsterTestDrive
bocado?
isla = Fiji aliento } miedo booleano (byte b) {
=deCozumel
fuego isla arrrgh isla B [Link](“¿un bocado?”);
Bermuda
= isla = Azores devolver verdadero;
}

usted está aquí 193


Machine Translated by Google

rompecabezas: rompecabezas de piscina

Rompecabezas de piscina

bote de remos de clase pública ________ ________ { barcos de prueba de clase pública {

público ___________ filaElBarco() { ______ ______ _______ principal(Cadena[] argumentos){

[Link](“golpe de natasha”); _________ b1 = barco nuevo();

} Velero b2 = nuevo __________();


}
Bote de remos ________ = nuevo bote de remos();
clase pública ________ { [Link](32);
privado __________ ;
b1.__________();
_______ vacío _________ ( ______ ){
b3.__________();
longitud = longitud; _______.mover();
} }
público int getLength() { }

________ _________ ; clase pública __________ ________ Bote {

} público _______ _________() {

público ___________ mover() { [Link](“___________”);

[Link](“___________”); }
}
}
}
vela de deriva a la deriva

194 capítulo 7
Machine Translated by Google

herencia y polimorfismo

El conjunto 1 funcionará.

El conjunto 2 no se compilará debido al tipo de retorno de


Vampire (int).

El método asustar() del Vampiro (B) no es una anulación O


sobrecarga legal del método asustar() del Monstruo.
Cambiar SÓLO el tipo de retorno no es suficiente para realizar una
sobrecarga válida y, dado que un int no es compatible con un
booleano, el método no es una anulación válida. (Recuerde, si cambia SÓLO
el tipo de devolución, debe ser a un tipo de devolución que sea compatible
con el tipo de devolución de la versión de superclase, y luego es una
anulación.

Los conjuntos 3 y 4 se compilarán, pero producirán:

arrrgh
aliento de fuego

arrrgh

Recuerde, la clase Vampiro no anula el método asustar()


de la clase Monstruo. (El método asustar() en el conjunto 4
de Vampire toma un byte, no un int.)

b.m1();

}
candidatos de código: producción:
c.m2();
a.m3(); A es m1, A es m2, C es m3, 6

fijo m1 de B, m2 de A, m3 de A,

}
c.m1();
c.m2();
esge c.m3();
A es m1, B es m2, A es m3,

B es m1, A es m2, C es m3, 13


a.m1();
M1 de B, m2 de C, m3 de A,
b.m2();

}
c.m3(); B es m1, A es m2, C es m3, 6

a2.m1(); A es m1, A es m2, C es m3, 13


a2.m2();
a2.m3();

usted está aquí 195


Machine Translated by Google

respuestas del rompecabezas

bote de remos de clase pública extiende bote {

fila vacía públicaElBot () {

[Link](“golpe de natasha”);

}
}

barco de clase pública {

longitud interna privada ;

setLength vacío público ( int len ) {


longitud = longitud;
}

público int getLength() {

longitud de retorno ;
}

movimiento vacío público () {

[Link](“deriva ”);

}
}

barcos de prueba de clase pública {

principal vacío estático público (String [] argumentos) {


Barco b1 = nuevo Barco();

Velero b2 = nuevo Velero();

Bote de remos b3 = nuevo Bote de remos();

[Link](32);

[Link]();

[Link]();

[Link]();

}
}

clase pública Velero extiende Barco {

movimiento vacío público () {

[Link](“izar vela ”);

}
}

vela de deriva a la deriva

196 capítulo 7
Machine Translated by Google

8 interfaces y clases abstractas.

Polimorfismo grave

La herencia es sólo el comienzo.

este es un nuevo capitulo 197


Machine Translated by Google

diseñando con herencia

¿Nos olvidamos de algo


cuando diseñamos esto? Animal
imagen
límites
del
hambre
alimentaria ubicación

hacer ruido()

comer()
dormir() deambular()

Felino

Canino

vagar()
Hipopótamo

vagar()
tamaño

imagen comida
makeNoise() presa
comer()

León
tamaño

imagen
comida
makeNoise() presa
comer()

Perro

Gato
tamaño
tamaño
Tigre imagen comida
de la imagen
Lobo makeNoise() presa
comer()
de la comida
makeNoise() presa
tamaño
tamaño come()
imagen
imagen comida
comida
makeNoise() presa comer() makeNoise() presa
comer()

198 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Sabemos que podemos decir:

Lobo aLobo = nuevo Lobo();

un lobo

Una referencia de Wolf a un [Link] F oh j mi


b
Connecticut
yo

objeto Wolf. Lobo

Estos dos son del mismo tipo.

Y sabemos que podemos decir:

Animal aHippo = nuevo hipopótamo();

un hipopótamo

Referencia animal a un
hi pag
bj mi
Connecticut

objeto hipopótamo. pag


oh oh
Animal

Estos dos NO son del mismo tipo.

Pero aquí es donde se pone raro:

Animación animal = nuevo Animal();

Referencia animal a un
animado ?
objeto animal. Ai Ct
a ohbj mi
norte
metro yo

Animal

Estos dos son del mismo tipo, pero...

¿Cómo diablos se ve un objeto Animal?

usted está aquí 199


Machine Translated by Google

cuando los objetos van mal

¿Cómo es un nuevo objeto Animal()?


mirar

objetos aterradores

¿Cuáles son los valores de las variables de instancia?

¡Algunas clases simplemente deberían no ser


crear instancias!

abstracto

clase abstracta Canino extiende Animal {

nuevo itinerancia pública vacía () {}


abstracto }

200 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

El compilador no te permitirá crear una instancia


de una clase abstracta.

clase pública abstracta Canino extiende Animal {

itinerancia pública vacía () {}

clase pública MakeCanine {


Esto está bien, porque siempre puedes asignar
vacío público ir () {
un objeto de subclase a una referencia de
Canino c; superclase, incluso si la superclase es abstracta.

c = nuevo Perro();

c = nuevo Canino();
entonces

[Link](); la clase Canino está marcada como abstracta,

} el compilador NO te permitirá hacer esto.

}
Ayuda de la ventana de edición de archivos BeamMeUp

% javac [Link]

[Link]: Canine es abstracto; no se puede crear una instancia

c = nuevo Canino();
^

1 error

Una clase abstracta prácticamente* no tiene utilidad, valor ni


extendido
propósito en la vida, a menos que sea .

Con una clase abstracta, los chicos que hacen el trabajo en tiempo de
subclase
ejecución son instancias de su clase abstracta.

*Existe una excepción a esto: una clase abstracta puede tener


miembros estáticos (consulte el capítulo 10).

usted está aquí 201


Machine Translated by Google

clases abstractas y concretas

Abstracto versus concreto abstracto


Animal

abstracto
Canino
concreto
Hipopótamo

abstracto
Felino concreto
Perro

concreto concreto
Gato
Lobo
concreto concreto
León

Tigre

¿abstracto o concreto?

Mmmm... ¿lo hago?


Mmmm... el Camelot
sentirse rojo o
Vineyards 1997 Pinot
blanco esta noche? Noir fue un año
bastante decente...

202 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Métodos abstractos

Realmente apesta
ser un método abstracto.

No tienes cuerpo.

¡Un método abstracto no tiene cuerpo!

comer vacío abstracto público ();

¡Sin cuerpo de método!


Termine con un punto y coma.

Si declara un resumen, marque el método método , DEBES abstraer


abstracto en clase también. no puedes tener
una clase no abstracta.

no existen
Preguntas tontas

usted está aquí 203


Machine Translated by Google

debes implementar métodos abstractos

DEBES implementar todos los métodos abstractos

Tengo una maravillosa


noticia, madre. ¡Joe finalmente
implementó todos sus métodos abstractos! Ahora
todo está funcionando tal como lo
planeamos...

Implementar un método
abstracto es como un
primordial método.

204 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Afila tu lápiz

simulación de campo de golf aplicación de vivero de árboles

solicitud de arquitecto

aplicación de fotografía satelital

aplicación de entrenamiento

usted está aquí 205


Machine Translated by Google

ejemplos de polimorfismo

Polimorfismo en acción

Construyendo nuestra propia lista específica para


perros (quizás el peor intento del mundo de crear
nuestra propia clase ArrayList, desde cero).

Utilice una matriz de perros antigua y


1 clase pública MiListaDePerros {
sencilla detrás de escena.
perro privado [] perros = nuevo perro [5];
Mi lista de perros

privado int nextIndex = 0; Incrementaremos esto cada vez


perro[] perros
int índice siguiente que se agregue un nuevo Perro.

agregar(Perro d)
agregar vacío público (Perro d) {
Si aún no estamos en el límite de la matriz
if (nextIndex <[Link]) { de perros, agregue el Perro e imprima un
mensaje.
perros[nextIndex] = d;

[Link](“Perro agregado en + índicesiguiente);

siguienteIndex++;

}
incremento, para darnos el el
siguiente índice a usar
}
}

206 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Uh­oh, ahora también debemos conservar a Cats.

Construyendo nuestra propia lista específica de animales


No entrar en pánico. No vamos a crear
un nuevo objeto Animal; Estamos creando
clase pública MiListaAnimal {
un nuevo objeto de matriz, de tipo Animal.

2 animal privado[] animales = nuevo animal[5]; (Recuerde, no puede crear una nueva
privado int nextIndex = 0; instancia de un tipo abstracto, pero PUEDE
Mi lista de animales
agregar vacío público (Animal a) {
crear un objeto de matriz declarado
para MANTENER ese tipo).
if (siguienteÍndice <[Link]) {
animales[] animales
int índice siguiente animales[nextIndex] = a;

[Link](“Animal agregado en nextIndex++; + índicesiguiente);
agregar(Animal a)

}
}
}

clase pública AnimalTestDrive{


público estático vacío principal (String[] args) {
Lista MyAnimalList = nueva MyAnimalList();
Perro a = nuevo Perro();
Gato c = nuevo gato();
[Link](a);
[Link](c);
}
}
Ventana de edición de archivos Ayuda Daño

% java AnimalTestDrive

Animal agregado en 0

Animal agregado en 1

usted está aquí 207


Machine Translated by Google

la superclase definitiva: Objeto

¿Qué pasa con los no animales? ¿Por qué no crear una clase
lo suficientemente genérica como para tomar cualquier cosa?

(Estos son sólo algunos de


los métodos de ArrayList...
3 hay muchos más).

Cada clase en Java extiende la


clase Objeto.

Muchos de los métodos ArrayList utilizan el


tipo polimórfico definitivo, Object. Dado que
perro de clase pública extiende Objeto { }
cada clase en Java es una subclase de Object,
¡estos métodos ArrayList pueden aceptar cualquier cosa!

(Nota: a partir de Java 5.0, los métodos get() y


add() en realidad se ven un poco diferentes a
los que se muestran aquí, pero por ahora esta es
Cualquier clase que no explícitamente extender otro
clasifique,implícitamente
extiende Object. la forma de pensarlo. Nos adentraremos un poco
en la historia completa. más tarde.)

208 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Entonces, ¿qué hay en este Objeto ultrasupermegaclase?

Objeto

booleano es igual()

Clase obtenerClase() Sólo ALGUNOS de los métodos


int código hash()
de la clase Objeto.
Cadena a Cadena()

Tuclaseaquí Cada clase que escribes hereda todos


los métodos de la clase Objeto. Las
clases que has escrito heredaron métodos
que ni siquiera sabías que tenías.

1 es igual a (Objeto o)
3 código hash()
Perro a = nuevo Perro();
Gato c = nuevo gato(); Gato c = nuevo gato();
[Link]([Link]());
si ([Link] igual a (c)) { Menú desplegable de ayuda de la ventana de edición de archivos

[Link](“verdadero”); Imprime un código hash


} demás { % objeto de prueba java
para el objeto (por ahora,
[Link](“falso”);
}
8202111 considérelo como una

identificación única).
Ventana de edición de archivos Ayuda Detener

% objeto de prueba java Le indica si dos objetos se


FALSO
consideran "iguales" (hablaremos
de lo que realmente significa 4 a Cadena()
"igual" en el apéndice B). Gato c = nuevo gato();
[Link]([Link]());

Ayuda de la ventana de edición de archivos LapseIntoComa

% objeto de prueba java


2 obtenerClase()
Gato@7d277f
Gato c = nuevo gato();
[Link]([Link]());

Ayuda de la ventana de edición de archivos débil


Imprime un mensaje de cadena
Le devuelve la clase con el nombre de la clase y algún
% objeto de prueba java
desde la que se creó la
otro número que rara vez nos
clase gato instancia de ese objeto.
importa.

usted está aquí 209


Machine Translated by Google

Clases de objetos y abstractas.

no existen
Preguntas tontas

final

Objeto o = nuevo Ferrari();


[Link](); //¡Ilegal!

210 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Usar referencias polimórficas de tipo Objeto tiene un precio...

Haga una ArrayList declarada para


ArrayList<Perro> myDogArrayList = nueva ArrayList<Perro>(); contener objetos Dog.
Haz un perro.
Perro aPerro = nuevo Perro();
Agrega el perro a la lista.
[Link](unPerro);
Asigne el Perro de la lista a una nueva variable de referencia de Perro.
Perro d = [Link](0); (Piense en ello como si el método get() declarara un tipo de retorno Perro

porque usó ArrayList<Dog>.)

Haga una ArrayList declarada para


ArrayList<Objeto> myDogArrayList = nuevo ArrayList<Objeto>(); contener cualquier tipo de Objeto.

Perro aPerro = nuevo Perro(); Haz un perro.


(Estos dos pasos son iguales).
[Link](unPerro); Agrega el perro a la lista.

Perro d= = [Link](0);
myD d=m ¡¡NO!! ¡¡No se compilará!! Cuando usas ArrayList<Object>, el método get() d
devuelve tipo Objeto. ¡El compilador solo sabe que el objeto hereda de
Object (en algún lugar de su árbol de herencia) pero no sabe que es un perro!

Los objetos entran


como SoccerBall, Los objetos salen de un
Fish, Guitar y Car. ArrayList<Object> que actúa
como si fueran instancias
genéricas de la clase Object.
El compilador no puede asumir
ListaMatriz<Objeto> que el objeto que sale es
de cualquier tipo que no sea
Pero salen como si Objeto.
fueran de tipo Objeto.

Objeto Objeto Objeto Objeto

usted está aquí 211


Machine Translated by Google

Cuando un perro pierde su carácter canino

Cuando un perro no actúa como un perro No sé de qué estás hablando.


¿Sentarse? ¿Permanecer?
¿ladrar? Mmmm... yo no

Recuerdo haberlos conocido.

vacío público ir () { ¡Esta línea no funcionará! Aunque el método


Perro aPerro = nuevo Perro(); devolvió una referencia al mismo Perro al que se
MALO
Perro mismoPerro ==getObject(unPerro);
gramo gramo refería el argumento, el tipo de retorno Objeto
significa que el compilador no le permitirá asignar la
}
referencia devuelta a nada más que a Objeto.

Objeto público getObject (Objeto o) {


volver o; Devolvemos una referencia al mismo Perro, pero como
} un tipo de retorno de Objeto. Esta parte es perfectamente
legal. Nota: esto es similar a cómo funciona el método get()
cuando tienes un ArrayList<Object> en lugar de un ArrayList<Dog>.

Ventana de edición de archivos Ayuda Recordar

El compilador no sabe que lo devuelto


[Link]: tipos incompatibles
por el método es en realidad un
encontrado: [Link]
Perro, por lo que no le permitirá
requerido: perro
asignarlo a una referencia de Perro.
Perro mismoPerro = tomarObjetos(unPerro); (Verás por qué en la página siguiente).
1 error ^

vacío público ir () {
Esto funciona (aunque puede que no sea
Perro aPerro = nuevo Perro();
muy útil, como verás en un momento) porque
BIEN Objeto mismoPerro = getObject(unPerro);
☺ puedes asignar CUALQUIER COSA a una referencia
}
de tipo Objeto, ya que cada clase pasa la prueba
IS­A para Objeto. Cada objeto en Java es una
Objeto público getObject (Objeto o) { instancia de tipo Objeto, porque cada clase en Java
volver o; tiene un Objeto en la parte superior de su árbol de herencia.

}
212 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Los objetos no ladran.

oh

Doh bj mi
gramo
oh
Connecticut

Objeto

Cuando obtiene una referencia de objeto de


ArrayList<Object> (o cualquier método que
declare Object como tipo de retorno), regresa
como un tipo de referencia polimórfica de
Object. Entonces tienes una referencia de
Objeto a (en este caso) una instancia de Perro.

Objeto o = [Link](index); Esto esta bien. El objeto de clase tiene


un método hashCode(), por lo que puede
int i = [Link](); llamar a ese método en CUALQUIER objeto en Java.

[Link]
[Link]();
¡No se compilará!
¡¡No puedo hacer esto!! La clase Object no tiene idea de
lo que significa ladrar(). Aunque USTED sabe que en
realidad es un perro en ese índice, el compilador no lo sabe.

código hash()
El compilador decide si se puede llamar a un
método basándose en el tipo, no en el tipo
real. referencia
oh
objeto
Doh bj mi
gramo
oh
Connecticut

Objeto
Objeto
El método que estás llamando a
es igual() una referencia DEBE estar en la clase
obtenerClase()
de ese tipo de referencia. No importa cuál
código hash()
sea el objeto real.
Encadenar()

[Link]();

La referencia "o" fue declarada como tipo


Objeto, por lo que puede llamar a métodos
solo si esos métodos están en la clase Objeto.

usted está aquí 213


Machine Translated by Google

los objetos son objetos

Me trata como a un

Objeto. Pero puedo hacer


mucho más... si tan solo él viera
yo por lo que yo en realidad soy.

Ponte en contacto con tu Objeto interior.

nueva tabla de snowboard()

Objeto

es igual() Un solo objeto


obtenerClase()
en el montón.
código hash()
()
dmi ttur
Encadenar()
r norte

()
sh ( ) has C
h oh
gramo

rit
norte

S d
mi
t oh (
mi )

snowboard
q Objeto
El snowboard hereda métodos tu
ayo ()
s() ass
gramo
mi
A
)
es igual()
de la superclase Objeto, y t yC yo
oh
yo(

agrega cuatro ir tr
gramo
obtenerClase()
más.
()
norte

Coh
código hash()
yo s
oh mi
Encadenar()

snowboard
doblar()

S miC
t
desgarrar() oh
norte
wboh ard obj
obtenerAire()

perder el control()

Aquí solo hay UN objeto en el montón. Un objeto de snowboard.


Pero contiene tanto las partes de sí mismo de la clase Snowboard
como las partes de sí mismo de la clase Objeto.

214 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

"Polimorfismo" significa "muchas formas".


Cuando colocas un
objeto en
Puedes tratar una tabla de snowboard como una ArrayList<Object>, puedes tratarlo
tabla de snowboard o como un objeto. solo como un Objeto,
independientemente del tipo
que era cuando lo colocaste.

Cuando obtienes una


referencia de un
ArrayList<Objeto>, la referencia
siempre es de tipo
Objeto .

Eso significa que obtienes un control


Objeto remoto.

()
dmi ttur
Snowboard s = nueva Snowboard(); r norte

()
h
s ( ) has C
h oh
gramo

rit
norte

Objeto o = s; S d
mi
t oh (
mi )
q Objeto
tu
ayo ()
s() ss
gramo
mi
A y Ca
)
t yo(

s
yo
oh
ir tr
gramo

()
norte

Coh
yo s
oh mi

snowboard
El mando a distancia Snowboard
S miC
t
(referencia) tiene más botones que un
menos métodos aquí... oh
norte
wboh ard obj
mando a distancia Object. El oh
control remoto de Snowboard puede
ver la Snowboardness completa del La referencia de Objeto solo puede ver las
partes del Objeto del objeto Snowboard.
objeto Snowboard. Puede acceder a
todos los métodos de Snowboard, Sólo puede acceder a los métodos de la
clase Objeto. Tiene menos botones que el
incluidos los métodos de objeto
mando a distancia de Snowboard.
heredados y los métodos de la clase Snowboard.

usted está aquí 215


Machine Translated by Google

objetos de fundición

Espera un momento... que bueno

¿Qué es un Perro si sale de un

ArrayList<Object> y no puede hacer ninguna Convertir una referencia de objeto a su tipo.


cosa de Perro? Tiene que haber un real
manera de hacer que el Perro vuelva a un
estado de Dogness...

oh

Doh bj mi
gramo
oh
Connecticut

Objeto
Espero que no duela.
¿Y qué tiene de malo seguir
siendo un Objeto? Vale, no puedo
buscarlo, claro, pero puedo dártelo.
un código hash realmente agradable.

Objeto o = [Link](index);
devolver el objeto a un perro
Perro d = (Perro) o; que sabemos que está allí.
[Link]();

oh

Doh bj migramo
oh
Connecticut

Objeto

Lanza el llamado 'Objeto' (pero


d
sabemos que en realidad es un Perro)
para escribir Perro, para que puedas
Perro
tratarlo como el Perro que realmente es.

en vez de

si (o instancia de Perro) {
Perro d = (Perro) o;
}

216 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Ahora has visto cuánto se preocupa Java por los


métodos en la clase de la variable de referencia.

Puede llamar a un método en un objeto, la clase de la solo si


variable de referencia tiene ese método.

Piense en los métodos públicos de su clase como su


contrato, su promesa al mundo exterior sobre las
cosas que puede hacer.

Cuenta
débito (doble cantidad)

crédito (cantidad doble)

doble obtenerSaldo()

usted está aquí 217


Machine Translated by Google

modificando un árbol de clases

¿Qué pasa si necesitas


cambiar el contrato?

Piensa en lo que TÚ harías si TÚ fueras el programador de

la clase Perro y necesitaras modificar el Perro para que

también pudiera hacer cosas de Mascotas. Sabemos que

simplemente agregar nuevos comportamientos (métodos)

de mascotas a la clase Perro funcionará y no romperá el

código de nadie más.

Pero... este es un programa de PetShop. ¡Tiene más


que solo perros! ¿Y qué pasa si alguien quiere usar
tu clase Perro para un programa que tiene Perros?
salvaje ¿Cuáles cree que podrían ser sus opciones?
Y sin preocuparse por cómo Java maneja las
cosas, simplemente intente imaginar cómo resolvería
como de modificar algunas de sus clases de
el problema
Animales para incluir comportamientos de Mascotas.

Deténgase ahora mismo y piense en


ello, antes de mirar la página siguiente donde
comenzamos a revelar
todo .

(haciendo así que todo el ejercicio sea completamente inútil, robándote

tu única gran oportunidad de quemar algunas calorías cerebrales)

218 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Exploremos algunas opciones de diseño


para reutilizar algunas de nuestras
clases existentes en un programa PetShop.

1 Opción uno
Tomamos el camino fácil y colocamos
métodos pet en la clase Animal.
Coloque todo el
Ventajas:
código del método pet
Todos los animales heredarán instantáneamente los aquí para heredar.
comportamientos de las mascotas. No tendremos que
tocar las subclases de Animal existentes en absoluto, y
cualquier subclase de Animal creada en el futuro Animal
también podrá aprovechar la herencia de esos métodos.
De esa manera, la clase Animal se puede usar como
tipo polimórfico en cualquier programa que quiera tratar
a los animales como mascotas.

Canino

Hipopótamo
Contras:

Entonces… ¿cuándo fue la última vez que viste


un hipopótamo en una tienda de mascotas? ¿León? Felino
¿Lobo? Podría ser peligroso darle métodos para
mascotas que no sean mascotas.
Perro

Además, es casi seguro que tendremos que


tocar las clases de mascotas como Perro y
Gato
Gato, porque (al menos en nuestra casa) los Lobo
perros y los gatos tienden a
implementar comportamientos de
León
mascotas MUY diferentes.
Tigre

usted está aquí 219


Machine Translated by Google

modificando clases existentes

2 Opción dos
Comenzamos con la Opción Uno, poniendo los métodos
pet en la clase Animal, pero hacemos que los métodos
sean abstractos, forzando a las subclases Animal a anularlos.

Ventajas:

Eso nos daría todos los beneficios de la Opción Uno, pero sin el inconveniente
de tener animales que no son mascotas corriendo con métodos de mascotas Coloque todos los métodos favoritos aquí,

(como beFriendly()). Todas las clases de Animal tendrían el método


pero sin implementaciones. Haga que todos
(porque está en la clase Animal), pero debido a que es abstracto, las clases
de Animal que no son mascotas no heredarán ninguna funcionalidad. los métodos de mascotas sean abstractos.

Todas las clases DEBEN anular los métodos, pero pueden hacer que los
métodos "no hagan nada".

Animal
Contras:

Debido a que todos los métodos pet en la clase Animal son


abstractos, las subclases Animal concretas se ven obligadas a
implementarlos todos. (Recuerde, todos los métodos abstractos DEBEN
ser implementados por la primera subclase concreta del árbol de
herencia). ¡Qué pérdida de tiempo! Canino
Tienes que sentarte allí y escribir todos y cada uno de los
Hipopótamo
métodos pet en todas y cada una de las clases concretas
que no son mascotas, y también en todas las subclases futuras.
Y si bien esto resuelve el problema de que las Felino
personas que no son mascotas realmente
HACEN cosas como mascotas (como lo harían Perro
si heredaran la funcionalidad de mascota de la
no Cada
clase Animal), el contrato es malo.
clase ­pet estaría anunciando al mundo
que ella también tiene esos métodos Gato
Lobo
pet, aunque los métodos en
realidad no HACEN nada
León
cuando se los llama.
Tigre

Este enfoque no parece


nada bueno. Simplemente
Pídeme que sea amigable.
parece incorrecto incluir en No, en serio... pregúntame.
la clase Animal todo lo que más de Yo tengo el método.

un tipo de Animal pueda necesitar, A


MENOS que se aplique a TODAS las
subclases de Animal.

220 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

3 Opción tres
Coloque los métodos pet SÓLO en
las clases a las que pertenecen.
Ventajas:

No más preocupaciones de que los hipopótamos te saluden en


la puerta o te laman la cara. Los métodos están donde
pertenecen, y SÓLO donde pertenecen. Los perros pueden
implementar los métodos y los gatos pueden implementar los
métodos, pero nadie más tiene que saber sobre ellos. Coloque los métodos pet SÓLO en las
clases Animal que pueden ser
mascotas, en lugar de en Animal.
Contras:

Dos grandes problemas con este enfoque. En primer lugar, tendría


que aceptar un protocolo, y todos los programadores de clases de
animales domésticos, ahora y en el futuro, tendrían que CONOCER
Animal
el protocolo. Por protocolo nos referimos a los métodos exactos
que hemos decidido que todas las mascotas deberían tener. El
contrato de mascota sin nada que lo respalde.
Pero ¿qué pasa si uno de los programadores se equivoca un poquito?
¿Un método toma una cadena cuando se suponía que debía tomar
un int? ¿O lo llamaron Friendly() en lugar de Friendly()? hacer
Como no está
en un contrato,ser
el compilador no tiene forma de verificar si ha Canino
implementado los métodos correctamente. Alguien podría venir Hipopótamo

fácilmente a utilizar las clases de animales domésticos y


descubrir que no todas funcionan del todo bien.
Felino

Perro
Y segundo, no puedes usar polimorfismo
para los métodos pet.
¡Cada clase que necesite utilizar
Gato
comportamientos de mascotas Lobo
debería conocer todas y cada una
de las clases! En otras León
palabras, no puedes usar
Tigre
Animal como tipo
polimórfico ahora, porque el
compilador no te permitirá llamar
a un método Pet en una referencia
Animal (incluso si es realmente un
objeto Perro) porque la clase Animal no
tiene el método. .

usted está aquí 221


Machine Translated by Google

herencia múltiple ?

Entonces lo que REALMENTE necesitamos es:

Una forma de tener un comportamiento de mascota solo en las clases de mascotas.

Una forma de garantizar que todas las clases pet tengan los mismos
métodos definidos (mismo nombre, mismos argumentos, mismos tipos de
retorno, no faltan métodos, etc.), sin tener que cruzar los dedos y esperar que
todos los programadores lo hagan bien.

Una forma de aprovechar el polimorfismo para que todas las mascotas puedan
llamar a sus métodos de mascotas, sin tener que usar argumentos, tipos de
retorno y matrices para todas y cada una de las clases de mascotas.

Parece que necesitamos DOS


superclases en la cima

Creamos una nueva


superclase abstracta llamada
Pet y le damos todos los métodos pet.
Mascota Animal

Canino

Hipopótamo

Felino

Perro

perro se extiende
Gato León Lobo mascota y ambos
Animal

Cat ahora se extiende


Tigre
tanto desde Animal

como desde Pet, por lo que


obtiene los métodos de ambos. Los animales que no son
mascotas no tienen ninguna
mascota heredada.

222 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Sólo hay un problema con el enfoque de “dos superclases”...

Se llama “herencia múltiple” y puede ser


algo realmente malo.
Es decir, si fuera posible hacerlo en Java.

Pero no lo es, porque la herencia múltiple tiene un problema


conocido como El Diamante Mortal de la Muerte.

Diamante mortal de la muerte


Grabadora digital
ent yo

CDBurner y DVDBurner heredan


de DigitalRecorder y ambos quemar()

anulan el método burn().


Ambos heredan la “i”
Instancia variable.
Quemador de CD Quemador de dvd Imagine que CDBurner y
DVDBurner utilizan la variable de
quemar() quemar()
instancia “i”, con valores
diferentes. ¿Qué sucede si
ComboDrive necesita usar ambos valores de “

Unidad combinada

problema con múltiples


herencia.
llamar
¿Qué a burn() burn() se ejecuta cuando
método
en el ComboDrive?

usted está aquí 223


Machine Translated by Google

interfaces

Interfaz al rescate!
interfaz

Mascota
Una interfaz Java es como un
Clase 100% pura abstracta.
resumen vacío beFriendly();
Todos los métodos en una interfaz son
juego vacío abstracto();
abstractos, por lo que cualquier clase
que ES­A Pet DEBE implementar (es decir,
anular) los métodos de Pet.

Para DEFINIR una interfaz:


interfaz pública Mascota {...}

Utilice la palabra clave "interfaz"


en lugar de "clase"

Para IMPLEMENTAR una interfaz:


clase pública Perro extiende implementos caninos Mascota {...}

Utilice la palabra clave "implementos" seguida

del nombre de la interfaz. Tenga en


cuenta que cuando implementa una
interfaz aún puede extender una clase

224 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

Creación e implementación de la
interfaz Pet Los métodos de interfaz son implícitamente
públicos y abstractos, por lo que escribir "público"
y "abstracto" es opcional (de hecho, no se considera
"buen estilo" escribir las palabras, pero hizo aquí
En su lugar dices "interfaz" solo lo reforzamos, y porque nunca lo hemos
hecho). sido esclavos de la moda...)
de 'clase' aquí

Todos los métodos de interfaz


interfaz pública mascota {
son abstractos, por lo que DEBEN
resumen público vacío beFriendly(); terminar en punto y coma. Recuerda que tienen
¡nadie!
juego vacío abstracto público();
}

Dices 'implementos'
Perro ES­Un Animal seguido del nombre
y Perro ES­Una Mascota
de la interfaz.
clase pública Perro extiende implementos caninos Mascota {

público vacío beFriendly() {...}

juego público vacío() {..}


DIJISTE que eres una mascota, por lo DEBE
contrato.
que implementas los métodos de mascota. Es su
Observe el rizado en tirantes
lugar del punto y coma.
itinerancia pública vacía () {...}

comer vacío público() {...} Estos son simplemente


métodos.
anulaciones normales.
}

no existen
Preguntas tontas

usted está aquí 225


Machine Translated by Google

polimorfismo de interfaz

Las clases de pueden diferente Interfaz de árboles de


implementar el mismo herencia.

Robot

Mascota Animal

Agente
RoboPerro
Canino

Hipopótamo
La clase RoboDog no
venir
proviene del animal.
árbol de herencia, ¡pero aún así
Felino
llega a ser una mascota!

Perro

Gato León Lobo

Tigre

Mejor aún, ¡una clase puede implementar interfaces!


múltiple

clase pública Perro extiende Implementos animales Mascota,


Guardable, Pintable {...}

226 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

hazlo pegado

¿Cómo saber si crear una clase, una subclase, una clase


o una interfaz? abstracto

Cree una clase que no extienda nada (aparte de Objeto)


cuando su nueva clase no pase la prueba IS­A para ningún otro
tipo.

Cree una subclase (en otras palabras, solo extender una clase)
cuando necesite crear una versión de más específicoC
una clase y necesite anular o agregar nuevos comportamientos).

Utilice una clase abstracta cuando desee definir un grupo de


a subclases y tenga al menos un código de
plantilla
implementación que
alguno
todas las subclases puedan utilizar. Haga
que la clase sea abstracta cuando quiera garantizar que nadie
pueda crear objetos de ese tipo.

Utilice una interfaz cuando desee definir una que otras role
clases puedan reproducir, independientemente de dónde se
encuentren esas clases en el árbol de herencia.

usted está aquí 227


Machine Translated by Google

usando súper

Invocar la versión de superclase de


un método La versión de superclase del
método hace cosas importantes
que las subclases podrían usar.
Informe de clase abstracta {
informe de ejecución nulo() {
// informe de configuración
}
void imprimirInforme() {
// impresión genérica
}
}

clase BuzzwordsReport extiende Informe {

informe de ejecución nulo() { llame a la versión de


[Link](); palabra superclase, luego regrese
de modaCumplimiento(); y haga algunas cosas
Imprimir reporte();
específicas de la subclase

}
void buzzwordCompliance() {...}
}

Si el código del método dentro

de una subclase BuzzwordReport dice: método de subclase (anula


la versión de superclase)
[Link]();

Se ejecutará el método runReport()


sacar un reporte()
dentro de la superclase Informe. métodos de
palabra de modaCumplimiento()
superclase (incluido el
sacar un reporte()
runReport() anulado
Imprimir reporte()

Informe
[Link]();
Informe de palabra de moda
Una referencia al objeto de subclase
(BuzzwordReport) siempre llamará a la
versión de subclase de un método anulado.
La palabra clave super es en realidad una referencia
Eso es polimorfismo.
Pero el código de la subclase puede a la parte de superclase de un objeto.
Cuando el código de subclase usa super,
llamar a [Link]() para invocar
como en [Link](), la versión de superclase de
la versión de la superclase.
el método se ejecutará.

228 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

PUNTOS DE VIÑETA

Cuando no desea que se cree una instancia de una clase (en otras palabras, no desea que
nadie cree un nuevo objeto de ese tipo de clase), marque la clase con la palabra clave abstracta .

Una clase abstracta puede tener métodos tanto abstractos como no abstractos.

Si una clase tiene incluso un método abstracto, la clase debe marcarse como abstracta.

Un método abstracto no tiene cuerpo y la declaración termina con un punto y coma (sin llaves).

Todos los métodos abstractos deben implementarse en la primera subclase concreta del árbol de
herencia.

Cada clase en Java es una subclase directa o indirecta de la clase Objeto ([Link].
Objeto).

Los métodos se pueden declarar con argumentos de objeto y/o tipos de retorno.

Puede llamar a métodos en un objeto solo si los métodos están en la clase (o interfaz) utilizada como
tipo de variable de referencia , independientemente del tipo de objeto real . Por lo tanto, una
variable de referencia de tipo Objeto sólo se puede utilizar para llamar a métodos definidos en la clase
Objeto, independientemente del tipo de objeto al que se refiere la referencia.

Una variable de referencia de tipo Objeto no se puede asignar a ningún otro tipo de referencia sin
una conversión. Se puede utilizar una conversión para asignar una variable de referencia de un tipo
a una variable de referencia de un subtipo, pero en tiempo de ejecución la conversión fallará si el
objeto en el montón NO es de un tipo compatible con la conversión.

Ejemplo: Perro d = (Perro) [Link](aPerro);

Todos los objetos salen de ArrayList<Object> como tipo Objeto (es decir, solo se puede hacer referencia
a ellos mediante una variable de referencia de Objeto, a menos que use una conversión).

La herencia múltiple no está permitida en Java debido a los problemas asociados con el “Diamante Mortal
de la Muerte”. Eso significa que sólo puede ampliar una clase (es decir, sólo puede tener una superclase
inmediata).

Una interfaz es como una clase abstracta 100% pura. Define sólo métodos abstractos.

Cree una interfaz utilizando la palabra clave interfaz en lugar de la palabra clase.

Implementar una interfaz usando la palabra clave implements.


Ejemplo: Perro implementa Mascota

Su clase puede implementar múltiples interfaces.

Una clase que implementa una interfaz debe implementar todos los métodos de la interfaz, ya
que todos los métodos de la interfaz son implícitamente públicos y abstractos.

Para invocar la versión de superclase de un método desde una subclase que ha anulado el método,

utilice la palabra clave super . Ejemplo: [Link]();

usted está aquí 229


Machine Translated by Google

Ejercicio: ¿Cuál es la imagen?

Dado: ¿Cuál es la imagen?

(interfaz)
1) foo
1) interfaz pública Foo { }

La barra de clase pública implementa Foo {}

2)
2) interfaz pública Vinn { }
Bar
La clase abstracta pública Vout implementa Vinn {}

3) clase abstracta pública Muffie implementa Whuffie {}

la clase pública Fluffie extiende a Muffie {} 3)


interfaz pública Whuffie { }

4) clase pública Zoop { } 4)


la clase pública Boop extiende Zoop { }

la clase pública Goop extiende Boop { }

5) la clase pública Gamma extiende Delta implementa Epsilon { }

interfaz pública Epsilon { }


5)
interfaz pública Beta { }

la clase pública Alpha extiende Gamma implementa Beta { }

clase pública Delta { }

230 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

¿Qué es la Declaración?
Dado:
Hacer clic
clase pública Haga clic en
1
{ } 1) clase pública Clack se extiende Haga clic en { }

Arriba
2
2)
Charla

Consejo

3)

Tarifa

3
4)
foo
4

fi

Bar 5)

Zeta
5

baz

Beta
Alfa LLAVE

Charla
Delta
Charla

Charla

usted está aquí 231


Machine Translated by Google

rompecabezas: rompecabezas de piscina

Piscina

Rompecabezas

____________ Nariz {
público ___________ ________ extiende Payasos {
________________________
} público estático vacío principal (String [] argumentos) {

____________________________
clase abstracta Picasso implementa ________
yo[0] = nuevo __________
__________________________
yo[1] = nuevo __________
devolver 7;
} yo[2] = nuevo __________

} para(int x = 0; x < 3; x++) {

[Link](__________________
clase {} + ““
_________ ________ __________
+ _______.getClass() );
}
clase {
_________ ________ __________
}
___________________________ } Ayuda de la ventana de edición de archivos BeAfraid

devolver 5; %Java ______________


} 5 actos de clase
} Payasos de 7 clases

________De76

232 capítulo 8
Machine Translated by Google

interfaces y polimorfismo

¿Cuál es la imagen?

2) (interfaz)
Vinn
3) (interfaz)
Wuffie

votar
¿Qué es la Declaración?
Muffie

clase abstracta pública Top { } 2) La

sugerencia de clase pública extiende Top { }

4) zoop
peludito

Tarifa de clase de resumen público


{}

3) Clase de resumen público Fi extiende la tarifa { }

boop
interfaz pública Foo { } 4) la

barra de clase pública implementa Foo { } la clase

Pegajoso
pública Baz extiende la barra { }

interfaz pública Zeta { } 5) clase

5) Delta
(interfaz) pública Alpha implementa Zeta { } interfaz pública
Épsilon
Beta { } clase pública Delta

extiende Alpha implementa Beta { }


(interfaz)
Gama Beta

Alfa

usted está aquí 233


Machine Translated by Google

solución de rompecabezas

interfaz Nariz { public int clase pública Of76 extiende Payasos {

iMethod() ; público estático vacío principal (String [] argumentos) {


Nariz [ ] i = nueva Nariz [3] ;
} clase abstracta Picasso implementa Nariz { public int iMethod() { i[0] = nuevos actos();
i[1] = nuevos Payasos( );
devolver 7;
i[2] = nuevo Of76( );
}
para(int x = 0; x < 3; x++) {
}
clase Payasos extiende Picasso { } [Link]( i [x] . iMethod( )
+ ““
+ i [x].getClass() );
clase Actos extiende Picasso { public int iMethod() }

{ }
devolver 5; }
}
}

Ayuda de la ventana de edición de archivos KillTheMime

% java de 76
5 actos de clase

Payasos de 7 clases

7 clase de 76

234 capítulo 8
Machine Translated by Google

9 constructores y recolección de basura.

Vida y muerte de un
...luego dijo: “¡No

objeto puedo sentir mis piernas!” y dije


“¡Joe! ¡Quédate conmigo Joe!
Pero fue demasiado tarde. Llegó el
recolector de basura y... se había ido.
El mejor objeto que he tenido.

Los objetos nacen y los objetos mueren.

este es un nuevo capitulo 235


Machine Translated by Google

la pila y el montón

La pila y el montón: donde viven las cosas

La pila el montón también conocido como

“El montón de basura recolectable”

ir()

Connecticut
S
DtuCk bj miC t norte mi

hacer cosas() oh oh
wbohar d oh b
j

principal()
t
C
Btut t bj mi
ohnorte oh

Variables de instancia Variables locales

público vacío foo (int x) {


pato de clase pública {
int yo = x + 3; El parámetro x y las variables
tamaño entero; Cada pato tiene una variable de i y b son todas variables
booleano b = verdadero;
instancia de "tamaño". locales.
}
}

236 capítulo 9
Machine Translated by Google

constructores y gc

Los métodos están apilados.


Una pila de llamadas con dos métodos.

parte superior de la pila

marcos de pila
bar() s
variables
foo() xib locales
(incluido el parámetro x)

parte inferior de la pila

El método en la parte superior de la


pila es siempre el método que se está
ejecutando actualmente.

público vacío hacer cosas() { Un escenario de pila


booleano b = verdadero;
ir(4);
}
vacío público ir (int x) {
int z = x + 24;
loco();
// imagina más código aquí
}
público vacío loco() {
carácter c = 'a';
}

1 código de otro 2 doStuff() llama a go(), go() 3 go() llama a Crazy(), 4 loco() completo,
la clase llama a doStuff() está en empujado en Crazy() ahora está en la y su marco de pila está
y doStuff() va a un la parte superior de la pila. parte superior de la apareció fuera de la pila.
marco de pila en la Las variables 'x' y 'z' pila, con la variable La ejecución vuelve al
parte superior de la están en el marco de pila 'c' en el marco. método go() y continúa
pila. La variable go() . en la línea que sigue
booleana denominada a la llamada a crazy().
'b' va al marco de pila
doStuff() .
loco() c
ir() xz ir() xz ir() xz

hacer cosas() b hacer cosas() b hacerCosas() b hacer cosas() b

usted está aquí 237


Machine Translated by Google

referencias de objetos en la pila

¿Qué pasa con las variables locales que son objetos?

barf() declara y crea una nueva


variable de referencia de Duck 'd'
(dado que se declara dentro del
método, es una variable local y va a la pila.

clase pública StackRef {


foof público vacío() {
vomitar();
vomitar() d
}
DtuCk bj miC t
oh
Montón
tonto()
vómito público vacío() {
Pato d = nuevo Pato(24);
No importa DÓNDE se declare la
}
} variable de referencia del objeto (dentro
de un método o como una variable de

instanciavadeenuna clase), el objeto siempre siempre


siempre
el montón.

no existen
Preguntas tontas
PUNTOS DE VIÑETA

Java tiene dos áreas de memoria que nos interesan: la


pila y el montón.

Las variables de instancia son variables declaradas

dentro de una clase pero fuera de cualquier método.

Las variables locales son variables declaradas dentro de

un método o parámetro de método.

Todas las variables locales viven en la pila, en el


marco correspondiente al método donde se declaran las
variables.

Las variables de referencia de objetos funcionan igual


que las variables primitivas: si la referencia se declara

como una variable local, va a la pila.

Todos los objetos viven en el montón,


independientemente de si la referencia es una
variable local o de instancia.

238 capítulo 9
Machine Translated by Google

constructores y gc

Si las variables locales viven en la pila, Objeto de teléfono celular

¿dónde viven las variables de instancia?


X y

largo

Objeto con dos variables de instancia primitivas.


El espacio para las variables vive en el objeto.

Objeto de teléfono celular

hormiga

Antena

Objeto con una variable de instancia no primitiva:


una referencia a un objeto Antena, pero no un
objeto Antena real. Esto es lo que obtienes
si declaras la variable pero no la inicializas
con un objeto Antena real.

teléfono celular de clase pública {


hormiga antena privada;
}

Objeto CellPhone Objeto Antena

hormiga

Antena

hormiga antena privada; Objeto con una variable de instancia no primitiva y


a la variable Antena se le asigna un nuevo
objeto Antena.

teléfono celular de clase pública {


hormiga antena privada = nueva antena();
hormiga antena privada = nueva antena(); }

usted está aquí 239


Machine Translated by Google

creación de objetos

El milagro de la creación de objetos

Revise los 3 pasos de declaración,


creación y asignación de objetos:

Declarar una variable de


1 referencia
mi pato
Cree una nueva variable Pato miPato = nuevo Pato();
de referencia de una
clase o tipo de interfaz.
Referencia de pato

2 Crear un objeto
Pato miPato = nuevo Pato();
Aquí
ocurre un milagro. Objeto pato

3 Vincular el objeto y la
Asigne el nuevo
referencia.
objeto al
referencia.
Pato miPato = nuevo Pato();

Objeto pato

mi pato

Referencia de pato

240 capítulo 9
Machine Translated by Google

constructores y gc

¿Estamos llamando a un método llamado Duck()?


Porque seguro que le gusta.
aspecto

Parece que estamos llamando


a un método llamado Duck(),
Pato miPato = nuevo Pato();
debido a los paréntesis.

No.

Estamos llamando al pato constructor .

nuevo
Un constructor tiene el código

que se ejecuta cuando creas


nuevo
una instancia de un objeto.
En otras palabras, el código
que se ejecuta cuando dices
nuevo en un tipo de clase.

Cada clase que creas tiene


un constructor, incluso si
¿Pero dónde está el constructor? no lo escribes tú mismo.

Si no lo escribimos nosotros, ¿quién lo hizo?

pato público() {

¿Notas que falta algo? ¿En qué se diferencia esto de un


método? Su nombre es el mismo que el
nombre de la clase. Eso es obligatorio.

pato público() {
¿Dónde está el tipo de devolución? // el código del constructor va aquí
Si este fuera un método, }

necesitaría un tipo de
retorno entre "público" y
"Pato()".

usted está aquí 241


Machine Translated by Google

construyendo un nuevo pato

construir un pato
Si grazna como un
constructor...

pato de clase pública {

público Pato()
{ [Link](“Quack”);
} El constructor te da la oportunidad
} de entrar en medio de lo nuevo.
Código constructor.

Ventana de edición de archivos Ayuda Quack


clase pública UseADuck {
% java UsoADuck
público estático vacío principal (String[] args) { Curandero
Pato d = nuevo Pato();
}
} Esto llama al
constructor Duck.

Afila tu lápiz
Incrementa un contador para rastrear cuántos objetos de este tipo de
clase se han creado.

Asigne un estado específico del tiempo de ejecución (datos sobre lo que está sucediendo AHORA).

Asigne valores a las variables de instancia importantes del objeto.


nuevo
Obtenga y guarde una referencia al objeto que está creando el nuevo objeto.
Agregue el objeto a una ArrayList.
Crea objetos HAS­A.
________________________________________ (tu idea aquí)

242 capítulo 9
Machine Translated by Google

constructores y gc

Inicializando el estado de un nuevo pato no existen


Preguntas tontas

pato público() {
tamaño = 34;
}

pato de clase pública {


tamaño entero; Instancia variable

pato público() {
[Link](“Cuac”); constructor
}

setSize vacío público (int nuevoTamaño) { método de establecimiento


tamaño = nuevoTamaño;
}
}

clase pública UseADuck {

principal vacío estático público (String[] args){


Pato d = nuevo Pato();

[Link](42);
Hay algo malo aquí. ¡El Pato está vivo en este
} puntoconfiando
del código,
estás enpero sin un tamaño!* Y luego
SABER
} proceso: uno
el usuario Duck
que la creación del Pato es una
debe llamar al constructor de dos partes
para llamar al configurador.
y uno
*Las variables de instancia tienen un valor predeterminado. 0
o 0,0 para primitivas numéricas, falso para booleanos y nulo
para referencias.
usted está aquí 243
Machine Translated by Google

inicializando el estado del objeto

Usando el constructor para inicializar


estados importantes de Duck*
Permita que el usuario cree un nuevo pato
y y establezca todo el tamaño del pato.
una llamada. La llamada a lo nuevo.
La llamada al constructor
Duck.

Agregue un parámetro int al


pato de clase pública {
Constructor de patos.
tamaño entero;

pato público (int tamaño pato) {


[Link](“Cuac”);
Utilice el valor del argumento para establecer

la variable de instancia de tamaño.


tamaño = tamaño del pato;

[Link](“el tamaño es” + tamaño);


}
}

clase pública UseADuck {

público estático vacío principal (String[] args) {


Pato d = nuevo Pato(42);
}
Esta vez sólo hay una } Pasar un valor al
declaración. Creamos el
constructor.
nuevo Pato y establecemos Ventana de edición de archivos Ayuda Bocina

su tamaño en una sola declaración.


% java UsoADuck

Curandero

el tamaño es 42

*No quiero dar a entender que no todos los estados de Duck carezcan de importancia.

244 capítulo 9
Machine Translated by Google

constructores y gc

Haz que sea fácil hacer un pato.


Asegúrate de tener un constructor sin argumentos.

clase pública pato2 {


tamaño entero;

Imagine que desea que los usuarios de Duck tengan DOS opciones pato público2() {
para crear un Duck: una en la que proporcionan el tamaño del // suministra el tamaño predeterminado
Duck (como argumento del constructor) y otra en la que no tamaño = 27;
}
especifican un tamaño y, por lo tanto, obtienen el tamaño del Duck predeterminado.

pato público2 (int tamaño pato) {


// usar el parámetro tamaño pato
tamaño = tamaño del pato;
}
}

Pato2 d = nuevo Pato2(15);

pato de clase pública {


tamaño entero;
Si el valor del parámetro es
cero, asigne al nuevo pato un Pato2 d2 = nuevo Pato2();
Pato público (int nuevoTamaño) {
si (nuevoTamaño == 0) { tamaño predeterminado; de lo
tamaño = 27; contrario, utilice el valor del
} demás { parámetro para el tamaño. NO es muy bueno
tamaño = nuevoTamaño; solución.
}
}
}

usted está aquí 245


Machine Translated by Google

constructores sobrecargados y predeterminados

¿No crea siempre el


compilador un constructor OK, veamos aquí...
“Tienes derecho a tu propia
sin argumentos?
No ! constructor." Tiene sentido.

"Si no puede permitirse un constructor,


el compilador le proporcionará uno".
Bueno saber.

Si escribes un constructor que toma argumentos


y quieres un constructor sin argumentos, aún
¡tendrás que construir el constructor sin
argumentos tú mismo!

Si tiene más de un constructor en una


clase, los constructores DEBEN tener
listas de argumentos diferentes.

246 capítulo 9
Machine Translated by Google

constructores y gc

Constructores sobrecargados significa que tienes


más de un constructor en tu clase.
Para compilar, cada constructor debe tener un
diferente lista de argumentos!

Cuatro constructores
medio

hacer un
diferentes deformas
nuevo hongo.
a
cuatro diferentes.

cuando sabes el tamaño, pero


hongo de clase pública {
no sabes si es mágico
Hongo público ( tamaño int) {}
cuando no sabes nada
Hongo público( ) { }
cuando sabes si es mágico o no,
pero no se el tamaño
Hongo público (booleano esMagic) { }
cuando
estos dos tienen los
Hongo público (booleano isMagic, tamaño int) { } sabes si es
mismos argumentos, mágico o no, Y
Hongo público ( tamaño int, booleano isMagic) { } también sabes el tamaño
pero en diferente orden,
así que está bien
}

PUNTOS DE VIÑETA

Las variables de instancia viven dentro del objeto al que pertenecen, en el Si desea un constructor sin argumentos y ya ha instalado un constructor
montón. con argumentos, tendrá que crear el constructor sin argumentos usted
mismo.
Si la variable de instancia es una referencia a un objeto, tanto la referencia
como el objeto al que hace referencia están en el montón. Siempre proporcione un constructor sin argumentos si puede, para que a los

programadores les resulte más fácil crear un objeto funcional. Proporcione


Un constructor es el código que se ejecuta cuando dices nuevo en un tipo de
valores predeterminados.
clase.
Constructores sobrecargados significa que tienes más de un constructor en
Un constructor debe tener el mismo nombre que la clase y no debe tener un
tu clase.
tipo de retorno.
Los constructores sobrecargados deben tener listas de argumentos
Puede utilizar un constructor para inicializar el estado (es decir, las
diferentes.
variables de instancia) del objeto que se está construyendo.
No puedes tener dos constructores con las mismas listas de
Si no coloca un constructor en su clase, el compilador colocará un
argumentos. Una lista de argumentos incluye el orden y/o el tipo de
constructor predeterminado.
argumentos.
El constructor predeterminado es siempre un constructor sin argumentos.
A las variables de instancia se les asigna un valor predeterminado,
Si pones un constructor (cualquier constructor) en tu clase, el compilador incluso cuando no se asigna uno explícitamente. Los valores
no construirá el constructor predeterminado. predeterminados son 0/0.0/false para primitivas y nulos para referencias.

usted está aquí 247


Machine Translated by Google

constructores sobrecargados

clase pato {
Afila tu lápiz libras enteras = 6;
Haga coincidir la nueva llamada Duck() con el constructor flotabilidad del flotador = 2.1F; Nombre
que se ejecuta cuando se crea una instancia de ese Duck. Lo hicimos de cadena = "Genérico"; plumas
largas[] = {1,2,3,4,5,6,7}; booleano canFly = verdadero;
el más fácil para empezar.
int velocidadmáx = 25;

clase pública TestDuck {


pato público()
principal vacío estático público (String [] argumentos) { { [Link](“pato tipo 1”);
}
peso interno = 8;
densidad de flotación = 2,3F; Pato público (mosca booleana) {
Nombre de cadena = "Donald"; canFly = volar;
plumas largas[] = {1,2,3,4,5,6}; booleano canFly = [Link](“pato tipo 2”);
verdadero; velocidad aérea interna }
= 22;
pato público (cadena n, larga [] f) {
Pato[] d = nuevo Pato[7]; nombre = n; plumas
= f; [Link](“pato
d[0] = nuevo Pato(); tipo 3”);
}
d[1] = pato nuevo(densidad, peso);
pato público (int w, float f) { libras = w;
d[2] = nuevo Pato(nombre, plumas); flotabilidad = f;
[Link](“pato
d[3] = nuevo Pato(canFly); tipo 4”);
}
d[4] = nuevo Pato(3.3F, velocidad aérea);
pato público (densidad de flotación, int max) { flotabilidad
d[5] = pato nuevo(falso); = densidad; velocidadmáx = máx;
[Link](“pato
d[6] = new Duck(velocidad aérea, densidad); tipo 5”);
} }
} }

Color c = nuevo Color();

Ayuda de la ventana de edición de archivos StopBeingStupid

no se puede resolver el
símbolo :constructor Color()
ubicación: clase
[Link] Color c =
new Color();
^
Color c = nuevo Color(3,45,200); 1 error

248 capítulo 9
Machine Translated by Google

constructores y gc

Nanoreview: cuatro cosas


para recordar sobre los constructores

1 Un constructor es el código que se ejecuta cuando


alguien dice nuevo en un tipo de clase.
Pato d = nuevo Pato();

2 Un constructor debe tener el mismo nombre


que la clase y tipoNo
de retorno

Pato público (tamaño int) {}

3 Si no coloca un constructor en su clase, el


compilador coloca un constructor predeterminado.
El constructor predeterminado es siempre un constructor
sin argumentos.
no existen
Preguntas tontas
pato público() { }
público

público
4 Puedes tener más de un constructor en tu clase, siempre que las listas de privado
argumentos sean diferentes. Tener más de un constructor en una
clase significa que tienes constructores sobrecargados.

pato público() { }

Pato público (tamaño int) {}

Pato público (nombre de cadena) {} privado

Pato público (nombre de cadena, tamaño int) {}

Se ha demostrado que hacer todas las Brain Barbells produce un aumento del 42% en el
tamaño de las neuronas. Y ya sabes lo que dicen: "Grandes neuronas..."

usted está aquí 249


Machine Translated by Google

espacio para las partes de superclase de un objeto

Espera un minuto... nunca hablamos


sobre superclases y herencia y cómo todo eso
encaja con los constructores.

nuevo
nuevo

Un solo
Objeto objeto en
El objeto tiene variables de instancia
Foo a; el montón.
encapsuladas por métodos de acceso. Y
intb; X
Esas variables de instancia se z
intc;

crean cuando se crea una


es igual() instancia de cualquier subclase.
obtenerClase()
REAL (Estas no son las variables C
licenciado en Letras
código hash()

Encadenar() de Objeto, pero no nos importa


Objeto
cuáles sean ya que están encapsuladas)

snowboard Snowboard también tiene sus

foo x propias variables de instancia, por lo que snowboard


foo y
para crear un objeto Snowboard
entero z
S t
miC
necesitamos espacio para las variables oh
norte
wboh ard obj
de instancia de ambas clases.
doblar()

desgarrar()

obtenerAire() Aquí solo hay UN objeto en el montón. Un objeto de


perder el control()
snowboard. Pero contiene tanto las partes de Snowboard
de sí mismo como las partes de Objeto de sí mismo. Todas las
variables de instancia de ambas clases deben estar aquí.

250 capítulo 9
Machine Translated by Google

constructores y gc

El papel de los constructores de superclases


en la vida de un objeto.

nuevo XY
Objeto
SV
k

C
a b
Animal

Objeto

Animal
Hipopótamo
Hipopótamo

Un único objeto Hippo en el montón

Un nuevo objeto hipopótamo también ES­Un animal


y objeto IS­A. Si quieres hacer un
Hipopótamo, también debes hacer las partes Animal
y Objeto del Hipopótamo.

Todo esto sucede en un proceso llamado


Encadenamiento de constructores.

usted está aquí 251


Machine Translated by Google

construcción de objetos

Hacer un hipopótamo significa hacer


también las partes del animal y del objeto... Afila tu lápiz

clase pública Animal {


Animal público() {
[Link](“Haciendo un animal”);
Ventana de edición de archivos Ayuda Jurar
}
} % java TestHippo
A A partir de...
hipopótamo de clase pública extiende Animal { hacer un animal
hipopótamo público() { hacer un hipopótamo
[Link](“Haciendo un hipopótamo”);
}
}

Ventana de edición de archivos Ayuda Jurar

clase pública TestHippo { % java TestHippo


público estático vacío principal (String[] args) {
B
A partir de...
[Link](“Iniciando...”);
hacer un hipopótamo
Hipopótamo h = nuevo hipopótamo();
} hacer un animal
}

1 El código de otra clase 2 Hippo() invoca el 3 Animal() invoca el 4 Object() se completa y su


constructor de constructor de marco de pila sale de la
dice new Hippo()
superclase que superclase que empuja apareció pila. La
y el constructor
Hippo() va a un marco empuja a Animal() el Objeto() ejecución vuelve al Animal()
constructor en la parte constructor en la parte
de pila en la parte
superior de la pila. superior de la pila, ya que constructor, y continúa
superior de la pila.
Objeto es la superclase en la línea que sigue a la
de Animal. llamada de Animal a su
superclase
constructor

Objeto()
Animal() Animal() Animal()

Hipopótamo() Hipopótamo() Hipopótamo() Hipopótamo()

es el constructor Anima
El primero, A. Primero

252 capítulo 9
Machine Translated by Google

constructores y gc

Cómo ¿Invocas un constructor de superclase?

clase pública Pato extiende Animal {


tamaño entero;

¿Y cómo es que nos hemos salido


Pato público (int nuevoTamaño) {
Animal(); con la nuestra sin hacerlo?
¡MALO!
tamaño = nuevoTamaño; ¡NO! ¡Esto no es legal!

clase pública Pato extiende Animal { 1


tamaño entero;
nombre de clase pública() {

súper();
Pato público (int nuevoTamaño) {
}
súper();
solo dices super()
tamaño = nuevoTamaño;

}
2

súper();

*A menos que el constructor llame a otro constructor


sobrecargado (lo verá en unas pocas páginas).

usted está aquí 253


Machine Translated by Google

ciclo de vida del objeto

¿Puede el niño existir antes


que los padres? Eewwww... eso

es TAN espeluznante. hay


No manera en que podría haber

nacido antes que mis padres.


eso es solo equivocado.

¡La llamada a super() debe ser en cada primero declaración


constructor!*

Posibles constructores para la clase Boop.


Boop público() {

Boop público() { }
Esto está bien porque el
súper();
compilador llamará a
} Estos están bien porque Boop público (int i) { super() como primera
el programador ex­ declaración.
codificó tamaño = yo;
tácitamente la llamada.
Boop público (int i) { a super(), como el primero }
declaración.
súper();

tamaño = yo; Boop público (int i) {


¡¡MALO!! ¡Esto no se compilará!
} tamaño = yo;
No puedes poner
explícitamente la abajo
súper(); llamada a super()
demás. nada

*Existe una excepción a esta regla; lo aprenderás en la página 252.

254 capítulo 9
Machine Translated by Google

constructores y gc

Constructores de superclase con argumentos.

Animal

nombre de cadena privada

Animal(Cadena n)

Cadena getName()

Hipopótamo

clase abstracta pública Animal {


Hipopótamo (cadena n)
Todos los animales (incluidas
nombre de cadena privada;
las subclases) tienen un nombre.
[otros métodos específicos

de hipopótamos]
cadena pública getName() {
Un método getter que
nombre de retorno; hipopótamo hereda

La parte Animal de
Animal público (Cadena el nombre) { mí necesita saber mi nombre,
nombre = elNombre; El constructor que así que tomo un nombre propio.
toma el nombre y le asigna Constructor Hippo, luego pasa
} el nombre de instancia.
variable el nombre a super()
}

hipopótamo de clase pública extiende Animal {

hipopótamo público (nombre de cadena) {


El constructor de hipopótamos toma un nombre
super(nombre);
}
}
envía el nombre de la pila al
constructor Animal

Ventana de edición de archivos Ayuda Ocultar

clase pública MakeHippo { %java MakeHippo


público estático vacío principal (String [] argumentos) {
Haz un hipopótamo y pasa el Buffy
Hipopótamo h = nuevo hipopótamo ("Buffy");
el nombre "Buffy" al constructor
[Link]([Link]()); del hipopótamo. Luego llame al
} getName() heredado del hipopótamo
}

usted está aquí 255


Machine Translated by Google

llamar a constructores sobrecargados

Invocar un constructor sobrecargado


desde otro

Cada constructor puede tener una llamada a super() o


this(), ¡pero nunca a ambos!

clase Mini extiende Coche {

Color de color; El constructor sin argumentos


proporciona un Color
público Mini() { predeterminado y llama al
esto ([Link]); Real Constructor sobrecargado
} (el que llama a super()).

Mini público (Color c) {


súper(“Mini”); Este es el verdadero constructor que hace
color = c; el verdadero trabajo de inicializar el objeto
// más inicialización (incluida la llamada a super())
}
Unidad de ayuda de la ventana de edición de archivos

Mini público (tamaño entero) {


javac [Link]
esto ([Link]);
súper(tamaño); ¡¡No funcionará!! ¡No se [Link]: la llamada a super debe ser la primera declaración
puede tener super() y this() en el en el constructor

} mismo constructor, porque cada uno


} de ellos debe ser la primera declaración! súper();
^

256 capítulo 9
Machine Translated by Google

constructores y gc

Afila tu lápiz

hazlo pegado

clase pública abucheo {


abucheo público (int i) {}
abucheo público (cadena s) {}
público Boo(Cadena s, int i) { }
}

clase SonOfBoo extiende Boo { Ayuda de la ventana de edición de archivos

%javac [Link]
público SonOfBoo()
{ super(“abucheo”); no se puede resolver el símbolo
}
símbolo: constructor Boo
public SonOfBoo(int i) { super(“Fred”); ([Link],[Link] [Link])

public SonOfBoo(String s) { super(42); Ayuda de la ventana de edición de archivos Yadayadayada

%javac [Link]
}
no se puede resolver el símbolo
público SonOfBoo(int i, String s) { }
símbolo: constructor Boo
(int,[Link])
public SonOfBoo(Cadena a, Cadena b, Cadena c) { super(a,b);

Ayuda de la ventana de edición de archivos ImNotListening

public SonOfBoo(int i, int j) { super(“hombre”, j);


%javac [Link]
}
no se puede resolver el símbolo
public SonOfBoo(int i, int x, int y) { super(i, “estrella”); símbolo:constructor Boo()

}
}

usted está aquí 257


Machine Translated by Google

vida útil del objeto

Ahora sabemos cómo nace un objeto, 1 Una variable local vive sólo dentro del
pero ¿cuánto tiempo dura? vivir ? método que declaró la variable.

lectura pública vacía() {


int s = 42;
// 's' sólo se puede utilizar
// dentro de este método.
// Cuando finaliza este método,
// 's' desaparece por completo.
}

clase pública TestLifeOne {

lectura pública vacía() { 2 Una variable de instancia vive tanto como


int s = 42; el objeto. Si el objeto todavía está
's' tiene como alcance
dormir();
}
método, por lo que la lectura() vivo, también lo están sus variables de
lugar no se puede utilizar en ningún
demás instancia.
sueño vacío público() {
s = 7;
} vida de clase pública {
tamaño entero;
} ¡¡MALO!! ¡No es legal
usar 's' aquí!
conjunto vacío público (int s) {
tamaño = s;
// 's' desaparece al // final de este
sleep() no puede ver la variable 's'. método,
// pero se puede usar 'tamaño'
Como no está en el propio marco de
// en cualquier lugar de la clase
dormir() pila de sleep(), sleep() no sabe nada al respecto. }
}
leer() s

La variable
leer()
's' está vivo, pero sólo en el alcance
método. Cuando sleep() se completa en
dentro de
todavía veo y read() está
la parte superior de la pila y se ejecuta
's'. Cuando se lee()
read() se nuevamente,
puede completar y se retira
la pila, 's' está muerta. Empujando
margaritas digitales.

258 capítulo 9
Machine Translated by Google

constructores y gc

La diferencia entre vida y alcance para


variables locales:
público vacío hacer cosas() {
booleano b = verdadero;
Vida
ir(4);
}
vacío público ir (int x) {
int z = x + 24;
loco();
// imagina más código aquí
Alcance }
público vacío loco() {
carácter c = 'a';
}

loco() c
ir() xz ir() xz ir() xz

hacer cosas() b hacer cosas() b hacerCosas() b hacer cosas() b

1 doStuff() va a la pila. La variable 2 go() se deja caer encima 3 Crazy() se inserta en la pila, 4 crazy() se completa y se
'b' está viva y dentro del de la pila. 'x' y 'z' están con 'c' ahora viva y dentro del elimina de la pila, por lo que 'c'
alcance. vivos y dentro del alcance, y 'b' alcance. Las otras tres variables está fuera de alcance y
está vivo pero no dentro del están vivas pero fuera de muerto. Cuando go() continúa
alcance. donde lo dejó, 'x' y 'z' están

alcance. vivos y nuevamente dentro del

alcance.
La variable 'b' todavía está

activa pero fuera de alcance


(hasta que se complete go()).

usted está aquí 259


Machine Translated by Google

ciclo de vida del objeto

¿Qué pasa con las variables de referencia?

Tres formas de deshacerse de la referencia de un objeto:


Un objeto se vuelve elegible
1 La referencia sale del alcance, permanentemente
para GC cuando desaparece
ir vacío() { la referencia 'z' muere
su última referencia activa.
Vida z = nueva Vida(); al final del método
}

2 A la referencia se le asigna otro objeto


Vida z = nueva Vida(); el primer objeto se abandona
z = nueva Vida(); cuando z se 'reprograma' para
un nuevo objeto.

3 La referencia se establece explícitamente en nula.


el primer objeto se abandona
Vida z = nueva Vida();
z = nulo; cuando z se "desprograma".

260 capítulo 9
Machine Translated by Google

constructores y gc

Asesino de objetos n.° 1


La referencia queda
fuera de alcance
de forma permanente.

clase pública StackRef {


foof público vacío() { No me gusta hacia
vomitar(); dónde va esto.
}

vómito público vacío() {


Pato d = nuevo Pato();
}
}

1 foof() se inserta en la pila,


tonto()
no se declaran variables.

El nuevo Duck va al montón,


Montón y mientras se esté ejecutando
barf(), la referencia 'd' está viva
2 barf() se inserta en la pila, donde y dentro del alcance, por lo
declara una variable de
vomitar()
d
que el Duck se considera vivo.
referencia y crea un nuevo objeto DtuCk bj miC t
oh
asignado a esa referencia.
tonto()
El objeto se crea en el montón y
la referencia está viva y dentro
de su alcance.

UH oh. La variable 'd'


Montón
desapareció cuando el vómito()
El marco de la pila salió
3 barf() completa y sale de la pila. Su d volando de la pila, por lo que el
estructura se desintegra, por

lo que 'd' ahora está muerta y DtuCk bj miC t pato está abandonado.
desaparecida. La ejecución vuelve tonto() oh
Cebo recolector de basura.
a foof(), pero foof()
No puedo usar 'd'.

usted está aquí 261


Machine Translated by Google

ciclo de vida del objeto

Asesino de objetos n.° 2

Asignar la referencia a
otro objeto.

clase pública ReRef { Amigo, todo lo que


tenías que hacer era reiniciar
Pato d = nuevo Pato(); la referencia. Supongo

vacío público ir () { que en aquel entonces no


d = nuevo pato(); tenían gestión de memoria.
}
}

DtuCk bj miC t
oh

d
RmiRmi t Montón
F bj miC
oh

El nuevo Duck va al montón, al que se hace

referencia con 'd'. Dado que 'd' es una variable


de instancia, Duck vivirá mientras el objeto
ReRef que lo instancia esté vivo. A menos que...

Cuando alguien llama


al método go(), este pato
se abandona. Su única
2 referencia ha sido reprogramada
para un Pato diferente.
t
DtuCk bj
oh
miC

d
RmiRmi t Montón
F bj miC
oh DtuCk bj miC t
oh

A 'd' se le asigna un nuevo objeto Duck, dejando


abandonado el (primer) objeto Duck original. Ese
primer pato ahora está casi muerto.

262 capítulo 9
Machine Translated by Google

constructores y gc

Asesino de objetos n.° 3

Establecer explícitamente
la referencia a nula

1
clase pública ReRef {

Pato d = nuevo Pato(); DtuCk bj miC t


oh

vacío público ir () {
d
d = nulo;
RmiRmi t Montón
} F bj miC
oh
}
El nuevo Duck va al montón, al que se hace

referencia con 'd'. Dado que 'd' es una variable


El significado de nulo.
de instancia, Duck vivirá mientras el objeto
nulo ReRef que lo instancia esté vivo. A menos que...

Este pato está abandonado.

Su única referencia ha sido


establecido en nulo.

DtuCk bj miC t
oh

d
RmiRmi t Montón
F bj miC
oh

'd' está configurado en nulo, que es como tener un


control remoto que no está programado para nada. Ni
siquiera se le permite utilizar el operador de punto en 'd'

hasta que se reprograme (se le asigne un objeto).

usted está aquí 263


Machine Translated by Google

ciclo de vida del objeto

Charla de esta noche: una variable de instancia


y una variable local discuten la vida y la
muerte (con notable civilidad)

Instancia variable Variable local

264 capítulo 9
Machine Translated by Google

constructores y gc

Instancia variable Variable local

usted está aquí 265


Machine Translated by Google

Ejercicio: Sea el recolector de basura

¿Cuál de las líneas de código de la derecha, si se agrega


a la clase de la izquierda en el punto A, haría que
exactamente un objeto adicional sea elegible para el recolector
de basura? (Supongamos que el punto A (//llamar a más
métodos) se ejecutará durante un tiempo prolongado, lo que le
dará tiempo al recolector de basura para hacer sus cosas).

clase pública GC {

GC estático público hacer cosas() {

GC nuevoGC = nuevo GC();


1 copiarGC = nulo;
hacerCosas2(newGC);

devolver nuevoGC;
2 gc2 = nulo;
}

3 nuevoGC = gc3;

público estático vacío principal (String [] argumentos) {

GC gc1; 4 gc1 = nulo;

GC gc2 = nuevo GC();

GC gc3 = nuevo GC(); 5 nuevoGC = nulo;

GCgc4 = gc3;

gc1 = hacer cosas(); 6 gc4 = nulo;

A
7 gc3 = gc2;
// llama a más métodos

}
8 gc1 = gc4;

público estático vacío hacerCosas2 (GC copyGC) { 9 gc3 = nulo;

GC localGC = copiarGC;
Ventana de edición de archivos Ayuda Suspender

266 capítulo 9
Machine Translated by Google

constructores y gc

Popular
clase abejas {
Objetos
Miel [] abejaHA;
}

clase mapache {
Equipo k;
Miel rh;
}

equipo de clase {
Miel kh;
}

clase oso {
Miel cariño;
}

clase pública cariño {


public static void main(String [] args) { Honey honeyPot = new
Honey(); Miel [] ha = {honeyPot, HoneyPot,
HoneyPot, HoneyPot}; Abejas b1 = nuevas Abejas(); [Link] = ha; Oso [] ba = nuevo
Oso[5]; for (int x=0; x < 5; x++)
{ ba[x] = nuevo Oso();
ba[x].hunny = tarro de miel;

}
¡Aquí hay un
Kit k = nuevo Kit(); [Link] =
tarro de miel; Mapache r
nuevo objeto Mapache!
= nuevo mapache();

Aquí está su variable de


[Link] = tarro de miel; rk = k;
referencia 'r'.
k = nulo; //
fin de principal
}
}

usted está aquí 267


Machine Translated by Google

rompecabezas: Misterio de cinco minutos

“Hemos ejecutado la simulación cuatro veces y la temperatura del módulo principal cambia constantemente
de la nominal a la fría”, dijo Sarah, exasperada. “Instalamos los nuevos robots temporales la semana pasada. Las lecturas
de los robots de radiador, diseñados para enfriar las viviendas, parecen estar dentro de las especificaciones, por lo que
hemos centrado nuestro análisis en los robots de retención de calor, los robots que ayudan a calentar las habitaciones”.
Tom suspiró, al principio había parecido que la nanotecnología realmente los adelantaría a lo previsto. Ahora, cuando sólo
faltaban cinco semanas para el lanzamiento, algunos de los sistemas clave de soporte vital del orbitador todavía no
pasaban el desafío de la simulación.
Cinco minutos
"¿Qué proporciones estás simulando?", Preguntó Tom.

Misterio “Bueno, si veo hacia dónde vas, ya hemos pensado en eso”, respondió Sarah. "Mal­
El control de misión no aprobará los sistemas críticos si los ejecutamos sin especificaciones. Estamos
obligados a ejecutar las SimUnits del robot del radiador v3 en una proporción de 2:1 con las SimUnits
del radiador v2”, continuó Sarah. "En general, se supone que la proporción entre robots de retención y
robots de radiador es de 4:3".

"¿Cómo va el consumo de energía, Sarah?", Preguntó Tom. Sarah hizo una pausa: “Bueno, esa
es otra cosa, el consumo de energía está siendo mayor de lo previsto. También tenemos un equipo que está
rastreando eso, pero debido a que los nanos son inalámbricos, ha sido difícil aislar el consumo de energía de los
radiadores de los robots de retención”. "Las relaciones generales de consumo de energía", continuó Sarah, "están
diseñadas para funcionar en una proporción de 3:2 y los radiadores extraen más energía de la red inalámbrica".

“Está bien, Sarah”, dijo Tom. “Echemos un vistazo al código de inicio de la simulación.
¡Tenemos que encontrar este problema y hacerlo rápido!

importar [Link].*;
clase V2Radiador {
V2Radiator (lista ArrayList) {
para(int x=0; x<5; x++) {
[Link](new SimUnit(“V2Radiator”));
}
}
}

clase V3Radiator extiende V2Radiator {


V3Radiator (lista de registro ArrayList) {
super(lista lg);
para(int g=0; g<10; g++) {
[Link](new SimUnit(“V3Radiator”));
}
}
}

clase RetenciónBot {
RetentionBot (listaArrayList) {
[Link](new SimUnit(“Retención”));
}
}

268 capítulo 9
Machine Translated by Google

constructores y gc

clase pública TestLifeSupportSim { principal vacío

El misterio de estático público (String [] args) {


ArrayList aList = nueva ArrayList();
cinco V2Radiator v2 = nuevo V2Radiator(aList);
V3Radiator v3 = nuevo V3Radiator(aList); para(int z=0;
minutos continúa... z<20; z++) {
RetentionBot ret = nuevo RetentionBot(aList);
}
}
}

clase Unidad Sim {


Tipo de bot de cadena;
SimUnit (tipo de cadena) {
tipobot = tipo;
}
int uso de energía() {
if (“Retención”.equals(botType)) {
devolver 2;
} demás {
devolver 4;
}
}
}

Tom le dio al código una mirada rápida y una pequeña sonrisa apareció en sus labios. Creo que he
encontrado el problema, Sarah, y apuesto a que sé en qué porcentaje tus lecturas de uso de energía también están
equivocadas.

¿Qué sospechaba Tom? ¿Cómo podría adivinar los errores en las lecturas de energía y qué pocos
¿Podrías agregar líneas de código para ayudar a depurar este programa?

usted está aquí 269


Machine Translated by Google

ciclo de vida del objeto

1 copiarGC = nulo; No: esta línea intenta acceder a una variable que está
fuera de alcance.
2 gc2 = nulo; Bien, gc2 era la única variable de referencia que
se refería a ese objeto.
3 nuevoGC = gc3; No, otra variable fuera de alcance.

4 gc1 = nulo; Bien, gc1 tenía la única referencia porque newGC


está fuera de alcance.
5 nuevoGC = nulo; No, newGC está fuera de alcance.

6 gc4 = nulo; No, gc3 todavía se refiere a ese objeto.

7 gc3 = gc2; No, gc4 todavía se refiere a ese objeto.

8 gc1 = gc4; OK: reasignando la única referencia a ese objeto.

9 gc3 = nulo; No, gc4 todavía se refiere a ese objeto.

Popular
Objetos

clase pública cariño {


público estático vacío principal (String [] argumentos) {
Miel HoneyPot = nueva Miel();
Miel [] ha = {honeyPot, HoneyPot, HoneyPot, HoneyPot};

Abejas b1 = nuevas Abejas();


[Link] = ha;
Oso [] ba = nuevo Oso[5];
para (int x=0; x < 5; x++) {
Miel
ba[x] = nuevo Oso();
Objeto ba[x].hunny = tarro de miel;
}
(termina nulo)
Kit k = nuevo Kit();
[Link] = tarro de miel;
Mapache r = nuevo mapache();

[Link] = tarro de miel;


rk = k;
k = nulo;
} // fin de principal
}

270 capítulo 9
Machine Translated by Google

constructores y gc

Solución misteriosa de cinco minutos


Tom notó que el constructor de la clase V2Radiator tomó una ArrayList. Eso
significaba que cada vez que se llamaba al constructor V3Radiator, pasaba un ArrayList en su
llamada super() al constructor V2Radiator. Eso significó que se crearon cinco V2Radiator
SimUnits adicionales. Si Tom tenía razón, el uso total de energía habría sido 120, no los 100
que predijeron las proporciones esperadas de Sarah.

Dado que todas las clases de Bot crean SimUnits, escribir un constructor
para la clase SimUnit, que imprimiera una línea cada vez que se creaba una
SimUnit, habría resaltado rápidamente el problema.

usted está aquí 271


Machine Translated by Google
Machine Translated by Google

10 números y estática

Los números importan

Haz las matematicas.

este es un nuevo capitulo 273


Machine Translated by Google

Métodos matemáticos

Métodos MATEMÁTICOS: lo más cerca


alguna vez llegar a un global que puedas

Los métodos de la clase Math


no utilizan ningún valor de
variable de instancia. Y como los
métodos son "estáticos", no

es necesario tener una instancia


de Math. Todo lo que necesitas
es la clase de Matemáticas.

int x = [Link](42.2);
int y = Matemá[Link](56,12);
intz = [Link](­343);

Estos métodos nunca utilizan


variables de instancia, por lo que
su comportamiento no necesita

conocer un objeto específico.


Si intentas crear una instancia de la clase
Math:
Matemáticas mathObject = new Math();

Recibirás este error:


Ayuda de la ventana de edición de archivos IwasToldThereWouldBeNoMath

%javac PruebaMatemáticas

[Link]: Math() tiene acceso privado en


¡Este error muestra que el constructor Math
[Link]
está marcado como privado! Eso significa que
Matemáticas mathObject = new Math(); NUNCA puedes decir "nueva" clase de sobre el
^
Matemáticas para crear un nuevo objeto de Matemáticas.

1 error

274 capítulo 10
Machine Translated by Google

números y estática

La diferencia entre métodos


regulares (no estáticos) y estáticos

estático

método regular (no estático) método estático

Canción de clase pública {


El valor de la variable de instancia
Título de cadena; afecta el comportamiento de play()
Canción pública (Cadena t) { método.
público estático int min(int a, int b){
título = t;
//devuelve el menor de a y b
}
}
juego público vacío() {
Reproductor SoundPlayer = nuevo SoundPlayer();
Matemáticas

[Link](título);
mín() Sin variables de instancia.
}
máx() El comportamiento del
El valor actual de la variable de
abdominales()
método no cambia con el
instancia 'título' es la canción que se ...
Canción
estado de la variable de instancia.
título
reproduce cuando llamas a reproducir().
A mi manera

pistolas sexuales
jugar() t
C

política mi
b j
oh
Coldplay
Soh gramo
norte

t
Matemá[Link](42,36);
C

mi
b j
oh
dos instancias Soh gramo
norte

de la clase Song Utilice el nombre de la clase, en

lugar de una variable de referencia


s3
s2 nombre.

Canción
Canción
[Link]();
[Link](); ¡¡SIN OBJETOS!!
Llamar a
la
en
referencia de play() esto Llamar a play() en esta ¡Absolutamente NO HAY OBJETOS
en cualquier lugar
causará referencia hará que se en esta imagen!
“Politik” para jugar.
reproduzca “My Way”.

usted está aquí 275


Machine Translated by Google

métodos estáticos

Llamar a un método estático usando


un nombre de clase

Matemáticas Matemá[Link](88,86);
mín()
máx()
abdominales()

...

Llame a un método no estático usando un nombre


de variable de referencia

Canción t2 = nueva canción();

t2 [Link]();

Qué significa tener una


clase con métodos estáticos.

abstracto

privado

276 capítulo 10
Machine Translated by Google

números y estática

¡Los métodos estáticos no pueden usar variables


no estáticas (de instancia)!

Si intentas utilizar
una variable de instancia
desde dentro de un
método estático, el
compilador cual
piensa: "¡No sé de qué
Si intentas compilar este código: variable de instancia estás hablando!".
pato de clase pública { ¿Qué pato? Si tiene diez objetos
¿De quién es el tamaño?

tamaño int privado; Duck en el montón, un


método estático no los
público estático vacío principal (String[] args) {
[Link](“El tamaño del pato es “ + tamaño); conoce. cualquier
}
Si hay un pato en
conjunto vacío público (int s) { algún lugar del
tamaño = s; montón, no lo sabemos.
}
público int getSize() {
tamaño de retorno;
} Estoy seguro de que
No, estoy bastante seguro
} están hablando MI
de que están hablando de
de tamaño variable.
MI tamaño variable.
Recibirás este error:
Ventana de edición de archivos Ayuda Quack

% javac [Link]

[Link]: no se puede hacer referencia al tamaño de la


variable no estática desde un
contexto estático

[Link](“El tamaño del pato es”


+ tamaño);
^

usted está aquí 277


Machine Translated by Google

métodos estáticos

¡Los métodos estáticos tampoco pueden usar no existen


Preguntas tontas
métodos no estáticos!

Esto no se compilará:
Llamar a getSize() simplemente
pato de clase pública { pospone lo inevitable: getSize()
usa la variable de instancia de tamaño.
tamaño int privado;

público estático vacío principal (String[] args) {


[Link](“El tamaño es “ + getSize());
}

conjunto vacío público (int s) {


tamaño = s;
}
público int getSize() {
tamaño de retorno;
Volviendo al mismo problema...
}
¿cuyo tamaño?
}

Conector de ayuda de la ventana de edición de archivos

% javac [Link]

[Link]: no se puede hacer referencia al método no


estático getSize() desde un contexto estático

Pato d = nuevo Pato();


[Link](“El tamaño del pato es” Cadena[] s = {};
+ obtenerTamaño()); [Link](es);
^

hazlo pegado
[Link](); [Link](); [Link]();

278 capítulo 10
Machine Translated by Google

números y estática

Variable estática:
El valor es el mismo para La variable estática duckCount se
inicializa SÓLO cuando la clase
TODAS las instancias de la clase. se carga por primera vez, NO cada

pato de clase pública { vez que se crea una nueva instancia.

tamaño int privado;


privado estático int duckCount = 0;

pato público() {
clase pato { patoCount++;
Ahora seguirá
int patoCount = 0;
incrementando cada vez
}
pato público() { las ejecuciones del constructor
patoCount++; Duck, porque duckCount es
} esto siempre establecería estático y no se restablecerá a 0.
} aduckCount en 1 cada vez conjunto vacío público (int s) {
se hizo pato
tamaño = s;
}
público int getSize() {
tamaño de retorno;
}
}

Un objeto Duck no guarda su propia copia


de patoCount.
Debido a que duckCount es estático, todos los
objetos Duck comparten una única copia. Puedes
pensar en una variable estática como una variable
que vive en una CLASE en lugar de en un objeto.
Pato

tamaño: 20 tamaño

pato estáticoCount tamaño: 22


patoContar: 4
patoContar: 4

DtuCk bj miCt
oh
obtenerTamaño()

establecerTamaño()
DtuCk bj miCt
oh

tamaño: 8
tamaño: 12
patoContar: 4 Cada objeto
variable de Duck tiene su propio
patoContar: 4
hay una tamaño, pero solo
DtuCk bj miCt copia de duckCount
oh
DtuCk bj miCt
oh
variable: la de la clase.

usted está aquí 279


Machine Translated by Google

variables estáticas

variable
niño instancia dos
estática: helado
niño ejemplo uno

variables de instancia: 1 por instancia

variables estáticas: 1 por clase

Barra cerebral
cerebro
con barra

280 capítulo 10
Machine Translated by Google

números y estática

Inicializando una variable estática

Todas las variables estáticas


de una clase se
inicializan y se antes
puede crear cualquier
objeto de esa clase.

jugador de clase { playerCount se inicializa cuando se carga la clase.


Lo inicializamos explícitamente en 0, pero no es necesario ya que 0
estático int playerCount = 0;
es el valor predeterminado para los enteros. Las variables estáticas
nombre de cadena privada; obtienen valores predeterminados al igual que las variables de instancia.

Reproductor público (Cadena n) {


nombre = n;

jugadorCount++; Los valores predeterminados para las variables estáticas y de


} instancia declaradas pero no inicializadas son los mismos:

} enteros primitivos (largos, cortos, etc.): 0

puntos flotantes primitivos (flotante, doble): 0,0


clase pública PlayerTestDrive { booleano: falso
público estático vacío principal (String [] argumentos) {
referencias de objetos: nulo
[Link]([Link]);

Jugador uno = nuevo jugador ("Tiger Woods");

[Link]([Link]);
} Acceda a una variable estática como a un método
} estático: con el nombre de la clase.

Ayuda de la ventana de edición de archivos ¿Qué?

% java PlayerTestDrive
0 antes de que se hagan instancias
1
después de crear un objeto

usted está aquí 281


Machine Translated by Google

constantes finales estáticas

las variables finales estáticas son constantes


final
Un inicializador estático es un bloque
de código que se ejecuta cuando
se carga una clase, antes de que
público estático final doble PI = 3,141592653589793; cualquier otro código pueda
usar la clase, por lo que es un
público
excelente lugar para inicializar
estático una variable final estática.
clase Foo {
final estático int x;
final
estático {
x = 42;

Inicializar un final variable estática:

1 Al momento de declararlo: Si no le da un valor a una variable final en uno de esos


clase pública Foo { dos lugares:
público estático final int FOO_X = 25;
} barra de clase pública {
público estático final doble BAR_SIGN;
observe que las variables No
nombre convención ­ estática } inicialización!
el
finales nombradas son constantes, por lo que
debe estar todo en mayúsculas,
con
O subrayado separando
las palabras
El compilador lo detectará:

2 En un inicializador estático: Conector de ayuda de la ventana de edición de archivos

barra de clase pública { % javac [Link]


público estático final doble BAR_SIGN;
[Link]: es posible que la variable
estático { BAR_SIGN no se haya inicializado
BAR_SIGN = (doble) [Link](); 1 error
}
}

este código se ejecuta tan pronto como se carga


la clase, antes de cualquier
se llama e incluso se método estático antes
puede usar variable. de cualquier estático

282 capítulo 10
Machine Translated by Google

números y estática

final no es sólo para


variables estáticas...
final

variables finales no estáticas


clase Foof {
ahora no puedes cambiar el tamaño
tamaño int final = 3;
final int whuffie;

Tonto() {
buf = 42; ahora no puedes cambiar whuffie
}

void hacer cosas (final int x) {


// no puedes cambiar x
}

anular hacerMás() {
final int z = 7;
// no puedes cambiar z Es todo tan... así final .
} que quiero decir, conocido
} si lo hiciera no sería capaz
de cambiar las cosas...

método final
clase puf {
calcWhuffie anulado final () {
// cosas importantes
// eso nunca debe ser anulado
}
}

clase final
clase final MiClaseMásPerfecta {
// no se puede ampliar
}

usted está aquí 283


Machine Translated by Google

estática y final

no existen
Preguntas tontas
PUNTOS DE VIÑETA

Se debe llamar a un método estático usando el nombre de la


clase en lugar de una variable de referencia de objeto:
[Link]() vs. [Link]()

Se puede invocar un método estático sin ninguna instancia de la clase


del método en el montón.

Un método estático es bueno para un método de utilidad que no


depende (y nunca dependerá) de un valor de variable de instancia
particular.

Un método estático no está asociado con una instancia particular,


solo con la clase, por lo que no puede acceder a ningún valor de
variable de instancia de su clase. No sabría qué valores de instancia
usar.

Un método estático no puede acceder a un método no estático, ya

que los métodos no estáticos generalmente están asociados con el


estado de la variable de instancia.

Si tiene una clase con solo métodos estáticos y no desea que se cree
una instancia de la clase, puede marcar el constructor como privado.

Una variable estática es una variable compartida por todos los


miembros de una clase determinada. Solo hay una copia de una
variable estática en una clase, en lugar de una copia por cada
instancia individual, por ejemplo, variables de instancia.

Un método estático puede acceder a una variable estática.

Para crear una constante en Java, marque una variable como estática
y final.

A una variable estática final se le debe asignar un valor en el momento


en que se declara o en un inicializador estático. estático {

CÓDIGO_PERRO = 420;
}

La convención de nomenclatura para las constantes (variables


estáticas finales) es poner el nombre en mayúsculas.

El valor de una variable final no se puede cambiar una vez que se ha


asignado.

La asignación de un valor a una variable de instancia final debe


realizarse en el momento de su declaración o en el constructor.

No se puede anular un método final.

Una clase final no se puede ampliar (subclasificar).

284 capítulo 10
Machine Translated by Google

números y estática

Afila tu lápiz

¿Qué es legal?

1 clase pública Foo {


estático int x;

público vacío ir() clase pública Foo4 { static final


4
{ [Link](x); int x = 12;
}
} público vacío ir()
{ [Link](x);
}
}

2 clase pública Foo2 { int x;

vacío estático público ir () { clase pública Foo5 { static final


5
[Link](x); int x = 12;
}
} public void go(final int x) { [Link](x);

}
}

3 clase pública Foo3 { final int x;

6 clase pública Foo6 { int x = 12;


público vacío ir()
{ [Link](x);
} public static void go(final int x) { [Link](x);
}
}
}

usted está aquí 285


Machine Translated by Google

Métodos matemáticos

Métodos matemáticos

Matemá[Link]()

Devuelve un doble entre 0,0 y (pero sin incluir) 1,0.

doble r1 = [Link]();
int r2 = (int) ([Link]() * 5);

Matemá[Link]()
Devuelve un doble que es el valor absoluto de

el argumento. El método está sobrecargado, por lo


que si le pasa un int, devuelve un int. Pásale un doble
y te devuelve un doble.

int x = Matemá[Link](­240); // devuelve 240


doble d = [Link](240,45); // devuelve 240,45

Matemá[Link]()

Devuelve un int o long (dependiendo de si el


argumento es flotante o doble) redondeado al valor
entero más cercano.

int x = [Link](­24.8f); // devuelve ­25


int y = [Link](24.45f); // devuelve 24

Recuerde, se supone que los literales de coma


flotante son dobles a menos que agregue la 'f'.
Matemá[Link]()
Devuelve un valor que es el mínimo de

dos argumentos. El método está sobrecargado para


aceptar enteros, largos, flotantes o dobles.
int x = Matemá[Link](24,240); // devuelve 24
doble y = [Link](90876.5, 90876.49); // devuelve 90876,49

Matemá[Link]()
Devuelve un valor que es el máximo de los dos
argumentos. El método está sobrecargado para
aceptar enteros, largos, flotantes o dobles.
intx = [Link](24,240); // devuelve 240
doble y = [Link](90876.5, 90876.49); // devuelve 90876,5

286 capítulo 10
Machine Translated by Google

números y estática

Envolviendo una primitiva

entero x = 32;
Lista ArrayList = nueva ArrayList();
[Link](x);

¡Esto no funcionará a menos que estés usando Java 5.0 o

superior! ¡No hay ningún método add(int) en ArrayList que tome un


int! (ArrayList solo tiene métodos add() que toman referencias de objetos,
no primitivos).

Booleano

Personaje

Byte ¡Cuidado! Los nombres no están


int primitivo
Corto asignados exactamente a los tipos
primitivos. Los nombres de las clases
Entero están completamente explicados. Objeto entero
Largo
Flotar t
En t C
mi
Doble I t mi mi ohbj
r
norte
gramo

Entregue la primitiva al constructor


del contenedor. Eso es todo.
envolviendo un valor
intyo = 288;
Entero iWrap = nuevo entero(i);
Todos los envoltorios
funcionan así. Boolean tiene
un booleanValue(), Character
envolviendo un valor
Naciones Unidas
tiene un charValue(), etc. Nota: la imagen de arriba es un chocolate envuelto en papel de aluminio.
int desenvuelto = [Link](); ¿Consíguelo? ¿Envoltura? Algunas personas piensan que parece una papa al horno,
pero eso también funciona.

usted está aquí 287


Machine Translated by Google

métodos estáticos

Esto es estúpido. ¿Quieres decir que no


puedo simplemente hacer una ArrayList de
enteros? ¿Tengo que envolver cada uno de ellos en un nuevo
objeto Integer y luego desenvolverlo cuando intento acceder
a ese valor en ArrayList?
Eso es una pérdida de tiempo y un error
esperando a ocurrir...

Antes de Java 5.0, TÚ tenías que hacer el trabajo...

Una ArrayList de entradas primitivas

Sin autoboxing (versiones Java antes 5.0)


Haz una ArrayList. (Recuerde, antes de 5.0 no se podía especificar
vacío público doNumsOldWay() { el TIPO, por lo que todas las ArrayLists eran listas de Objetos).

ArrayList listaDeNúmeros = nueva ArrayList();


No puede agregar la primitiva '3' a la lista, por lo
[Link](nuevo entero(3)); que primero debe envolverla en un número entero.

Entero uno = (Entero) [Link](0); Aparece como tipo


Objeto, pero puedes
int intOne = [Link](); convertir el Objeto en un número entero.
}

Finalmente puedes sacar la


primitiva del Integer.

288 capítulo 10
Machine Translated by Google

números y estática

Autoboxing: desdibujando
la línea entre primitivo y objeto

Una ArrayList de entradas primitivas

Con autoboxing (versiones Java 5.0 o superiores)

Haga una ArrayList de tipo Integer.


vacío público doNumsNewWay() {

ArrayList<Integer> listOfNumbers = new ArrayList<Integer>();

listaDeNú[Link](3); ¡Solo agrégalo! Aunque NO existe un método en ArrayList


para add(int), el compilador hace todo el
int num = listaDeNú[Link](0); empaquetado por usted. En otras palabras,
} realmente HAY un objeto Integer almacenado
en ArrayList, pero puedes "fingir" que ArrayList
Y el compilador desenvuelve automáticamente (descomprime) toma enteros. (Puede agregar tanto enteros
el objeto Integer para que puedas asignar el valor int como enteros a un ArrayList<Integer>.)
directamente a una primitiva sin tener que llamar al
Método intValue() en el
objeto Integer.

usted está aquí 289


Machine Translated by Google

métodos estáticos

Autoboxing funciona en casi todas partes

Diversión con autoboxing

Argumentos del método 3


Si un método toma un tipo de contenedor, 3
puede pasar una referencia a un contenedor t
o una primitiva del tipo coincidente. Y, por I t j
C
mi En t
mi mir ohb
norte

supuesto, ocurre lo contrario: si un gramo

método toma una primitiva, puede pasar


una primitiva compatible o una referencia a
un contenedor de ese tipo primitivo. void tomarNúmero(Entero i) { }

Valores de retorno int darNúmero() { return x;

Si un método declara un tipo de retorno


primitivo, puede devolver un primitivo }
compatible o una referencia al contenedor
de ese tipo primitivo.
3
Y si un método declara un tipo de retorno 3
de contenedor, puede devolver una t
I t j
C
mi
referencia al tipo de contenedor o una mi mir ohb
norte

gramo
En t
primitiva del tipo coincidente.

Expresiones booleanas verdadero

En cualquier lugar donde se espere un valor verdadero

booleano, puede usar una expresión que se t


bohoh C
mia ohbj
evalúe como un valor booleano (4 > 2), yo mi booleano
norte

o un booleano primitivo, o una referencia a


un contenedor booleano.
si (booleano) {
[Link](“verdadero”);
}

290 capítulo 10
Machine Translated by Google

números y estática

Operaciones con números

Este es probablemente el más extraño: sí, ahora puede


usar un tipo contenedor como operando en
operaciones donde se espera el tipo primitivo. ¡Eso 3
significa que puede aplicar, digamos, el operador 3
de incremento contra una referencia a un objeto entero! t
I t j
C
mi
mi mir ohb
norte

gramo
En t
Pero no te preocupes, esto es sólo un truco del compilador.
El lenguaje no fue modificado para que los
operadores trabajaran en objetos; el compilador yo ++;
simplemente convierte el objeto a su tipo primitivo
antes de la operación. Aunque seguro que parece
raro.

Entero i = nuevo entero (42);


yo ++;

Y eso significa que también puedes hacer cosas como:

Entero j = nuevo entero(5);


Entero k = j + 3;

Asignaciones 3
3
Puede asignar un contenedor o una primitiva a una
t
variable declarada como contenedor o primitiva I t j
C
mi
mi mir ohb
norte

coincidente. Por ejemplo, una variable int primitiva gramo


En t
se puede asignar a una variable de referencia
Integer y viceversa: se puede asignar una
referencia a un objeto Integer a una variable
Doble d = x;
declarada como primitiva int.

Afila tu lápiz Caja de prueba de clase pública {

Entero yo;
¿Se compilará este código? ¿Funcionará? Si se intj;
ejecuta, ¿qué hará?
público estático vacío principal (String[] args) {
Tómate tu tiempo y piensa en esto; trae a TestBox t = nuevo TestBox();
colación una implicación del autoboxing de [Link]();
la que no hablamos. }

Tendrás que ir a tu compilador para vacío público ir () {


encontrar las respuestas. (Sí, te obligamos j=yo;
a experimentar, por tu propio bien, por supuesto). [Link](j);
[Link](i);
}
}

usted está aquí 291


Machine Translated by Google

métodos de envoltura

¡Pero espera! ¡Hay más! ¡Los contenedores


también tienen métodos de utilidad estáticos!

Convertir una cadena en un No hay problema para


valor primitivo es fácil: analizar "2" en 2.

Cadena s = “2”;
int x = [Link](s);
doble d = [Link](“420.24”);

booleano b = nuevo booleano(“verdadero”).booleanValue();

Pensarías que habría un


[Link](), ¿no? Pero no lo hay.
Afortunadamente, existe un constructor booleano
que toma (y analiza) una cadena y luego obtienes
el valor primitivo al desenvolverla.

Pero si intentas hacer esto:


UH oh. Esto se compila muy bien, pero en
Cadena t = “dos”;
tiempo de ejecución explota. Cualquier
int y = [Link](t); cosa que no pueda analizarse como un
número provocará una excepción NumberFormatException.

Obtendrá una excepción de tiempo de ejecución:

Pista de ayuda de la ventana de edición de archivos

Cada método o
% Envoltorios de Java
constructor que analiza una
Excepción en el hilo "principal"
cadena puede generar una
[Link]: dos excepción NumberFormatException.
en [Link]([Link]) Es una excepción de tiempo de

en [Link]([Link]) ejecución, por lo que no es


necesario manejarla ni declararla.
en [Link]([Link])
Pero quizás quieras hacerlo.

(Hablaremos sobre excepciones en el


próximo capítulo).

292 capítulo 10
Machine Translated by Google

números y estática

Y ahora a la inversa... convirtiendo


un número primitivo en una Cadena

Recuerde que el operador '+' está sobrecargado


en Java (el único operador sobrecargado) como un
doble d = 42,5; concatenador de cadenas. Todo lo que se agrega a
“”
Cadena doblecadena = + d; una cadena se convierte en cadena.

doble d = 42,5;
Cadena dobleString = [Link](d);

Otra forma de hacerlo usando un método


estático en la clase Double.
Sí,
pero ¿cómo hago para
que parezca dinero? Con un signo ¿Dónde está mi printf
de dólar y dos decimales como como el que tengo en
$56,87 o qué pasa si quiero comas
C? ¿El formato de números es
como 45.687.890 o qué pasa si parte de las clases de E/S?
lo quiero en...

usted está aquí 293


Machine Translated by Google

formato de número

Formato de números

Formatear un número para usar comas

formatos de prueba de clase pública { El número a formatear


(queremos que tenga comas).
público estático vacío principal (String[] args) {

Cadena s = [Link](“%, d”, 1000000000);


[Link](s);
}
}
Las instrucciones de formato sobre cómo formatear el
segundo argumento (que en este caso es un valor int).
Recuerde, aquí solo hay dos argumentos para este método:
[Link] la primera coma está DENTRO del literal de cadena, por
lo que no separa los argumentos del método de formato.

Ahora insertamos comas en el número.

294 capítulo 10
Machine Translated by Google

números y estática

Formato deconstruido...

1 instrucciones de formato
Se utilizan especificadores de formato especiales que
describen cómo se debe formatear el argumento.
Nota: si ya conoce printf() de c/C+
+, probablemente pueda hojear las
2 El argumento que se va a formatear. siguientes páginas. De lo contrario,
¡lee atentamente!
Aunque puede haber más de un argumento, comenzaremos
con solo uno. El tipo de argumento no puede ser
cualquier cosa... tiene que ser algo que pueda formatearse
usando los especificadores de formato en las instrucciones de formato.
Por ejemplo, si sus instrucciones de formato especifican un
número de punto flotante, no puede pasar un perro o incluso
una cadena que parezca un número de punto flotante.

Hacer esto... a esto.


1 2

formato(“%, d”, 1000000000);

Utilice estas instrucciones... sobre este argumento.

¿Qué dicen realmente estas instrucciones?

¿Cómo dicen eso?

usted está aquí 295


Machine Translated by Google

el método formato()

El porcentaje (%) dice "inserte el argumento aquí" (y


formatéelo siguiendo estas instrucciones)

Más caracteres para


Especificadores de formato para
incluir en la cadena después de
Caracteres a incluir el segundo argumento del
formatear e insertar el
método (el número).
en la cadena final segundo argumento. Argumento que se
devuelta por format(). va a formatear.

format(“Tengo %.2f errores que corregir.”, 476578.09876);

Producción Tengo errores 476578.10 que corregir.

Note que Perdí


algunos de los números.

después
¿Qué del punto
significa ".2f"?decimal. Puedes adivinar

Agregando una coma

format(“Tengo %.2f errores que corregir.”, 476578.09876);

Tengo 476.578,10 errores que solucionar.

Al cambiar las instrucciones de


formato de “%.2f” a %,.2f”,
obtuvimos una coma en el número formateado.

296 capítulo 10
Machine Translated by Google

números y estática

Pero, ¿cómo SABE siquiera


dónde terminan las instrucciones y
comienzan el resto de los personajes? ¿Cómo
es que no imprime la “f” en “%.2f”? O
el 2"? ¿Cómo sabe que el .2f era parte de las
instrucciones y NO parte de la cadena?

El formato String utiliza su


propia sintaxis de lenguaje.

[Link](“Tengo %.2f, errores que corregir.”, 476578.09876);

usted está aquí 297


Machine Translated by Google

especificador de formato

El especificador de formato

Un especificador de formato puede tener hasta cinco partes diferentes (sin incluir el
"%"). Todo lo que está entre corchetes [ ] a continuación es opcional, por lo que solo se requieren
el porcentaje (%) y el tipo. Pero el orden también es obligatorio, por lo que cualquier pieza
que SÍ utilices debe ir en este orden.

%[número de argumento][banderas][ancho][.precisión]tipo

Llegaremos a esto más Esto define el Ya sabes que el tipo es obligatorio... define
adelante... te permite Estos son para número MÍNIMO de (ver la página siguiente) la precisión. En
decir QUÉ argumento más caracteres que se
si hay más de uno. opciones de formato otras palabras, "d" para un decimal
(No te preocupes utilizarán. Eso es establece el número entero o "f" para
especiales, como
por eso todavía). insertar comas, *mínimo* no lugares decimales.
un punto flotante. No
TOTAL. Si el número es olvides incluir el "." ahí.
poner números
negativos entre más largo que el número.
paréntesis o ancho, aún se usará en
suizquierda.
justificar los números a la totalidad, pero si es
menor que el ancho, se
completará con ceros.

%[número de argumento][banderas][ancho][.precisión]tipo

formato(“%,6.1f”, 42.000);

No hay ningún "número de argumento"

especificado en este formato de


cadena, pero todas las demás piezas están ahí.

298 capítulo 10
Machine Translated by Google

números y estática

El único especificador requerido es para TIPO

El TIPO es obligatorio, todo lo demás es opcional.

%d decimal
¡Un 42,25 no funcionaría! Sería lo
formato(“%d”, 42);
mismo que intentar asignar directamente
un doble a un
42 variable interna.

%F punto flotante
Aquí combinamos la “f” con un
formato(“%.3f”, 42.000000); indicador de precisión.
“.3” así que terminamos con
42.000 tres ceros.

%X hexadecimal
formato(“%x”, 42);

2a

%C personaje

formato(“%c”, 42);
El número 42 representa el

* carácter “*”.

usted está aquí 299


Machine Translated by Google

argumentos de formato

¿Qué pasa si tengo más de un argumento?

int uno = 20456654;


doble dos = 100567890,248907;
String s = [Link](“El rango es %,d de %,.2f”, uno, dos);

El puesto es 20.456.654 sobre 100.567.890,25 Cuando tiene más de un


argumento, se insertan
Agregamos comas a ambas usando el orden en el que
ellos al formato()
método de pase.
variables y restringimos el número
de punto flotante (la segunda
variable) a dos decimales.

300 capitulo 10
Machine Translated by Google

números y estática

En cuanto a los números, ¿qué pasa con las fechas?

La fecha y hora completa %tc

[Link](“%tc”, nueva fecha());

Domingo 28 de noviembre 14:52:41 MST 2004

justo el tiempo %tr

[Link](“%tr”, nueva fecha());

15:01:47

Día de la semana, mes y día. %tA %tB %td

Pero eso significa que tengo que


pasamos
una para el objeto Fecha tres veces,
cada parte del formato que
Fecha de hoy = nueva fecha(); queremos. En otras palabras, el %tA nos
[Link](“%tA, %tB %td”,hoy,hoy,hoy); dará solo el día de la semana, pero luego
tendrá que hacerlo nuevamente para
nosotros

La coma no forma parte del formato... es sólo el obtener solo el mes y nuevamente
carácter que queremos imprimir después del primer el día del mes. Para el
argumento formateado insertado.

Domingo 28 de noviembre

Igual que el anterior, pero sin duplicar los argumentos %tA %tB %td

Fecha de hoy = nueva fecha(); El corchete angular “<” es simplemente


otro indicador en el especificador que
[Link](“%tA, %<tB %<td”,hoy);
le dice al formateador que “use el argumento
Puedes pensar en esto como llamar a tres métodos anterior nuevamente”. Por lo tanto, le evita
getter diferentes en el objeto Date, para obtener tres datos repetir los argumentos y, en su lugar,
diferentes de él. formatea el mismo argumento de tres maneras diferentes.

usted está aquí 301


Machine Translated by Google

manipulando fechas

A ver... ¿cuántos días


laborables habrá si el
proyecto empieza el 27 de febrero
y finaliza el 5 de agosto?

Trabajar con fechas

302 capítulo 10
Machine Translated by Google

números y estática

Retroceder y avanzar en el tiempo

Parece que [Link] en realidad está... desactualizado

Utilice [Link] para su fecha manipulación

usted está aquí 303


Machine Translated by Google

conseguir un calendario

Obtener un objeto que extienda el Calendario

Esto NO FUNCIONA:
¡El compilador no permitirá esto!
Calendario cal = nuevo Calendario();

En su lugar, utilice el método estático “getInstance()”:

Calendario cal = [Link]();


Esta sintaxis debería resultarle familiar en este
punto: estamos invocando un método estático.

Espera un minuto.
Si no puede crear una
instancia de la clase
Calendario, ¿qué está asignando
exactamente a esa referencia
de Calendario?

No puede obtener una instancia de Calendar, pero puede


obtener una instancia de una subclase de Calendar
concreta.

304 capítulo 10
Machine Translated by Google

números y estática

Trabajar con objetos de calendario

Un ejemplo de trabajo con un objeto Calendario:


Fije la hora para el 7 de enero de 2004 a las 15:40.
Calendario c = [Link](); (Observe que el mes tiene base cero).

[Link](2004,0,7,15,40);
Convierta esto a una gran
cantidad de milisegundos.
día largo1 = [Link]();

día1 += 1000 * 60 * 60; Agregue el equivalente a una hora en milisegundos y luego actualice la hora.
(Observe el “+=”, es como día1 = día1 +...).
[Link](día1);

[Link](“nueva hora” + [Link](c.HORA_OF_DAY));

[Link]([Link], 35); Agregue 35 días a la fecha, lo


que debería llevarnos a febrero.
[Link] ("agregar 35 días" + [Link]());

[Link]([Link], 35);
“Avanzar” 35 días hasta esta fecha.
[Link] ("rollo 35 días" + [Link]()); ¡Esto “adelanta” la fecha 35 días,
pero NO cambia el mes!
[Link]([Link], 1);

[Link](“establecido en 1” + [Link]());
No estamos incrementando aquí, simplemente
haciendo un "conjunto" de la fecha.

Ayuda de la ventana de edición de archivos El tiempo vuela

nueva hora 16
agregar 35 días miércoles 11 de febrero 16:40:41 MST 2004
Este resultado confirma cómo
funcionan millis, add, roll y set.
rodar 35 días martes 17 de febrero 16:40:41 MST 2004
establecido en 1 domingo 01 de febrero 16:40:41 MST 2004

usted está aquí 305


Machine Translated by Google

API de calendario

Aspectos destacados de la API del Calendario

306 capítulo 10
Machine Translated by Google

números y estática

¡Aún más estática!... importaciones estáticas

Algún código antiguo:

importar [Link];

clase no estática {

público estático vacío principal (String [] argumentos) {

[Link](“sqrt” + Matemá[Link](2.0));

[Link](“bronceado“ + Matemá[Link](60));

}
La sintaxis que se utilizará al
} declarar importaciones estáticas.

Mismo código, con importaciones estáticas:


Advertencias y trampas
importar [Link] estático;

importar [Link].* estático; Si solo va a utilizar un miembro estático unas pocas


veces, creemos que debería evitar las
clase con estática {
importaciones estáticas para ayudar a que el
código sea más legible.
público estático vacío principal (String [] argumentos) {
Si va a utilizar mucho un miembro estático (como
[Link](“sqrt “ + raíz cuadrada (2.0));
hacer muchos cálculos matemáticos), entonces

[Link](“bronceado “ + bronceado(60)); probablemente esté bien utilizar la importación estática.

Tenga en cuenta que puede utilizar comodines (.*) en


}
su declaración de importación estática.
}
Un gran problema con las importaciones
estáticas es que no es demasiado difícil crear
Importaciones estáticas en acción. conflictos de nombres. Por ejemplo, si tiene
dos clases diferentes con un método “add()”,
¿cómo sabrán usted y el compilador cuál usar?

usted está aquí 307


Machine Translated by Google

estático versus instancia

Charla de esta noche: Una variable de


instancia realiza golpes bajos a una variable estática

Instancia variable Variable estática

308 capítulo 10
Machine Translated by Google

números y estática

Instancia variable Variable estática

usted está aquí 309


Machine Translated by Google

ser el compilador

El archivo Java en esta página


representa un programa completo. Su
trabajo es jugar al compilador y
determinar si este archivo se
compilará. Si no se
compila, ¿cómo lo
clase EstáticaSuper{
solucionaría y, si se compila, cuál sería el resultado?

estático {

[Link](“bloque súper estático”);

EstáticoSuper{

[Link](

“superconstructor”);

} Ventana de edición de archivos Ayuda Cling

%pruebas estáticas de Java


bloque estático 4
La clase pública StaticTests extiende StaticSuper {
en principal
int rand estático;
bloque súper estático

súper constructor
estático {
constructor
rand = (int) ([Link]() * 6);

[Link] ("bloque estático" + rand);

Pruebas estáticas() {

[Link](“constructor”); Archivo Editar Ventana Ayuda Electricidad

} %pruebas estáticas de Java


bloque súper estático
bloque estático 3
público estático vacío principal (String [] argumentos) {
en principal
[Link](“en principal”);
súper constructor
Pruebas estáticas st = nuevas pruebas estáticas();
constructor
}

310 capítulo 10
Machine Translated by Google

números y estática

estático

usted está aquí 311


Machine Translated by Google

imanes de código

día largo1 = [Link]();

[Link](2004,1,7,15,40);

importar [Link] estático;

estático int DAY_IM = 60 * 60 * 24;


(“luna llena en %tc”, c));
([Link]
Calendario c = nuevo Calendario();
clase Lunas llenas {

público estático vacío principal (String [] argumentos) {

día1 += (DAY_IM * 29,52);

para (int x = 0; x < 60; x++) {

estático int DAY_IM = 1000 * 60 * 60 * 24;


imprimir

importar [Link].*;
(“luna llena en %t”, c));
importar [Link].*;

importación estática [Link];

[Link](2004,0,7,15,40); [Link]
Ventana de edición de archivos Ayuda Howl

% java Lunas llenas


Luna llena el viernes 06 de febrero 04:09:35 MST 2004 Luna
[Link](día1);
([Link]
llena el sábado 06 de marzo 16:38:23 MST 2004
luna llena el lunes 05 de abril 06:07:11 MDT 2004
Calendario c = [Link]();

312 capítulo 10
Machine Translated by Google

números y estática

Verdadero o falso

FALSO

FALSO

Verdadero

FALSO

Verdadero

FALSO

EstáticoSuper( ) {
Verdadero
[Link](

“superconstructor”);

} Verdadero

StaticSuper es un constructor y debe tener ( ) en FALSO


su firma. Tenga en cuenta que, como lo demuestra
el resultado a continuación, los bloques estáticos para
ambas clases se ejecutan antes de que se ejecute
FALSO
cualquiera de los constructores.

FALSO

Ventana de edición de archivos Ayuda Cling Verdadero

%pruebas estáticas de Java


bloque súper estático
bloque estático 3
FALSO

en principal

súper constructor FALSO


constructor

usted está aquí 313


Machine Translated by Google

solución de imanes de código

importar [Link].*;

importar [Link] estático;

clase Lunas llenas {

estático int DAY_IM = 1000 * 60 * 60 * 24;

público estático vacío principal (String [] argumentos) {

Calendario c = [Link]();

[Link](2004,0,7,15,40);

día largo1 = [Link]();

para (int x = 0; x < 60; x++) {

día1 += (DÍA_IM * 29,52)

[Link](día1);

[Link]([Link](“luna llena en %tc”, c));

Ventana de edición de archivos Ayuda Howl

% java FullMoons luna


llena el viernes 06 de febrero 04:09:35 MST 2004
luna llena el sábado 06 de marzo 16:38:23 MST 2004 luna
llena el lunes 05 de abril 06:07:11 MDT 2004

314 capítulo 10
Machine Translated by Google

11 manejo de excepciones

Comportamiento riesgoso
Claro que es
arriesgado, pero puedo
manejarlo si algo sale mal.

Estas cosas pasan. El archivo no está ahí. El servidor está caído.

este es un nuevo capitulo 315


Machine Translated by Google

construyendo el reproductor de música MIDI

Hagamos una máquina de música.

El BeatBox terminado se parece a esto:

Para crear un bucle de beatbox (un patrón de batería de 16 tiempos),


coloque marcas de verificación en las casillas.

tu mensaje, que se
envía a los demás
ritmo de baile
jugadores, junto con tu
patrón de ritmo actual,
cuando presionas "Enviar"
Andy: ritmo #2

Chris: groove2 revisado

Nigel: ritmo de baile mensajes entrantes de


de otros jugadores. Haga clic

va
en uno para cargar el patrón que
con él y luego haga clic
'Comienza' a jugarlo.

316 capítulo 11
Machine Translated by Google

manejo de excepciones

Empezaremos con lo básico.

archivo midi
El archivo MIDI tiene
información sobre cómo se

debe reproducir una canción, pero


no tiene datos de sonido reales.
Es algo así como las
La API de sonido Java
instrucciones de una partitura para un piano.

Instrumento compatible con MIDI

El dispositivo MIDI sabe cómo

"leer" un archivo MIDI y reproducir el


sonido. El dispositivo puede ser un

teclado sintetizador o algún otro tipo


Vocero
de instrumento.

Por lo general, un instrumento

MIDI puede reproducir MUCHOS


sonidos diferentes (piano, batería,
violín, etc.) y todos al mismo tiempo.
Entonces, un archivo MIDI no es como

una partitura para un solo músico en


la banda: puede contener las partes

de TODOS los músicos que tocan

una canción en particular.

usted está aquí 317


Machine Translated by Google

pero parecía tan simple

Primero necesitamos un secuenciador.

importar el paquete [Link]


importar [Link].*; Necesitamos un objeto secuenciador. Es
la parte principal del dispositivo/instrumento
clase pública MusicTest1 {
MIDI que estamos usando. Es lo que,

juego público vacío() { bueno, secuencia toda la información MIDI en


una "canción". Pero no fabricamos uno
Secuenciador secuenciador = [Link]();
nuevo nosotros mismos: tenemos que pedirle

[Link](“Tenemos un secuenciador”); al MidiSystem que nos proporcione uno.

} // cerrar juego

público estático vacío principal (String [] argumentos) {


PruebaMúsica1 mt = nueva PruebaMúsica1();

[Link]();
} // cerrar principal

} // cerrar clase ¡Algo esta mal!


¡Este código no se compilará! El compilador dice que hay
una "excepción no informada" que debe detectarse o declararse.
Ayuda de la ventana de edición de archivos ¿Qué dices?

% javac [Link]

[Link]: excepción [Link] no reportada.


MidiNo disponibleExcepción; debe ser atrapado o declarado arrojado

Secuenciador secuenciador = [Link]();


^

1 errores

318 capítulo 11
Machine Translated by Google

manejo de excepciones

¿Qué sucede cuando un método al que deseas llamar


(probablemente en una clase que no escribiste) es riesgoso?

smis mit hohds


w r it mi
at tu metro

th en
1 Digamos que quieres
llamar a un método en un
clase vaca {
barra de clase { muu vacío() {
ir vacío() { si (servidorAbajo){

clase que no escribiste. mugir();

}
}
explotar();

} int cosas() {
}
[Link]();
}
}

tu codigo clase que


tú no escribiste

2 Ese método no clase vaca {


muu vacío() {
si (servidorAbajo){
muu vacío() {
explotar();

algo arriesgado, algo que }


}
}

si (servidor caído) {
podría no funcionar en tiempo de explotar();
ejecución. }
clase que
no escribiste }

Mi método
Me pregunto moo()
si ese método explotará si el
3 Necesitas saber servidor no funciona.
podría explotar...
que el método al que

estás llamando es clase vaca {


muu vacío() {
si (servidorAbajo){
explotar();

arriesgado. }
}
}

clase que
no escribiste

Ahora que lo
sé, puedo tomar
precauciones.

wr i t mi saFmiyo
4 Luego escribes el código y
que puede manejar la falla si
hace barra de clase {
ir vacío() {
intentar{
mugir();
}captura(MX m){

suceder. Tienes que estar preparado, }


llorar();

}
}
por si acaso.
tu codigo

usted está aquí 319


Machine Translated by Google

cuando las cosas pueden salir mal

Los métodos en Java utilizan excepciones para decir el código de llamada,

“Algo malo sucedió. Fallé."

lanza

El método getSequencer() corre un riesgo. Puede fallar en tiempo de ejecución.


Por eso debe 'declarar' el riesgo tú toma cuando lo llames.

Los documentos de la API


le dicen que

getSequencer() puede

generar una excepción: MidiUnavailableException.


Un método tiene que declarar

las excepciones que podría


tirar.

Esta parte le indica CUÁNDO podría obtener esa


excepción, en este caso, debido a restricciones de

recursos (lo que podría significar simplemente que el secuenciador


ya se está utilizando).

320 capítulo 11
Machine Translated by Google

manejo de excepciones

Estimado compilador,

Sé que estoy tomando un riesgo aquí, pero


El compilador necesita saber ¿no crees que vale la
pena? ¿Qué
TÚ llamando a un método
que estás tengo que hacer?

arriesgado. firmado, geek


en
Waikiki

trata de atraparlo

Querido geek,

La vida es corta (especialmente en


el montón).

Tomar el riesgo. intentalo . Pero por si acaso


las
cosas no funcionan,
asegúrate
importar [Link].*; de captar
cualquier

problemas antes de que se desate el infierno.


clase pública MusicTest1 {

juego público vacío() {

intentar {
Ponga lo arriesgado en
Secuenciador secuenciador = MidiSystem. getSecuenciador();
un bloque de "intentar".
[Link](“Obtuve un secuenciador con éxito”);

} captura (MidiUnavailableException ex) {


[Link](“Qué fastidio”);
}
} // cerrar juego
hacer una

bloque
hacer si ocurre 'catch' para saber qué
algo
público estático vacío principal (String [] argumentos) {
situación
PruebaMúsica1 mt = nueva PruebaMúsica1();
excepcional; en otras palabras, a
[Link](); MidiUnavailableException
es aventado
} // cerrar principal mediante la llamada a getSequencer().
} // cerrar clase

usted está aquí 321


Machine Translated by Google

las excepciones son objetos

Voy a
INTENTAR esta cosa
arriesgada y
me ATRAPARÉ si me caigo.

Una excepción es un objeto...


de tipo Excepción.

No intentes esto en casa.


atrapar

arrojable

obtener mensaje() intentar {


imprimirStackTrace()
// hacer algo arriesgado es como declarar el
argumento de un método.
Parte de la jerarquía de
clases de excepción. Todos
Excepción
} captura (Excepción ex) {
extienden la clase
Throwable y heredan dos claves. // intenta recuperarte
métodos.
}
Este código solo se
Si una
ejecuta. Se lanza una excepción.

IOExcepción Excepción interrumpida

322 capítulo 11
Machine Translated by Google

manejo de excepciones

su
Si es el código el que detecta la excepción, ¿de quién

es el código que la genera? ohws


a miX Cmi ti
norte

htr
pag
oh
baC
norte

2
k

clase vaca {
barra de clase { muu vacío() {
ir vacío() { si (servidorAbajo){

1
mugir(); explotar();
} }
}
int cosas() {
}
[Link]();
} llama al método arriesgado
}

tu codigo clase con un


método arriesgado

este método DEBE decirle al mundo


1 Código arriesgado que genera excepciones: (declarando) que arroja una BadException

takeRisk público vacío () lanza BadException {


si (abandonar toda esperanza) {
lanzar nueva BadException();
}

} cree un
de nuevo objeto
excepción y tírelo.

2 Tu código que llamadas el método arriesgado:

dedos cruzados vacíos públicos () {


intentar {

[Link]();
} captura (BadException ex) {
[Link](“¡Aaargh!”); Si no puede recuperarse
de la excepción, AL MENOS
[Link]();
obtenga un seguimiento de la pila utilizando el método printStackTrace()
} que heredan todas las excepciones.

usted está aquí 323


Machine Translated by Google

excepciones marcadas y no marcadas

El compilador comprueba todo excepto


RuntimeExceptions.
El compilador comprueba las El compilador garantiza:
excepciones que NO son subclases
de RuntimeException. Se llaman 1
"excepciones comprobadas"

Excepción 2

IOExcepción Excepción interrumpida Excepción en tiempo de ejecución


El compilador NO verifica las RuntimeExceptions.
Se les conoce como (gran sorpresa aquí)
"excepciones no controladas". Puede lanzar,
capturar y declarar RuntimeExceptions, pero no
es necesario y el compilador no lo comprobará.

Excepción ClassCast Excepción de puntero nulo

no existen
Preguntas tontas

324 capítulo 11
Machine Translated by Google

manejo de excepciones

PUNTOS DE VIÑETA

Un método puede generar una excepción cuando algo falla en tiempo de ejecución.

Una excepción es siempre un objeto de tipo Excepción. (Lo cual, como recordará
de los capítulos sobre polimorfismo, significa que el objeto es de una clase que tiene
Exception en algún lugar de su árbol de herencia).

El compilador NO presta atención a las excepciones que son de tipo


RuntimeException. Una RuntimeException no tiene que declararse ni incluirse en
un try/catch (aunque eres libre de hacer una o ambas cosas)

Todas las excepciones que le interesan al compilador se denominan


"excepciones comprobadas", lo que en realidad significa excepciones comprobadas
por el compilador. Sólo RuntimeExceptions están excluidas de la comprobación del
Si estás intentando aprender algo nuevo,
compilador. Todas las demás excepciones deben reconocerse en su código, de
haz que sea lo último que intentes aprender
acuerdo con las reglas.
antes de irte a dormir. Entonces, una vez que
dejes este libro (suponiendo que puedas
Un método genera una excepción con la palabra clave throw, seguida de un nuevo
separarte de él) no leas nada más desafiante
objeto de excepción:
que la parte posterior de un Cheerios™.
lanzar nueva NoCaffeineException(); caja. Tu cerebro necesita tiempo para procesar
lo que has leído y aprendido. Eso podría
Los métodos que podrían generar una excepción marcada deben anunciarla con una tardar unas horas. Si intentas insertar algo
declaración throws Exception . nuevo justo encima de tu Java, algunas de las
Es posible que Java no
Si su código llama a un método de lanzamiento de excepciones verificado, debe
se "pegue". Por supuesto, esto no descarta
asegurarle al compilador que se han tomado precauciones.
aprender una habilidad física. Trabajar en tu
última rutina de Ballroom
Si está preparado para manejar la excepción, incluya la llamada en un try/catch y
KickBoxing probablemente no
coloque su código de manejo/recuperación de excepciones en el bloque catch. afectará tu aprendizaje de Java.

Si no está preparado para manejar la excepción, aún puede hacer feliz al compilador Para obtener mejores resultados,
lea este libro (o al menos
"evitando" oficialmente la excepción. Hablaremos de agacharnos un poco más
mire las imágenes) justo
adelante en este capítulo.
antes de irse a dormir.

Afila tu lápiz

el servidor está caído

usted está aquí 325


Machine Translated by Google

excepciones y control de flujo

Control de flujo en bloques try/catch

Si el intento tiene éxito


(doRiskyThing() lanza una no
excepción)
intentar {

1 Foo f = [Link](); El código en el bloque


int b = [Link](); catch nunca
carreras.
Ventana de edición de archivos Ayuda RiskAll

abajo el
Primero se ejecuta el bloque try

y luego se ejecuta } captura (Excepción ex) { Probador %java

el código catch. [Link](“fallido”); ¡Lo hicimos!


}
2 [Link](“¡Lo logramos!”);

Si el intento falla
(porque doRiskyThing() lanza
hace una excepción)
El resto del bloque try nunca
intentar { se ejecuta, lo cual es bueno
1 Foo f = [Link](); porque el resto del try
El bloque try se ejecuta, pero la depende del éxito de
int b = [Link](); la llamada a doRiskyThing().
llamada a doRiskyThing() genera
una excepción, por lo que el
resto del bloque try no se ejecuta.
} captura (Excepción ex) { Ventana de edición de archivos Ayuda RiskAll

2 [Link](“fallido”); Probador %java


El bloque catch se ejecuta y
} fallido
luego el método continúa.
3 [Link](“¡Lo logramos!”); ¡Lo hicimos!

326 capítulo 11
Machine Translated by Google

manejo de excepciones

Finalmente: para las cosas que quieres


hacer no importaqué.

¿Estás seguro Pase lo que pase, ¡NO dejes que


de que quieres me olvide de apagar el horno!
probar esto?
La última vez incendié la mitad del
barrio.

Un bloque finalmente es donde colocas el código


que debe ejecutarse en caso a pesar de todo
de una excepción.

intentar {
encender el horno();
[Link]();
} captura (BakingException ex) {
[Link]();
} finalmente {
apagar horno();
}

Si el bloque try falla (una excepción), el control de


flujo pasa inmediatamente al bloque catch.
Cuando se completa el bloque catch, se ejecuta el
bloque finalmente. Cuando se completa el bloque finalmente,
el resto del método continúa.

No el control de
Si el bloque try tiene éxito (excepción),
intentar {
flujo salta el bloque catch y pasa al bloque
encender el horno();
finalmente. Cuando se completa el bloque
[Link]();
finalmente, el resto del método
apagar horno();
continúa.
} captura (BakingException ex) {
[Link]();
Si el bloque try o catch tiene una declaración de
apagar horno();
devolución, ¡finalmente aún se ejecutará! El
} flujo salta al final y luego regresa al retorno.

usted está aquí 327


Machine Translated by Google

ejercicio de control de flujo

Afila tu lápiz

Prueba de cadena = "sí";

Excepciones de prueba de clase pública {


prueba = "no"

público estático vacío principal (String [] argumentos) {

Prueba de cadena = “no”;


intentar
{ [Link](“iniciar intento”);

hacerArriesgado(prueba); [Link](“finalizar intento”);


} catch (ScaryException se)
{ [Link](“excepción aterradora”);
} finalmente
{ [Link](“finalmente”);
}
[Link](“fin de principal”);
}
prueba = “sí”

static void doRisky (prueba de cadena) lanza ScaryException {


[Link](“comenzar arriesgado”); si
("sí". es igual a (prueba)) {

lanzar nueva ScaryException();


}
[Link](“fin del riesgo”);
devolver;
}
}

328 capítulo 11
Machine Translated by Google

manejo de excepciones

¿Mencionamos que un método


puede generar más de una excepción?

Atrapando múltiples excepciones

lavandería de clase pública {

public void doLaundry() lanza PantsException, LingerieException {

// código que podría generar cualquiera de las excepciones

} Este método declara dos, cuéntalos,


} DOS excepciones.

clase pública Foo {

vacío público ir () {

Lavandería lavandería = nueva Lavandería(); si doLaundry() lanza una


PantsException, aterriza en el
intentar {
bloque catch PantsException.
lavanderí[Link]();

} captura (PantsException pex) {


// código de recuperación

} atrapar(LenceríaException lex) {
si doLaundry() lanza una
// código de recuperación
LingerieException, aterriza en el
}
} bloque catch de LingerieException.

usted está aquí 329


Machine Translated by Google

excepciones polimórficas

Las excepciones son polimórficas.

Todas las excepciones

Excepción tienen Exception

como superclase.

IOExcepción RopaExcepción

1 Puede DECLARAR excepciones utilizando un supertipo


de las excepciones que lanza.

PantalonesExcepción LenceríaExcepción CamisaExcepción

public void doLaundry() lanza ClothingException {

VestidoCamisaExcepción
Declarar una ClothingException te permite lanzar
cualquier
CamisetaExcepción

subclase de ClothingException. Eso significa


doLaundry() puede lanzar una PantsException,
Excepción de lencería, excepción de camiseta y

individualmente.
DressShirtException sin declararlas explícitamente

2 Puede CAPTAR excepciones utilizando


un supertipo de la excepción lanzada.
solo puede atrapar

intentar { puede atrapar cualquier intentar {


Tee ShirtException y Dress ShirtException

RopaExcepción lavanderí[Link]();
lavanderí[Link]();
subclase

} captura (ClothingException cex) { } captura (sexo ShirtException) {

// código de recuperación // código de recuperación

} }

330 capítulo 11
Machine Translated by Google

manejo de excepciones

El hecho de que PUEDES captar todo con una gran captura


súper polimórfica no siempre significa que DEBES hacerlo.

intentar {

lavanderí[Link]();

} captura (Excepción ex) {

// código de recuperación...
¿Recuperación de QUÉ? Este bloque de captura
detectará CUALQUIER excepción, por lo que
}
no sabrá automáticamente qué salió mal.

Escriba un bloque catch diferente para cada excepción


que necesite manejar de forma única.

intentar {

lavanderí[Link]();

TeeShirtExceptions y
} captura (TeeCamisaException tex) {
LingerieExceptions necesitan un código
// recuperación de Tee ShirtException de recuperación diferente, por lo que
debes usar diferentes bloques catch.

} atrapar(LenceríaException lex) {

// recuperación de LingerieException

Todas las demás excepciones de ropa


} captura (ClothingException cex) { están atrapados aquí.

// recuperación de todos los demás

usted está aquí 331


Machine Translated by Google

orden de múltiples bloques de captura

Se deben ordenar varios bloques de


RopaExcepción
captura de menor a mayor

Las Tee ShirtExceptions


se detectan aquí, pero no
caben otras excepciones.

captura (Tee ShirtException tex)

PantalonesExcepción LenceríaExcepción CamisaExcepción Excepción uniforme

Tee ShirtExceptions nunca


llegará aquí, pero todas las
demás subclases de
ShirtException quedan atrapadas aquí.

CamisetaExcepción VestidoCamisaExcepción

atrapar (CamisaExcepción sexo)

Todas las ClothingExceptions se detectan aquí, aunque TeeShirtException y ShirtException nunca

llegar tan lejos.

captura (RopaException cex)

332 capítulo 11
Machine Translated by Google

manejo de excepciones

No se pueden poner cestas más grandes


encima de cestas más pequeñas.

El tamaño importa
cuando tienes varios bloques
captura (Excepción ex) de captura. El que tenga la cesta más
grande tiene que estar abajo.
De lo contrario, los que tienen
cestas más pequeñas son inútiles.

¡No hagas esto!

intentar {

lavanderí[Link]();

} captura (ClothingException cex) {

// recuperación de ClothingException

} atrapar(LenceríaException lex) {

// recuperación de LingerieException

} captura (sexo ShirtException) {

// recuperación de ShirtException

usted está aquí 333


Machine Translated by Google

rompecabezas polimórfico

Afila tu lápiz

intentar {

[Link]();

} captura(AlphaEx a) {

// recuperación de AlphaEx

} captura(BetaEx b) {

// recuperación de BetaEx

} captura(GammaEx c) {

// recuperación de GammaEx

} captura(DeltaEx d) {

// recuperación de DeltaEx

BazEx

FooEx

BarEx BiffEx

boinkex

334 capítulo 11
Machine Translated by Google

manejo de excepciones

Cuando no quieres manejar


una excepción...

solo agáchalo Que...?

No hay manera de que


me contagie esa cosa. Me voy a
quitar del camino. Alguien
detrás de mí puede manejarlo.

Si no desea manejar una


excepción, puede evitarla
declarándola .

REALMENTE no lo lanzas, pero


como no tienes un try/catch para
public void foo() lanza ReallyBadException { el método arriesgado que
// llama a un método arriesgado sin intentarlo o capturarlo llamas, TÚ ahora eres el "método arriesgado".
Porque ahora, quien te llame a TI
lavanderí[Link]();
tiene que lidiar con la excepción.
}
usted está aquí 335
Machine Translated by Google

manejar o declarar

Agacharse (declarando)
sólo retrasa lo inevitable

Tarde o temprano, alguien tiene que


ocúpate de ello. ¿Pero qué pasa si principal()
elude la excepción?
¡Ambos métodos evitan la excepción
Lavadora de clase pública {
Lavandería lavandería = nueva Lavandería(); (declarándola) para que no haya nadie que
pueda manejarla! Esto se compila muy bien.
public void foo() lanza ClothingException { lavanderí[Link]();

public static void main (String[] args) lanza ClothingException {


Lavadora a = nueva Lavadora();
[Link]();
}
}

doLaundry() lanza un foo() evita la main() evita la La JVM se


1 RopaExcepción
2 excepción
3 excepción
4 apaga

lava la ropa
foo foo
principal principal
principal

principal() llama a foo() doLaundry() sale de la pila foo() sale de la pila


inmediatamente y la inmediatamente y la
foo() llama a doLaundry()
excepción se devuelve a excepción se devuelve a...
doLaundry() se foo(). ¿quién? ¿Qué?
está ejecutando y lanza un No queda nadie excepto
Pero foo() no tiene try/catch,
RopaExcepción la JVM, y está pensando:
así que...
"No esperes que YO te
saque de esto".

Estamos usando la camiseta para representar una


excepción de ropa. Lo sabemos, lo sabemos...
hubieras preferido los jeans azules.

336 capítulo 11
Machine Translated by Google

manejo de excepciones

Manejar o Declarar. Es la ley.

Ahora hemos visto ambas formas de satisfacer al compilador cuando


llamas a un método arriesgado (que lanza excepciones).

1 MANGO
Envuelva la decisión arriesgada en un intento/captura

Más vale que esto sea un problema lo suficientemente


intentar {
lavanderí[Link](); grande como para manejar todas las excepciones
que doLaundry() pueda generar. De lo contrario,
} captura (ClothingException cex) {
// código de recuperación el compilador seguirá quejándose de que no detecta
todas las excepciones.
}

2 DECLARAR (esquivarlo)
Declare que SU método arroja las mismas excepciones que el método
riesgoso al que está llamando. El método doLaundry() genera una
ClothingException, pero al declarar la
void foo() lanza ClothingException {
excepción, el método foo() consigue
lavanderí[Link]();
eludir la excepción. Sin intento/captura.
}

Pero ahora esto significa que quien llame al método foo() debe seguir la
ley Handle o Declare. Si foo() evita la excepción (declarándola) y main()
llama a foo(), entonces main() tiene que lidiar con la excepción.

Lavadora de clase pública {


Lavandería lavandería = nueva Lavandería();

public void foo() lanza ClothingException { lavanderí[Link]();

} ¡¡PROBLEMA!!

público estático vacío principal (String[] args) { Ahora main() no se compila y


Lavadora a = nueva Lavadora(); obtenemos un error de "excepción no informada".
[Link](); En lo que respecta al compilador, el
} método foo() arroja un
} excepción.
Debido a que el método foo() evita la

ClothingException lanzada por doLaundry(),


main() tiene que envolver
o [Link]() en un try/catch,
main() tiene que declarar que
también lanza ClothingException.

usted está aquí 337


Machine Translated by Google

arreglando el código del secuenciador

Volviendo a nuestro código musical...

No hay problema en llamar a


juego público vacío() { getSequencer(), ahora que lo hemos incluido en un try/

intentar { bloque de captura.

Secuenciador secuenciador = [Link]();


[Link](“Obtuve un secuenciador con éxito”);

El parámetro
} captura (MidiUnavailableException ex) { de captura
tiene que ser
[Link](“Qué fastidio”); la excepción "correcta".
Si dijéramos
que el código
'catch(ExcepciónArchivoNoEncontradof), el
mórficamente a
} } // cerrar juego no se compilaría,
no porque poli­
encajaría en un
Excepción inviable Midi

atrapar FileNotFoundException.
Recuerda que no es suficiente
bloquearte tener que
¡cosa siendo arrojada!
atrapar el
Reglas de excepción

1 No puedes atraparlo o finalmente sin 3 Un intento DEBE ir seguido de una captura


intentarlo. o de un finalmente
ir vacío() { ¡ILEGAL! intentar { LEGAL porque tu
Foo f = nuevo Foo(); ¿Dónde está el intento? [Link](); tener un finalmente,
aunque
[Link](); } finalmente { no haya pero
lo atrapes. No puede intentarlo
atrapar (FooException ex) { } // limpiar por sí
tener un
}
solo.
}

2 No puedes poner código entre el try y el 4 Un intento con solo finalmente (sin captura)
catch. aún debe declarar la excepción.
intentar { void go() lanza FooException {
¡ILEGAL! No puedes poner
[Link](); intentar {
código entre el intento y
la captura. Un intento sin captura
} [Link]();
no cumple con el
int y = 43; } finalmente { }

}
identificador ni declara la ley
} captura (Excepción ex) { }

338 capítulo 11
Machine Translated by Google

manejo de excepciones

No hay manera de
Pero, ¿por qué
que deje que Betty gane el
no utilizas el
código este año, así que lo
código Ready­Bake?
haré yo mismo desde cero.

usted está aquí 339


Machine Translated by Google

Clases JavaSound MIDI

Haciendo sonido real

Necesitas CUATRO cosas:

1 Lo que 2 La música que se 3 La parte del 4 La información


reproduce la música. reproducirá... una canción. Secuencia que musical real:
contiene la notas a tocar,
información real. cuánto tiempo, etc.

midi
tiene un sostiene Evento
obras de teatro

Secuenciador Secuencia Pista


midi
Evento

midi
Evento

midi
Evento

Para este libro, piense en la Secuencia como


un CD de una sola canción (tiene sólo una
Pista). La información sobre cómo reproducir
la canción se encuentra en la pista, y la pista es parte
de la Secuencia.

340 capítulo 11
Machine Translated by Google

manejo de excepciones

Y necesitas CINCO pasos:


1 Consigue un secuenciador y ábrelo
Reproductor secuenciador = [Link]();
[Link]();

2 Haz una nueva secuencia


Secuencia seq = nueva Secuencia(timing,4);

3 Obtener una nueva pista de la secuencia


Seguimiento t = [Link]();

4 Llena la Pista con MidiEvents y dale la


Secuencia al Secuenciador
[Link](miEventoMidi1);
[Link](seq); Ahhh. Nos
olvidamos de presionar
el botón PLAY. ¡Tienes que
iniciar() el secuenciador!
Odio decírtelo, pero son
solo CUATRO pasos.

[Link]();

usted está aquí 341


Machine Translated by Google

una aplicación de sonido

Tu primera aplicación de reproducción de sonido

importar [Link].*; No olvides importar el paquete midi.

clase pública MiniMiniMusicApp {

público estático vacío principal (String [] argumentos) {


MiniMiniMusicApp mini = nueva MiniMiniMusicApp();
[Link]();
} // cerrar principal

juego público vacío() { consigue un secuenciador y


ábrelo (para que podamos usarlo...
intentar {
un secuenciador no viene ya abierto)

Reproductor secuenciador = [Link]();


1
[Link]();

No te preocupes por los argumentos del


2 Secuencia secuencia = nueva Secuencia ([Link], 4);
constructor Sequence. Simplemente cópielos (piense
en ellos como argumentos listos para hornear).

3 Seguimiento de seguimiento = [Link]();

Solicite una pista a la secuencia. Recuerde,


la pista vive en la secuencia y los datos MIDI
vive en la Pista.
Mensaje Corto a = nuevo Mensaje Corto();
4 [Link](144, 1, 44, 100);
MidiEvent noteOn = nuevo MidiEvent(a, 1); [Link](notaEn); Pon algo
MidiEvents en la pista. Esta parte es
principalmente código listo para hornear. Lo único
que tendrá que preocuparse son los argumentos
Mensaje Corto b = nuevo Mensaje Corto();
[Link](128, 1, 44, 100); del método setMessage() y los argumentos del
MidiEvent noteOff = nuevo MidiEvent(b, 16); [Link](notaDesactivada); constructor MidiEvent. Los veremos en la página
argumentos sobre
siguiente.

[Link](seq);
Dar la secuencia al secuenciador (como
[Link](); poner el CD en el reproductor de CD)

} captura (Excepción ex) { Start() el secuenciador (como presionar JUGAR)


[Link]();
}
} // cerrar juego
} // cerrar clase

342 capítulo 11
Machine Translated by Google

manejo de excepciones

Crear un MidiEvent (datos de la canción)

1 hacer un mensaje
Mensaje Corto a = nuevo Mensaje Corto();

2 Ponga la instrucción en el mensaje


Este mensaje dice "comienza a tocar la nota 44"
[Link](144, 1, 44, 100);
(veremos los otros números en la

siguiente página)

3 Crea un nuevo MidiEvent usando el Mensaje


MidiEvent noteOn = nuevo MidiEvent(a, 1);
Las instrucciones están en el pero el Midi­
mensaje, Evento agrega el momento en el que se
4 Agregue el MidiEvent a la pista
debe activar la instrucción. Este MidiEvent dice que
mensaje
[Link](notaEn); se active 'a' en el primer tiempo (tiempo 1).

Una pista contiene todos los objetos MidiEvent. La Secuencia los


organiza según cuándo se supone que debe ocurrir cada evento, y luego
el Secuenciador los reproduce en ese orden. Puedes tener muchos
eventos sucediendo exactamente en el mismo momento. Por ejemplo,

es posible que desees tocar dos notas simultáneamente, o incluso


diferentes instrumentos que reproduzcan sonidos diferentes al mismo tiempo.

usted está aquí 343


Machine Translated by Google

Contenido de un evento Midi

Mensaje MIDI: el corazón de un MidiEvent

Anatomía de un mensaje.
El argumento
primero de setMessage() siempre representa
el 'tipo' de mensaje, mientras que los tres otro
t argumentos representan cosas diferentes
dependiendo del tipo de mensaje.
2 Canal
canal
Tipo de mensaje nota para velocidad
jugar Piense en un canal como un músico en una banda.

[Link](144, 1, 44, 100); El canal 1 es el músico 1 (el teclista), el canal 9


es el baterista, etc.

Los últimos 3 argumentos varían según


el mensaje
el tipo.
otros Este esson
argumentos un mensaje NOTA SOBRE, entonces
el
para conocer las cosas que el secuenciador
necesita saber para poder tocar una nota. 3 Nota para jugar
Un número del 0 al 127, que va de notas
1 tipo de mensaje bajas a altas.

144 significa
NOTA SOBRE 1 127

012345678
empezar a jugar

128 significa
NOTA APAGADA
4 Velocidad
¿Qué tan rápido y fuerte hizo

presionas la tecla? 0 es tan suave que probablemente


dejar de jugar no escuches nada, pero 100 es un buen valor
predeterminado.

344 capítulo 11
Machine Translated by Google

manejo de excepciones

cambiar un mensaje

1 cambiar la nota
Pruebe con un número entre 0 y 127 en los mensajes de
127
activación y desactivación de notas.

[Link](144, 1, 20, 100);


012345678

2 Cambiar la duración de la nota.


Cambia el evento de nota desactivada mensaje ) entonces

(no el que sucede en un tiempo anterior o posterior).

[Link](128, 1, 44, 100);


MidiEvent noteOff = nuevo MidiEvent(b, 3 );

3 cambiar el instrumento
Agregue un nuevo mensaje, ANTES del mensaje de
reproducción de notas, que configure el instrumento en el canal
1 en algo distinto al piano predeterminado. El mensaje de
cambio de instrumento es '192' y el tercer argumento
representa el instrumento real (pruebe con un número entre 0 y 127).

[Link](192, 1, 102, 0);

al instrumento 102

en canal 1 (músico 1)
mensaje de cambio de instrumento

usted está aquí 345


Machine Translated by Google

cambiar el instrumento y la nota

Versión 2: uso de argumentos de línea de comandos para experimentar con sonidos

importar [Link].*;

clase pública MiniMusicCmdLine { // Este es el primero

público estático vacío principal (String [] argumentos) {


MiniMusicCmdLine mini = nuevo MiniMusicCmdLine();
si ([Link] < 2) {
[Link](“No olvide los argumentos del instrumento y de las notas”);
} demás {
int instrumento = [Link](args[0]);
int nota = [Link](args[1]);
[Link](instrumento, nota);
}
} // cerrar principal

reproducción pública vacía (int instrumento, int nota) {

intentar {

Reproductor secuenciador = [Link](); [Link]();


Secuencia secuencia
= nueva Secuencia ([Link], 4); Seguimiento de seguimiento =
[Link]();

Evento MidiEvent = nulo;

Mensaje Corto primero = nuevo Mensaje Corto();


[Link](192, 1, instrumento, 0);
MidiEvent changeInstrument = nuevo MidiEvent(primero, 1); [Link](cambiarInstrumento);

Mensaje Corto a = nuevo Mensaje Corto(); Ejecútelo con dos argumentos int de
[Link](144, 1, nota, 100); 0 a 127. Pruebe estos para empezar:
MidiEvent noteOn = nuevo MidiEvent(a, 1); [Link](notaEn);
Ayuda de la ventana de edición de archivos Atenuar

%java MiniMusicCmdLine 102 30


Mensaje Corto b = nuevo Mensaje Corto();
[Link](128, 1, nota, 100); %java MiniMusicCmdLine 80 20
MidiEvent noteOff = nuevo MidiEvent(b, 16); [Link](notaDesactivada);
%java MiniMusicCmdLine 40 70
[Link](seq); [Link]();

} captura (Excepción ex) {[Link]();}


} // cerrar juego
} // cerrar clase

346 capítulo 11
Machine Translated by Google

manejo de excepciones

Hacia dónde nos dirigimos con el resto de


CodeKitchens

Capítulo 15: la meta


Cuando hayamos terminado, tendremos un
BeatBox funcional que también es un cliente Drum Chat.
Necesitaremos aprender sobre GUI (incluido el
ritmo de baile
manejo de eventos), E/S, redes y subprocesos. Los
próximos tres capítulos (12, 13 y 14) nos llevarán allí.

Andy: ritmo #2

Chris: groove2 revisado

Nigel: ritmo de baile

Capítulo 12: Eventos MIDI


Este CodeKitchen nos permite crear un pequeño
“video musical” (un poco exagerado llamarlo así...)
que dibuja rectángulos aleatorios al ritmo de la
música MIDI. Aprenderemos cómo construir y
reproducir muchos eventos MIDI (en lugar de solo
vencer a uno vencer a dos vencer a tres vencer a cuatro...
un par, como hacemos en el capítulo actual).

Capítulo 13: Independiente


BeatBox
Ahora construiremos el BeatBox real, la GUI y todo.
Pero es limitado: tan pronto como cambias un patrón,
el anterior se pierde.
No hay función Guardar y Restaurar y no se comunica
con la red.
(Pero aún puedes usarlo para mejorar tus habilidades
con los patrones de batería).

Capítulo 14: Guardar y


Restaurar
Has creado el patrón perfecto y ahora puedes
guardarlo en un archivo y volver a cargarlo cuando
quieras volver a reproducirlo. Esto nos prepara para
la versión final (capítulo 15), donde en lugar de escribir
el patrón en un archivo, lo enviamos a través de una
red al chat.
servidor.

usted está aquí 347


Machine Translated by Google

ejercicio: Verdadero o Falso

348 capítulo 11
Machine Translated by Google

manejo de excepciones

intentar {
[Link](“r“);

[Link](“t“);
hacerArriesgado(prueba);

[Link](“s“); } finalmente {

[Link](“o“);

clase MyEx extiende la excepción {}

clase pública ExTestDrive {

[Link](“w“);

si ("sí". es igual a (t)) {

[Link](“a“);

lanzar nuevo MyEx();


} captura (MyEx e) {

vacío estático doRisky (String t) lanza MyEx {

[Link](“h”);
Ventana de edición de archivos Ayuda ThrowUp

% java ExTestDrive sí se
descongela público estático vacío principal (String [] argumentos) {
Prueba de cadena = args[0];
% java ExTestDrive sin
lanzamientos

usted está aquí 349


Machine Translated by Google

rompecabezas: crucigrama

JavaCross 7.0

350 capítulo 11
Machine Translated by Google

manejo de excepciones

clase MyEx extiende la excepción {}

clase pública ExTestDrive {

público estático vacío principal (String [] argumentos) {


Prueba de cadena = args[0];
intentar {

[Link](“t”);

hacerArriesgado(prueba);

[Link](“o”);

} captura (MyEx e) {

[Link](“a”);

} finalmente {

[Link](“w”);
}
[Link](“s”);
}

vacío estático doRisky (String t) lanza MyEx {


[Link](“h”);

si ("sí". es igual a (t)) {

lanzar nuevo MyEx();


}

[Link](“r”);

}
} Ventana de edición de archivos Ayuda Chill

% java ExTestDrive sí se
descongela

% java ExTestDrive sin


lanzamientos

usted está aquí 351


Machine Translated by Google

respuestas del rompecabezas

JavaCross Respuestas
ASIGNACIÓN
ASIGNACIÓN estalló
MCN R
SUBCLASE AOS INVOCAR
TPT t V C
MANGO DE JERARQUÍA l
norte NUEVA HAMPSHIRE t t A
S C ETEXCEPCIONES
t mi C R norte S
COMO PALABRA CLAVE h
nordeste mi ETREE
TT PATO C RT
EN T A ALGORITMO
AE ÉL A TR
LANZAR CONCRETO oh

mi Ah mi NUEVO

352 capítulo 11
Machine Translated by Google

12 obteniendo gui

Un muy gráfico
Historia
¡Guau! Esto luce genial.
Escuché que tu
Supongo que la presentación
ex esposa sólo podía cocinar
eslo es todo.
realmente comidas de línea de comando.

Acéptalo, necesitas crear GUI.

este es un nuevo capitulo 353


Machine Translated by Google

tu primera interfaz gráfica de usuario

“Si veo uno más


Todo comienza con una ventana aplicación de línea de
comandos, estás despedido”.

un JFrame con una barra de


menú y dos 'widgets' (un botón
y un botón de opción)

Hacer una GUI es fácil:


1 Hacer un marco (un JFrame)
Marco JFrame = nuevo JFrame();

2 Crea un widget (botón, campo de texto, etc.)


Botón JButton = nuevo JButton(“haz clic en mí”);
Pon widgets en la ventana.

3 Añade el widget al marco.


[Link]().add(botón);

No agregas cosas al marco


directamente. Piensa en el marco
como el borde alrededor de la ventana
y agregas cosas al panel de la ventana.

4 Muéstralo (dale un tamaño y hazlo visible)


[Link](300,300);
[Link] (verdadero);

354 capítulo 12
Machine Translated by Google

obteniendo gui

Tu primera GUI: un botón en un marco

No olvides importar este


importar [Link].*; paquete swing.

clase pública SimpleGui1 {


público estático vacío principal (String[] args) { hacer un marco y un botón

Marco JFrame = nuevo JFrame(); (puedes pasarle al constructor del


Botón JButton = nuevo JButton(“haz clic en mí”); botón el texto que quieras en el botón)

[Link](JFrame.EXIT_ON_CLOSE);

esta línea hace que el programa se cierre tan pronto como


cierres la ventana (si omites esto, se cerrará
simplemente siéntate ahí
en la pantalla para siempre)
[Link]().add(botón);

agregue el botón al panel de


contenido del marco
[Link](300,300);

Dale al marco un tamaño, en píxeles.


[Link] (verdadero);
}
}
¡¡Por fin hazlo visible!! (si olvidas este
paso, no verás nada cuando
ejecutas este código)

Veamos qué pasa cuando lo ejecutamos: %java


SimpleGui1

¡Vaya! Ese es un
botón realmente grande.

El botón llena todo el


espacio disponible en el marco.
Más adelante aprenderemos a
controlar dónde (y qué tan
grande) está el botón en el marco.

usted está aquí 355


Machine Translated by Google

eventos de interfaz de usuario

no existen
Preguntas tontas

Pero no pasa nada cuando hago clic en él...

Necesitamos dos cosas:

1 A
método que se llamará cuando el usuario
haga clic (lo que desea que suceda como
resultado del clic del botón).

2
camino saber cuándo activar un
hacia ese método. En otras palabras, ¡una
forma de saber cuándo el usuario hace
clic en el botón!

Cuando el usuario hace clic, queremos saber.

Estamos interesados en el evento en el


que el usuario realiza una acción con un botón.

356 capítulo 12
Machine Translated by Google

obteniendo gui

Obtener un evento de usuario


Primero, el botón necesita saber que nos importa.

Oye botón, me
1
importa lo que te pase.

cambio público vacío() {


[Link](“¡Me han hecho clic!”);
} tu codigo t
C
btut t ohnorte
j
transmisión exterior
mi

¡El usuario me hizo clic!


2

En segundo lugar, el botón necesita una forma de


devolvernos la llamada cuando se produce un
evento en el que se hace clic en el botón.

usted está aquí 357


Machine Translated by Google

oyentes de eventos

Si le interesan los eventos del botón, implemente

una interfaz que diga, para sus eventos”.


"Soy escuchando

Una interfaz de escucha es el puente entre el Cuando implementas una


escucha (usted) y la fuente del evento (el botón). interfaz de escucha, le das al
botón una forma de
devolverte la llamada. La interfaz
es donde se declara el método
de devolución de llamada.

<<interfaz>> ActionListener actionPerformed(ActionEvent

ev)

<<interfaz>>
ItemListener

itemStateChanged(ItemEvent ev)

<<interfaz>>
Escucha clave

tecla presionada (Evento clave ev)

claveReleased(KeyEvent ev)

keyTyped(KeyEvent ev)

358 capítulo 12
Machine Translated by Google

obteniendo gui

Cómo se comunican el oyente y la fuente:

"Botón, agrégame a tu lista de


oyentes y llama a mi método
actionPerformed() cuando el usuario
haga clic en ti".
"Está bien, eres un ActionListener,
así que sé cómo devolverte la
llamada cuando hay un evento; te llamaré

el método actionPerformed() que


tienes”. saber

Ct i oh nL si t mi
.adda r( t
mi
norte

norte hs
i)
tt
oh

btu

t )
aCti oh mivmi
norte

r Foh r mid( el
nortePAG
mi metro

usted está aquí 359


Machine Translated by Google

obteniendo eventos

Obtener el ActionEvent de un botón

1 Implementar la interfaz ActionListener

2 Regístrese con el botón (dígale que


desea escuchar eventos)

3 Defina el método de manejo de eventos


(implemente el método actionPerformed() desde el
interfaz ActionListener)

una nueva declaración de importación para el paquete en


importar [Link].*;
importar [Link].*; el que se encuentran ActionListener y ActionEvent.

1 Implementar la interfaz. Esto dice,


la clase pública SimpleGui1B implementa ActionListener {
Botón JBotón;
"una instancia de SimpleGui1B IS­
a
A ActionListener". solo
público estático vacío principal (String[] args) { (El botón dará eventos a los
interfaz gráfica de usuario SimpleGui1B = nueva SimpleGui1B();
implementadores de ActionListener)
[Link]();
}

vacío público ir () {
Marco JFrame = nuevo JFrame();
botón = nuevo JButton(“haz clic en mí”);
registra tu interés con el botón. Esto le dice al
botón "Agrégame a tu lista de oyentes".
2 botó[Link](esto);
¡El argumento que pase DEBE ser un objeto de
una clase que implemente ActionListener!

[Link]().add(botón);
[Link](JFrame.EXIT_ON_CLOSE);
[Link](300,300);
Implemente el método actionPerformed()
[Link] (verdadero);
} de la interfaz ActionListener. ¡Este es el
método de manejo de eventos real!
3
acción vacía pública realizada (evento ActionEvent) {
[Link](“¡Me han hecho clic!”);
}
}
El botón llama a este método para informarle que ocurrió un
evento. Le envía un objeto ActionEvent como argumento,
pero no lo necesitamos. Saber que ocurrió el evento es
suficiente información para nosotros.

360 capitulo 12
Machine Translated by Google

obteniendo gui

Oyentes, fuentes y eventos

Como fuente de eventos, mi trabajo

Como oyente, mi trabajo es es aceptar registros (de oyentes) y obtener

implementar la interfaz, eventos del usuario. y llamar al

registrarme con el botón y método de manejo de eventos del

proporcionar el manejo de eventos. oyente (cuando el usuario hace clic en mí)

Fuente ENVÍA
el evento

El oyente OBTIENE el
evento

Oye, ¿y yo? ¡Yo también soy jugador, ya sabes!


Como objeto de evento, soy el argumento del método
de devolución de llamada del evento (desde la
interfaz) y mi trabajo es llevar datos sobre el evento al
oyente.

Objeto de evento
CONTIENE DATOS
sobre el evento
mi
vmi Ct
t ohbj
norte
mi

usted está aquí 361


Machine Translated by Google

manejo de eventos

no existen
Preguntas tontas

Afila tu lápiz
¿Cómo se sabe si un objeto es
una fuente de evento?

Busque en la API.

widgets Métodos de evento DE ACUERDO. ¿Buscar qué?


casilla de verificación cierre de ventana() Un método que comienza con

campo de texto 'add', termina con 'Listener' y lleva al oyente


acción realizada()
a
lista de desplazamiento elementoEstadoCambiado() Argumento de cara. Si tú ves:

botón ratónPresionado() agregarKeyListener(KeyListener k)

caja de diálogo clave mecanografiada() sabes que una clase con este método
es una
boton de radio ratónSalido()
fuente de eventos clave.
opción del menú enfoque ganado() Hay un patrón de nombres.

362 capítulo 12
Machine Translated by Google

obteniendo gui

Volviendo a los gráficos...

Tres formas de poner cosas en tu GUI:

1
Poner widgets en un marco
Agregue botones, menús, botones de radio, etc.

[Link]().add(miBotón);

El paquete [Link] tiene más de una docena de tipos


de widgets.

Número de libros de
Head First Java
2 Dibujar gráficos 2D en un widget comprados

Utilice un objeto gráfico para pintar formas. por error por los
baristas de cafeterías.
grá[Link](70,70,100,100);

Puedes pintar mucho más que cuadros y círculos; La


API Java2D está llena de métodos gráficos
divertidos y sofisticados.

cuadros,
gráficos
arte, juegos,
comerciales,
simulaciones, etc.
etc.

3
Poner un JPEG en un widget
Puedes poner tus propias imágenes en un widget.

grá[Link](miPic,10,10,this);

usted está aquí 363


Machine Translated by Google

haciendo un panel de dibujo

Crea tu propio widget de dibujo

Cree una subclase de JPanel y anule un método, paintComponent().

importar [Link].*; necesitas ambos


importar [Link].*; Crea una subclase de JPanel, un widget
que puedes agregar a un marco como
cualquier otra cosa. Excepto que este es
tu propio widget personalizado.
clase MyDrawPanel extiende JPanel {
Este es el método de los grandes gráficos importantes.

componente de pintura público vacío (Gráficos g) { NUNCA llamarás a esto tú mismo. El sistema lo

llama y dice: "Aquí hay una bonita superficie de


dibujo nueva, de tipo Gráficos, sobre la que puedes
[Link]([Link]); pintar ahora".

[Link](20,50,100,100); Imaginemos que 'g' es una máquina de pintar. Le


} estás diciendo con qué color pintar y luego qué forma
pintar (con coordenadas de dónde va y qué para
} tamaño tiene)

364 capítulo 12
Machine Translated by Google

obteniendo gui

Cosas divertidas para hacer en paintComponent()

Mostrar un JPEG
tu nombre de archivo va aquí
componente de pintura público vacío (Gráficos g) {

Imagen imagen = new ImageIcon(“[Link]”).getImage();

[Link](imagen,3,4,esto);

}
La esquina izquierda

de las coordenadas x,y por donde está la foto arriba


esto dice “3 píxeles de
debería desaparecer. el borde izquierdo del panel y 4
píxeles desde el borde superior del panel”. Estos
números siempre son relativos al widget (en JPanel
este caso, su subclase), no al marco completo.

Pinta un círculo de colores aleatorios


sobre un fondo negro.

componente de pintura público vacío (Gráficos g) { llenar todo el panel con negro (el
color predeterminado)

[Link](0,0,[Link](), [Link]());
Los primeros dos argumentos definen la esquina superior (x,y), izquierda

relativa al panel, donde comienza el dibujo, por lo que 0, 0 significa


"comenzar 0 píxeles desde el borde izquierdo y 0 píxeles desde el

int rojo = (int) ([Link]() * 255); borde superior". Los otros dos argumentos dicen: "Haga que el ancho de
int verde = (int) ([Link]() * 255); este rectángulo sea tan ancho como el panel ([Link]()) y que la

int azul = (int) ([Link]() * 255); altura sea tan alta como el panel ([Link])".

Color randomColor = nuevo Color (rojo, verde, azul);


[Link](coloraleatorio);
[Link](70,70,100,100);
para representar
} Puedes hacer un color pasando 3 entradas.
los valores RGB.
comience 70
píxeles desde la izquierda, 70 desde
100 píxeles
la parte de alto.
superior, hazlo de 100 píxeles de ancho y

usted está aquí 365


Machine Translated by Google

dibujar gradientes con Graphics2D

Detrás de cada buena referencia de Graphics


hay un objeto Graphics2D.

componente de pintura público vacío (Gráficos g) { } Métodos a los que puedes recurrir en un
Referencia gráfica :
dibujarImagen()

Dibujar linea()

dibujarpolígono

dibujarRect()

dibujarOval()

llenarRect()

llenarRoundRect()

establecerColor()

Para convertir Graphics2D objeto a


en Graphics2D referencia :

Gráficos2D g2d = (Gráficos2D) g;


Animal a = nuevo Perro();

[Link]();
Métodos que puede invocar en
una referencia de Graphics2D :

llenar3DRect()

dibujar3DRect()

girar()
Perro d = (Perro) a;
[Link](); escala()

cortar()

transformar()

setRenderingHints()

Gráficos2D g2d = (Gráficos2D) g;


(Estas no son listas de métodos completas, consulte
la API para obtener más información)

366 capítulo 12
Machine Translated by Google

obteniendo gui

Porque la vida es demasiado corta para


pintar el círculo de un color sólido cuando
hay una mezcla de degradado esperándote.

en realidad es un objeto Graphics2D


disfrazado de simple Graphics
objeto.
componente de pintura público vacío (Gráficos g) {

Gráficos2D g2d = (Gráficos2D) g;


Emítelo para que podamos llamar a algo que
Graphics2D tiene pero Graphics no

GradientPaint gradiente = new GradientPaint(70,70,[Link], 150,150, [Link]);

a partir de color color final final


a partir de punto
punto

esto configura el pincel virtual en un


[Link](gradiente); degradado en lugar de un color sólido

[Link](70,70,100,100);

}
el método fillOval() realmente significa
"rellenar el óvalo con lo que esté cargado
en tu pincel (es decir, el degradado)"

componente de pintura público vacío (Gráficos g) {


Gráficos2D g2d = (Gráficos2D) g;

int rojo = (int) ([Link]() * 255); Esto es como el de arriba,


int verde = (int) ([Link]() * 255); excepto que crea colores aleatorios
int azul = (int) ([Link]() * 255); para los colores de inicio y finalización
Color startColor = nuevo Color (rojo, verde, azul); del degradado. ¡Intentalo!

rojo = (int) ([Link]() * 255);


verde = (int) ([Link]() * 255);
azul = (int) ([Link]() * 255);
Color endColor = nuevo color (rojo, verde, azul);

GradientPaint gradiente = new GradientPaint(70,70,startColor, 150,150, endColor);


[Link](gradiente);
[Link](70,70,100,100);
}

usted está aquí 367


Machine Translated by Google

eventos y gráficos

PUNTOS DE VIÑETA

EVENTOS GRÁFICOS

Para crear una GUI, comience con una ventana, generalmente un JFrame
Puede dibujar gráficos 2D directamente en un widget.
Marco JFrame = nuevo JFrame();
Puedes dibujar un .gif o .jpeg directamente en un widget.
Puede agregar widgets (botones, campos de texto, etc.) al
Para dibujar sus propios gráficos (incluido un .gif o .jpeg),
JFrame usando:
[Link]().add(button); cree una subclase de JPanel y anule el método paintCom­
ponent().
A diferencia de la mayoría de los otros componentes, JFrame no le
permite agregarle directamente, por lo que debe agregarlo al panel de El sistema GUI llama al método paintComponent(). NUNCA

contenido de JFrame. LO LLAMAS TÚ MISMO. El argumento para paintComponent()


es un objeto Graphics que le brinda una superficie para
Para que se muestre la ventana (JFrame), debe darle un
dibujar, que terminará en la pantalla. No puedes construir
tamaño y decirle que sea
ese objeto tú mismo.
visible: [Link](300,300);
[Link] (verdadero); Los métodos típicos para llamar a un objeto Graphics (el
parámetro paint­Component) son:
Para saber cuándo el usuario hace clic en un botón (o realiza
[Link]([Link]);
alguna otra acción en la interfaz de usuario), debe escuchar un [Link](20,50,100,120);
evento de GUI.
Para dibujar un .jpg, construya una imagen
Para escuchar un evento, debe registrar su interés en una usando: Imagen imagen = new ImageIcon(“catzilla.
fuente de eventos. Una fuente de evento es lo que (botón, jpg”).getImage(); y dibuja
casilla de verificación, etc.) "activa" un evento basado en la la imagen usando:
interacción del usuario. [Link](image,3,4,this);

La interfaz de escucha le brinda al origen del evento una El objeto al que hace referencia el parámetro Graphics
forma de devolverle la llamada, porque la interfaz define de paintComponent() es en realidad una instancia de la
los métodos que el origen del evento llamará cuando clase Graphics2D. La clase Graphics 2D tiene una variedad de
ocurra un evento. métodos que incluyen:
fill3DRect(), draw3DRect(), rotate(), scale(), shear(),
Para registrarse para eventos con una fuente, llame al
transform()
método de registro de la fuente. Los métodos de registro
siempre toman la forma: add<EventType>Listener. Para Para invocar los métodos Graphics2D, debe convertir el
registrarse en ActionEvents de un botón, por parámetro de un objeto Graphics a un objeto Graphics2D:
ejemplo, llame a: [Link](this);
Gráficos2D g2d = (Gráficos2D) g;
Implemente la interfaz de escucha implementando todos los
métodos de manejo de eventos de la interfaz. Coloque su
código de manejo de eventos en el método de devolución
de llamada del oyente. Para
ActionEvents, el método es: public void actionPerformed(ActionEvent

evento) {
[Link](“¡hiciste clic!”);
}

El objeto de evento pasado al método del controlador de eventos


transporta información sobre el evento, incluido el origen del
evento.

368 capítulo 12
Machine Translated by Google

obteniendo gui

Podemos conseguir un evento.

Podemos pintar gráficos.

¿Pero podemos pintar gráficos? cuando ¿Tenemos un evento?

Inicia la aplicación

1 El marco se construye con los dos widgets (su


panel de dibujo y un botón). Se crea y
registra un oyente con el botón. Luego se
muestra el marco y simplemente espera a que
el usuario haga clic.

El usuario hace clic en el botón y el botón


2
crea un objeto de evento y llama al
controlador de eventos del oyente.

3 El controlador de eventos llama a repaint()


en el marco. El sistema llama a paintComponent()
en el panel de dibujo.

4 ¡Voilá! Se pinta un nuevo color porque


paintComponent() se ejecuta nuevamente,
llenando el círculo con un color aleatorio.

usted está aquí 369


Machine Translated by Google

construyendo un marco GUI

Espera un minuto... ¿cómo?

¿Pones DOS
cosas en un marco?

Diseños de GUI: poner más de un


widget en un marco

[Link]().add(botón);

Esta no es realmente la manera


de hacerlo (el argumento único se supone que
Esta es la mejor forma (y generalmente agrega el método).
obligatoria) de agregar contenido al panel de
contenido predeterminado de un marco.
Siempre especifique DÓNDE (qué región) [Link]().add([Link], botón);
widget para ir.

desea que Cuando llame al método add


de argumento único (el que no
Llamamos al método add de dos
argumentos, que toma una región (usando
deberíamos usar), el widget aterrizará automáticamente norte
la región central. una constante) y el widget para agregar a esa región.

este
región predeterminada Oeste centro Afila tu lápiz
Dadas las imágenes de la página 351, escribe la

código que agrega el botón y el panel a


el marco.
sur

370 capítulo 12
Machine Translated by Google

obteniendo gui

El círculo cambia de color cada vez que haces clic en el botón.


El panel de dibujo
personalizado (instancia de
MyDrawPanel)
región CENTRALestá
delen la
marco.

importar [Link].*;
importar [Link].*;
importar [Link].*;

clase pública SimpleGui3C implementa ActionListener {

Marco JFrame;

público estático vacío principal (String[] args) { El botón está en el


Interfaz gráfica de usuario SimpleGui3C = nueva SimpleGui3C(); región SUR de
[Link](); el marco
}

vacío público ir () {
marco = nuevo JFrame();
[Link](JFrame.EXIT_ON_CLOSE);

Botón JButton = nuevo JButton(“Cambiar colores”); Agregue el oyente (este)


botó[Link](esto); al botón.

MiDrawPanel drawPanel = nuevo MiDrawPanel();


Agregue los dos widgets
[Link]().add([Link], botón); (botón y panel de dibujo)
[Link]().add([Link], drawPanel); a las dos regiones del
[Link](300,300); marco.
[Link] (verdadero);
}

acción vacía pública realizada (evento ActionEvent) {


[Link]();
}
Cuando el usuario haga clic, indique al
}
marco que se vuelva a pintar(). ¡Eso
significa que se llama a paintComponent()
en cada widget del marco!

clase MyDrawPanel extiende JPanel {

El método del panel


componente de pintura público vacío (Gráficos g) {
// Código para rellenar el óvalo con un color aleatorio clics.
de dibujo se llama cada
vezpaintComponent()
que el usuario
// Consulta la página 347 para ver el código.
}

usted está aquí 371


Machine Translated by Google

múltiples oyentes

Probémoslo con DOS botones.

Entonces ahora necesitamos CUATRO widgets

norte

este El botón de cambio de etiqueta estará aquí.

Oeste centro
la etiqueta

irá aquí
panel de dibujo
va en el centro
sur

El botón de
cambio de color irá aquí.

Y necesitamos conseguir
DOS eventos

Este botón cambia el texto


en el lado opuesto.

Este botón cambia el color


del círculo.

372 capítulo 12
Machine Translated by Google

obteniendo gui

¿Cómo se obtienen eventos de acción para dos botones


diferentes, cuando cada botón necesita hacer algo diferente?

1 opción uno
Implementar dos métodos actionPerformed()

clase MyGui implementa ActionListener {


// mucho código aquí y luego:

acción vacía pública realizada (evento ActionEvent) {


[Link]();
¡Pero esto es imposible!
}

acción vacía pública realizada (evento ActionEvent) {


[Link](“¡Eso duele!”);
}
}

Defecto: ¡No puedes!

2 opción dos
Registre al mismo oyente con ambos botones.
clase MyGui implementa ActionListener {
// declaramos un montón de variables de instancia aquí

vacío público ir () {
// construir interfaz gráfica de usuario

colorButton = nuevo JButton();


labelButton = nuevo JButton();
[Link](esto); Registre el mismo oyente
[Link](esto); con ambos botones
// más código gui aquí...
}

acción vacía pública realizada (evento ActionEvent) {


if ([Link]() == colorButton) {
[Link](); Consulta el objeto de
} demás { evento para descubrir qué
[Link](“¡Eso duele!”); botón realmente lo activó
} y úsalo para decidir qué hacer.
}
}
Defecto: esto funciona, pero en la mayoría de los casos no es muy OO.

usted está aquí 373


Machine Translated by Google

múltiples oyentes

¿Cómo se obtienen eventos de acción para dos botones


diferentes, cuando cada botón necesita hacer algo diferente?

3 opción tres
Crea dos clases ActionListener separadas

clase MyGui {
Marco JFrame;
Etiqueta JLabel;
interfaz gráfica de usuario vacía() {

// código para crear una instancia de los dos oyentes y registrar uno // con el botón de color y
el otro con el botón de etiqueta

} } // cerrar clase

clase ColorButtonListener implementa ActionListener {


acción vacía pública realizada (evento ActionEvent) {
[Link]();
}
¡No funcionará! Esta clase no tiene una referencia
}
a la variable 'marco' de la clase MyGui

clase LabelButtonListener implementa ActionListener {


acción vacía pública realizada (evento ActionEvent) {
[Link](“¡Eso duele!”);
}
} ¡Problema! Esta clase no
tiene referencia a la variable 'etiqueta'

Defecto: estas clases no tendrán acceso a las variables sobre las que necesitan
actuar, 'marco' y 'etiqueta'.

374 capítulo 12
Machine Translated by Google

obteniendo gui

¿No sería maravilloso si pudieras tener


dos clases de escucha diferentes, pero las clases de
escucha pudieran acceder a las variables de instancia
de la clase GUI principal, casi como si las clases de
escucha fueran a la otra clase? Entonces pertenecía
tendrías lo mejor de ambos mundos. Sí, eso sería un sueño.

Pero es sólo una fantasía...

usted está aquí 375


Machine Translated by Google

clases internas

¡Clase interior al rescate!

Clase interna simple:

clase MiClaseExterna {

La clase interna está


clase MiClaseInterior {
completamente encerrada por la clase externa
ir vacío() {
}
}

Clase interna usando una variable de clase externa


clase MiClaseExterna {

privado int x;

clase MiClaseInterior { void go()


{ x = 42;
¡Usa 'x' como si fuera una
variable de la clase interna!
}
} // cerrar clase interna

} // cerrar clase externa

376 capítulo 12
Machine Translated by Google

obteniendo gui

Una instancia de clase interna debe estar vinculada


a una instancia de clase externa*. Un objeto interior
comparte un vínculo
especial con un
objeto exterior.

1 Hacer una instancia


de la clase externa
¡Más de 65.536 copias vendidas!
t
C
METRO
yohtut mir ohbj mi

Ponerse
2 Cree una instancia de
en contacto la clase interna
utilizando la instancia
de la clase externa.

con tu interior METRO


yI r b
j mi Ct

clase mi oh
nortenorte

3 Los objetos externos e internos


Dr. Polimorfismo ahora están íntimamente vinculados.

entero x
El nuevo bestseller del
autor de "¿Quién movió mi Char?" r
Estos dos objetos del montón t mi
ohtu
tienen un vínculo especial. El cuerdas
interno puede usar las variables
del externo (y viceversa). i mi
nortenorte r

*Hay una excepción a esto, para un caso muy especial: una clase interna definida
dentro de un método estático. Pero no vamos a llegar allí, y es posible que pases
toda tu vida en Java sin encontrarte con uno de estos.

usted está aquí 377


Machine Translated by Google

instancias de clase interna

Cómo hacer una instancia de una clase interna

nuevo MiInterior()

clase MiExterior { En t
La clase externa tiene una variable
de instancia privada 'x'
privado int x;
exterior

MiInterior interno = nuevo MiInterior(); Haga una instancia de la


clase interna

public void hacerCosas() { [Link](); Mi exterior


llamar a un método en la
}
clase interna

clase MiInterior { void


go() { x = 42; X
El método de la clase interna utiliza la
variable de instancia de la clase externa 'x', En t
}
} // cerrar clase interna como si 'x' perteneciera a la clase interna. enlace
especial
exterior
} // cerrar clase externa

Mi exterior

interno

mi interior

clase Foo {
público estático vacío principal (String[] args) {
MiExteriorobjexterno = nuevo MiExterior();
[Link] internalObj = [Link] MyInner();
}
}

378 capítulo 12
Machine Translated by Google

obteniendo gui

Ahora podemos hacer funcionar el


código de dos botones.
la clase GUI principal no
clase pública dos botones {
implementa ActionListener ahora

Marco JFrame;
Etiqueta JLabel;

público estático vacío principal (String[] args) {


Interfaz gráfica de usuario de TwoButtons = nuevos TwoButtons ();
[Link]();
}

vacío público ir () {
marco = nuevo JFrame();
[Link](JFrame.EXIT_ON_CLOSE);

JButton labelButton = new JButton(“Cambiar etiqueta”); en lugar de pasar (this) al método


[Link](new LabelListener()); de registro de escucha del
botón, pase una nueva instancia
JButton colorButton = new JButton(“Cambiar círculo”);
de la clase de escucha apropiada.
[Link](new ColorListener());

etiqueta = new JLabel(“Soy una etiqueta”);


Objeto dos
MiDrawPanel drawPanel = nuevo MiDrawPanel();
botones

[Link]().add([Link], colorButton);
exterior
[Link]().add([Link], drawPanel);
interno
[Link]().add([Link], labelButton);
[Link]().add([Link], etiqueta); Objeto
interno
LabelListener
[Link](300,300); Objeto
[Link] (verdadero); ColorListener
} ¡Ahora podemos
tener DOS
clase LabelListener implementa ActionListener { ActionListeners en una sola clase!
acción vacía pública realizada (evento ActionEvent) {
[Link](“¡Ay!”);
} la clase interna
} // cerrar clase interna conoce la 'etiqueta'

clase ColorListener implementa ActionListener {


acción vacía pública realizada (evento ActionEvent) {
[Link]();
} la clase interna puede usar una
el marco'
} // cerrar clase interna
variable de instancia, sin tener una
referencia explícita a la clase externa
objeto.
}

usted está aquí 379


Machine Translated by Google

clases internas

Entrevista de esta semana:


Instancia de una clase interna

HeadFirst: ¿Qué hace que las clases internas sean importantes? separado de todos los demás. Las clases internas no son exactamente
reutilizables. De hecho, los he oído llamar “Inútiles—
Objeto interior: ¿ Por dónde empiezo? Te damos la oportunidad de
inútil una y otra vez”.
implementar la misma interfaz más de una vez en una clase.
Recuerde, no puede implementar un método más de una vez en una Objeto interno: Sí, es cierto que la clase interna no es tan reutilizable;
clase Java normal. Pero al usar clases internas , cada clase interna de hecho, a veces no es reutilizable en absoluto, porque está
puede implementar la misma interfaz, por lo que puedes tener todas íntimamente ligada a las variables de instancia y métodos de la clase
estas implementaciones diferentes de los mismos métodos de interfaz. externa. Pero­

HeadFirst: ¡Lo cual sólo prueba mi punto! Si no son reutilizables, ¿por qué
HeadFirst: ¿ Por qué querrías implementar el mismo método dos molestarse con una clase separada? Quiero decir, aparte del problema
veces? de la interfaz, que parece una solución alternativa.
a mi.
Objeto interno: revisemos los controladores de eventos de la GUI.
Piénselo... si desea que tres botones tengan cada uno un Objeto interno: como decía, debes pensar en IS­A y el polimorfismo.
comportamiento de evento diferente, entonces use tres clases
internas, todas implementando ActionListener, lo que significa que
CabezaPrimero: Está bien. Y estoy pensando en ellos porque...
cada clase puede implementar su propio método actionPerformed.
Objeto interno: ¡Porque es posible que las clases externa e interna
HeadFirst: Entonces, ¿son los controladores de eventos la única razón para
deban pasar diferentes pruebas IS­A! Comencemos con el ejemplo del
utilizar clases internas?
oyente de GUI polimórfico. ¿Cuál es el tipo de argumento declarado
Objeto interior: Oh, Dios mío, no. Los controladores de eventos son para el método de registro del oyente del botón? En otras
sólo un ejemplo obvio. Siempre que necesite una clase separada, pero palabras, si va a la API y verifica, ¿qué tipo de cosa (clase o tipo de
aún desee que esa clase se comporte como si fuera parte de otra interfaz) debe pasar al método addActionListener()?
clase, una clase interna es la mejor (y a veces la única) forma de hacerlo.

HeadFirst: Tienes que pasar a un oyente. Algo que implemente una


HeadFirst: Todavía estoy confundido aquí. Si desea que la clase interna interfaz de escucha particular, en este caso ActionListener. Sí,
se comporte como si perteneciera a la clase externa, ¿por qué tener sabemos todo esto. ¿Cual es tu punto?
una clase separada en primer lugar? ¿Por qué el código de la clase
Objeto interno: Mi punto es que polimórficamente, tienes un método que
interna no estaría en la clase externa en primer lugar?
toma solo un tipo particular. Algo que pase la prueba IS­A para
Objeto interno: acabo de brindarte un escenario en el que necesitas ActionListener. Pero, y aquí está lo más importante, ¿qué pasa si su
más de una implementación de una interfaz. Pero incluso cuando no esté clase necesita ser un IS­A de algo que es un tipo de clase en lugar de
utilizando interfaces, es posible que necesite dos clases diferentes una interfaz?
porque esas clases representan dos cosas diferentes. Esta bien OO.
HeadFirst: ¿No harías que tu clase ampliara la clase de la que necesitas
ser parte? ¿No es ese el objetivo de cómo funcionan las subclases? Si
De cabeza: Vaya. Espera aquí. Pensé que una gran parte del diseño OO B es una subclase de A, entonces en cualquier lugar donde se espere
tiene que ver con la reutilización y el mantenimiento. Ya sabes, la idea de una A se puede usar una B. Todo eso de pasar un perro donde un
que si tienes dos clases separadas, cada una puede modificarse y animal es del tipo declarado.
usarse de forma independiente, en lugar de meterlo todo en una clase yada
Objeto interior: ¡Sí! ¡Bingo! Entonces, ¿qué pasa si necesitas aprobar el
yada yada. Pero con una clase interna , al final todavía estás trabajando
examen IS­A para dos clases diferentes? ¿Clases que no están en la
con una clase real , ¿verdad?
misma jerarquía de herencia?
La clase adjunta es la única que es reutilizable y

380 capítulo 12
Machine Translated by Google

obteniendo gui

HeadFirst: Oh, bueno, tú simplemente... hmmm. Creo que lo estoy HeadFirst: ¿La vida de quién? ¿Tuyo? ¿El objeto exterior? ¿Ambos?
entendiendo. Siempre puedes implementar más de una interfaz, pero solo
Objeto interior: Mío. No puedo estar atado a ningún otro objeto exterior.
puedes extender una clase. Sólo puedes ser un tipo de IS­A cuando se
Mi única salida es la recogida de basura.
trata de tipos de clases .
HeadFirst: ¿Qué pasa con el objeto exterior? ¿Se puede asociar
Objeto interior: ¡Bien hecho! Sí, no puedes ser al mismo tiempo un Perro
con otros objetos internos?
y un Botón. Pero si eres un Perro que a veces necesita ser un Botón
(para poder pasar a métodos que toman un Botón), la clase Perro (que Objeto interior: ahora lo tenemos. Esto es lo que realmente querías. Sí Sí.

extiende Animal para que no pueda extender el Botón) puede tener una Mi así llamado 'compañero' puede tener tantos objetos internos como

clase interna que actúa en nombre del Perro como un Botón, extendiendo quiera.

el Botón y, por lo tanto, dondequiera que se requiera un Botón, el HeadFirst: ¿Eso es monogamia en serie? ¿O puede tenerlos todos al
Perro puede pasar su Botón interno en lugar de él mismo. En otras mismo tiempo?
palabras, en lugar de decir [Link](this), el objeto Dog llama a
Objeto interior: Todo al mismo tiempo. Allá. ¿Satisfecho?
[Link](new MyInnerButton()).
HeadFirst: Bueno, tiene sentido. Y no lo olvidemos, fuiste tú quien
ensalzó las virtudes de “múltiples implementaciones de la misma
HeadFirst: ¿Puedo darme un ejemplo claro?
interfaz”. Entonces tiene sentido que si la clase externa tiene tres botones,
Objeto interno: ¿Recuerdas el panel de dibujo que usamos, donde necesitaría tres clases internas diferentes (y por lo tanto tres objetos
creamos nuestra propia subclase de JPanel? En este momento, esa de clase interna diferentes) para manejar los eventos. Gracias por todo.
clase es una clase separada, no interna. Y eso está bien, porque la
clase no necesita acceso especial a las variables de instancia de la GUI Aquí tienes un pañuelo.
principal. Pero ¿y si así fuera? ¿Qué pasa si estamos haciendo una
animación en ese panel y obtiene sus coordenadas de la aplicación
principal (por ejemplo, en función de algo que el usuario hace en otra
parte de la GUI)? En ese caso, si convertimos el panel de dibujo en
una clase interna, la clase del panel de dibujo pasa a ser una Él piensa que es
subclase de JPanel, mientras que la clase externa sigue siendo libre Lo hice, teniendo objetos dos
de ser una subclase de otra cosa.
de clase interna. Pero tenemos nosotros

HeadFirst: ¡Sí, ya veo! Y el panel de dibujo no es lo suficientemente acceso a todos sus datos privados, así
reutilizable como para ser una clase separada de todos modos, ya que lo que imagina el daño que podríamos causar...
que realmente está pintando es específico de esta aplicación GUI.

Objeto interior: ¡Sí! ¡Tu lo tienes!

De cabeza: Bien. Luego podemos pasar a la naturaleza de la relación entre

tú y la instancia externa.

Objeto interior: ¿Qué pasa con ustedes? ¿No hay suficientes chismes
sórdidos en un tema tan serio como el polimorfismo?

HeadFirst: Oye, no tienes idea de cuánto está dispuesto el público a pagar


por alguna buena basura de los tabloides. Entonces, alguien te crea y se
une instantáneamente al objeto exterior, ¿verdad?

Objeto interior: Sí, es cierto. Y sí, algunos lo han comparado con


un matrimonio arreglado. No tenemos voz y voto sobre a qué objeto estamos
vinculados.

HeadFirst: Muy bien, seguiré la analogía del matrimonio.


¿Puedes divorciarte y volver a casarte con otra cosa?

Objeto interior: No, es para toda la vida.

usted está aquí 381


Machine Translated by Google

clases internas

Usando una clase interna para animación

comenzar finalizar

no existen
Preguntas tontas

Cómo funciona la animación simple

1 Pintar un objeto en una coordenada xey particular


[Link](20,50,100,100);

20 píxeles desde la
izquierda, 50 píxeles desde arriba

2 Vuelva a pintar el objeto en una coordenada x e y diferente


[Link](25,55,100,100);

25 píxeles desde la izquierda, 55


píxeles desde arriba

(el objeto se movió un poco


hacia abajo y hacia la derecha)

3 Repita el paso anterior cambiando los valores de x e y durante


el tiempo que se supone que debe continuar la animación.

382 capítulo 12
Machine Translated by Google

obteniendo gui

Lo que realmente queremos es algo como...

clase MyDrawPanel extiende JPanel {


componente de pintura público vacío (Gráficos g) {
[Link]([Link]);
[Link](x,y,100,100);
}
cada vez que se llama a
} paintComponent(), el óvalo se pinta
en una ubicación diferente

Afila tu lápiz

Pero, ¿de dónde sacamos las nuevas coordenadas xey?

¿Y quién llama a repintar()?

usted está aquí 383


Machine Translated by Google

animación usando una clase interna

El código completo de animación simple.

importar [Link].*;
importar [Link].*;

clase pública Animación simple {


cree dos variables de instancia en la
entero x = 70; clase GUI principal, para las
int y = 70; coordenadas xey del círculo.

público estático vacío principal (String[] args) {


Interfaz gráfica de usuario SimpleAnimation = nueva SimpleAnimation ();
[Link]();
}

vacío público ir () {
Marco JFrame = nuevo JFrame();
[Link](JFrame.EXIT_ON_CLOSE);

MiDrawPanel drawPanel = nuevo MiDrawPanel();


Nada
nuevo aquí. Haz los widgets
[Link]().add(drawPanel); y colócalos en el marco.
[Link](300,300);
[Link] (verdadero);

¡Aquí es donde para (int i = 0; i < 130; i++) { repite esto 130 veces
está la acción!
x++;
y++; incrementar x e y
coordenadas
decirle al panel que se vuelva a pintar (para
[Link](); que podamos ver el círculo en la nueva ubicación)

intentar {
[Link](50);
} captura (Excepción ex) { } Disminuya un poco la velocidad (de lo contrario, se
} moverá tan rápido que no VERÁ que se
preocuparte
mueve). No se suponía que ya supiera esto. Llegaremos
}// cerrar el método go() a los hilos en el capítulo 15.

Ahora es una clase MyDrawPanel extiende JPanel {


clase interna.
componente de pintura público vacío (Gráficos g) {
[Link]([Link]);
[Link](x,y,40,40);
coordenadas
Utilice x e y continuamente actualizados
de la clase exterior.
}
} // cerrar clase interna
} // cerrar clase externa

384 capítulo 12
Machine Translated by Google

obteniendo gui

UH oh. No se movió... manchado .


que hicimos mal?

Hay un pequeño defecto en el método paintComponent().

¡Nos olvidamos de borrar lo que ya No es exactamente el


estaba allí! Entonces tenemos senderos. aspecto que buscábamos.

Para solucionarlo, lo único que tenemos que hacer es rellenar todo el


panel con el color de fondo, antes de pintar el círculo cada vez. El
siguiente código agrega dos líneas al inicio del método: una para
establecer el color en blanco (el color de fondo del panel de dibujo)
y la otra para llenar todo el rectángulo del panel con ese color.
En inglés, el siguiente código dice: “Rellene un rectángulo que
comience en xey de 0 (0 píxeles desde la izquierda y 0 píxeles desde
arriba) y hágalo tan ancho y alto como tiene actualmente el panel.

componente de pintura público vacío (Gráficos g) {


[Link]([Link]);
[Link](0,0,[Link](), [Link]());

[Link]([Link]);
[Link](x,y,40,40);
getWidth() y getHeight() son métodos
heredados de JPanel.
}

X +3 X

Y +3 Y

X X

Y Y

X X

Y Y

usted está aquí 385


Machine Translated by Google

Código Cocina

vencer a uno vencer a dos vencer a tres vencer a cuatro...

Recuerde, esta parte es opcional. Pero creemos que es bueno para ti.
Y te gustará. Y puedes usarlo para impresionar a la gente.

(Vale, claro, puede que funcione sólo con personas que son realmente fáciles de impresionar,
pero aun así...)

386 capítulo 12
Machine Translated by Google

obteniendo gui

Escuchando un evento que no es GUI

Lo que debe hacer el programa de arte


musical:

1 Cree una serie de mensajes MIDI/


eventos para tocar notas aleatorias en un
piano (o cualquier instrumento que elijas)

2 Registre un oyente para los eventos.

3 Inicie la reproducción del secuenciador

4 Cada vez que el evento del oyente


Se llama al método del controlador, se
dibuja un rectángulo aleatorio en el panel
de dibujo y se llama a repintar.

Lo construiremos en tres iteraciones:

1 Versión uno: Código que simplifica la creación


y adición de eventos MIDI, ya que crearemos
muchos de ellos.

2 Versión Dos: Regístrate y escucha


los eventos, pero sin gráficos.
Imprime un mensaje en la línea de comando
con cada latido.

4 Versión tres: la auténtica. Agrega gráficos


a la versión dos.

usted está aquí 387


Machine Translated by Google

método de utilidad para eventos

Una manera más fácil de


hacer mensajes/eventos
Cosas que tienen que suceder para cada evento:

1 Crea una instancia de mensaje


Mensaje Corto primero = nuevo Mensaje Corto();

2 Llame a setMessage() con las instrucciones


[Link](192, 1, instrumento, 0)

3 Crea una instancia de MidiEvent para el mensaje.


Mensaje Corto a = nuevo Mensaje Corto();
[Link](144, 1, nota, 100); MidiEvent noteOn = nuevo MidiEvent(primero, 1);
MidiEvent noteOn = nuevo MidiEvent(a, 1); [Link](notaEn);

4 Añade el evento a la pista


Mensaje Corto b = nuevo Mensaje Corto();
[Link](128, 1, nota, 100); [Link](notaEn);
MidiEvent noteOff = nuevo MidiEvent(b, 16);
[Link](notaDesactivada);

Creemos un método de utilidad estático que El evento 'tick' para


genere un mensaje y devuelva un MidiEvent. Los cuatro CUÁNDO debería
argumentos del [Link] este mensaje

MidiEvent estático público makeEvent (int comd, int chan, int uno, int dos, int tick) {

Evento MidiEvent = nulo;


¡vaya! Un método con cinco parámetros.
intentar {

Mensaje Corto a = nuevo Mensaje Corto();

[Link](comd, chan, uno, dos); convertir el mensaje


evento = nuevo MidiEvent(a, marca); en los parámetros del método
y el evento, usando

}catch(Excepción e) { }

evento de regreso;
devolver el evento (un MidiEvent
} todo cargado con el mensaje)

388 capítulo 12
Machine Translated by Google

obteniendo gui

Ejemplo: cómo utilizar el nuevo método


estático makeEvent()

importar [Link].*;
no olvides la importación
clase pública MiniMusicPlayer1 {

público estático vacío principal (String [] argumentos) {

intentar {

hacer (y abrir) un secuenciador


Secuenciador secuenciador = [Link](); [Link]();

Secuencia secuencia = nueva Secuencia ([Link], 4); hacer una secuencia


Seguimiento de seguimiento = [Link](); y una pista

para (int i = 5; i < 61; i+= 4) { haga un montón de eventos para que las notas sigan
subiendo (desde la nota de piano 5 hasta la nota de piano 61)

[Link](makeEvent(144,1,i,100,i)); llama a nuestro


[Link](makeEvent(128,1,i,100,i + 2)); Método makeEvent() para hacer que el
nuevo mensaje
y evento, luego agregue el resultado (el
} // finalizar bucle MidiEvent regrese desde makeEvent()) a la pista.
Estos son los pares NOTA ENCENDIDA (144) y
[Link](seq); NOTA APAGADA (128)
[Link](220); ponlo en marcha
[Link]();
} captura (Excepción ex) {[Link]();}
} // cerrar principal

MidiEvent estático público makeEvent (int comd, int chan, int uno, int dos, int tick) {
Evento MidiEvent = nulo;
intentar {
Mensaje Corto a = nuevo Mensaje Corto();
[Link](comd, chan, uno, dos);
evento = nuevo MidiEvent(a, marca);

}catch(Excepción e) { }
evento de regreso;
}
} // cerrar clase

usted está aquí 389


Machine Translated by Google

eventos del controlador

Versión dos: registrarse y obtener ControllerEvents


Necesitamos escuchar ControllerEvents, por
lo que implementamos la interfaz de escucha
importar [Link].*;
la clase pública MiniMusicPlayer2 implementa ControllerEventListener {

público estático vacío principal (String [] argumentos) {


MiniMusicPlayer2 mini = nuevo MiniMusicPlayer2();
[Link]();
}
vacío público ir () { Regístrese para eventos con el secuenciador.
El método de registro de eventos toma el oyente
intentar { Y una matriz int que representa la lista de
Secuenciador secuenciador = [Link](); [Link](); ControllerEvents que desea.
Sólo queremos un evento, el n.° 127.

int[] eventosQuiero = {127};


[Link] (esto, eventosIWant);

Secuencia secuencia = nueva Secuencia ([Link], 4);


Seguimiento de seguimiento = [Link]();

para (int i = 5; i < 60; i+= 4) { Así es como retomamos el ritmo: insertamos
[Link](makeEvent(144,1,i,100,i)); nuestro PROPIO ControllerEvent (176 dice que el
tipo de evento es ControllerEvent) con un argumento
[Link](makeEvent(176,1,127,0,i)); para el evento número 127. ¡Este evento no servirá
de NADA! Lo ponemos en JUST para poder
[Link](makeEvent(128,1,i,100,i + 2)); obtener un evento cada vez que se toca una nota.
} // finalizar bucle En otras palabras, su único propósito es que se
active algo que NOSOTROS podamos escuchar
[Link](seq); (no podemos escuchar los eventos NOTA ON/OFF).
[Link](220); Tenga en cuenta que haremos que este evento
[Link](); suceda en el MISMO tic que la NOTA EN. Entonces,
} captura (Excepción ex) {[Link]();} cuando ocurra el evento NOTA EN, lo sabremos
} // cerca porque NUESTRO evento se activará al mismo tiempo.

cambio de control de vacío público (evento de mensaje corto) { El método del controlador de eventos (desde la interfaz de
[Link](“la”); escucha Controlador­Evento). Cada vez que obtengamos
} el evento, imprimiremos "la" en la línea de comando.

public MidiEvent makeEvent(int comd, int chan, int uno, int dos, int tick) {
Evento MidiEvent = nulo;
intentar {
Mensaje Corto a = nuevo Mensaje Corto();
[Link](comd, chan, uno, dos);
evento = nuevo MidiEvent(a, marca);
El código que es diferente de la versión anterior
}catch(Excepción e) { } se resalta en gris. (y esta vez no lo ejecutaremos
evento de regreso; todo dentro de main())
}
} // cerrar clase

390 capítulo 12
Machine Translated by Google

obteniendo gui

Versión tres: dibujar gráficos al ritmo de la música

La clase interna del panel de dibujo:

El panel de dibujo es un oyente.

clase MyDrawPanel extiende JPanel implementa ControllerEventListener {

Establecemos una bandera en falso y la estableceremos


mensaje booleano = falso;
en verdadero solo cuando obtengamos un evento.

cambio de control de vacío público (evento de mensaje corto) {


mensaje =
verdadero; repintar(); Obtuvimos un evento, así que configuramos la bandera en
} verdadero y llamamos a repaint()

componente de pintura público vacío (Gráficos g) {


si (mensaje) {
Tenemos que usar una bandera porque OTRAS cosas pueden desencadenar un repintado(), y queremos
pintar SÓLO cuando hay un ControllerEvent
Gráficos2D g2 = (Gráficos2D) g;

int r = (int) ([Link]() * 250);


int gr = (int) ([Link]() * 250);
int b = (int) ([Link]() * 250); El resto es código para generar un color
aleatorio y pintar un rectángulo
[Link](nuevo Color(r,gr,b)); semialeatorio.

int ht = (int) (([Link]() * 120) + 10);


int ancho = (int) (([Link]() * 120) + 10);
int x = (int) (([Link]() * 40) + 10);
int y = (int) (([Link]() * 40) + 10); [Link](x,y,ht, ancho);

mensaje = falso;

} // cerrar si
} // cerrar método
} // cerrar clase interna

usted está aquí 391


Machine Translated by Google

Código MiniMusicPlayer3

Afila tu lápiz
importar [Link].*; Esta es la lista de códigos completa para la versión tres.
importar [Link].*; Construye directorio en la versión dos. Intente anotarlo
importar [Link].*;
usted mismo, sin mirar las páginas anteriores.
importar [Link].*;

clase pública MiniMusicPlayer3 {

JFrame estático f = nuevo JFrame ("Mi primer vídeo musical");


MyDrawPanel estático ml;

público estático vacío principal (String [] argumentos) {


MiniMusicPlayer3 mini = nuevo MiniMusicPlayer3();
[Link]();
} // cerrar método

setUpGui público vacío() {


ml = nuevo MiDrawPanel();
[Link](ml);
[Link](30,30, 300,300);
[Link] (verdadero);
} // cerrar método

vacío público ir () {
setUpGui();

intentar {

Secuenciador secuenciador = [Link]();


[Link]();
[Link](ml, new int[] {127});
Secuencia secuencia = nueva Secuencia ([Link], 4);
Seguimiento de seguimiento = [Link]();

int r = 0;
para (int i = 0; i < 60; i+= 4) {

r = (int) (([Link]() * 50) + 1);


[Link](makeEvent(144,1,r,100,i));
[Link](makeEvent(176,1,127,0,i));
[Link](makeEvent(128,1,r,100,i + 2));
} // finalizar bucle

[Link](seq);
[Link]();
[Link](120);
} captura (Excepción ex) {[Link]();}
} // cerrar método

392 capítulo 12
Machine Translated by Google

obteniendo gui

public MidiEvent makeEvent(int comd, int chan, int uno, int dos, int tick) {
Evento MidiEvent = nulo; Pruebe
{Mensaje
Corto a = nuevo Mensaje Corto(); [Link](comd, chan,
uno, dos); evento = nuevo MidiEvent(a, marca);

}catch(Excepción e) { } evento de
retorno; } // cerrar
método

clase MyDrawPanel extiende JPanel implementa ControllerEventListener {


mensaje booleano = falso;

cambio de control público vacío (evento de mensaje corto) { msj = verdadero;


repintar();

componente de pintura público vacío (Gráficos g) {


si (mensaje) {

Gráficos2D g2 = (Gráficos2D) g;

int r = (int) ([Link]() * 250); int gr = (int) ([Link]()


* 250); int b = (int) ([Link]() * 250);

[Link](nuevo Color(r,gr,b));

int ht = (int) (([Link]() * 120) + 10); int ancho = (int) (([Link]() *


120) + 10);

int x = (int) (([Link]() * 40) + 10); int y = (int) (([Link]() * 40)


+ 10);

[Link](x,y,ht, ancho); mensaje = falso;

} // cerrar si } // cerrar
método } // cerrar clase
interna

} // cerrar clase

usted está aquí 393


Machine Translated by Google

Ejercicio: ¿Quién soy yo?

¿Quién soy?

Tengo toda la GUI en mis manos.

Cada tipo de evento tiene uno de estos.

El método clave del oyente.

Este método le da a JFrame su tamaño.

Agrega código a este método pero nunca lo llama.

Cuando el usuario realmente hace algo, es un _____ .

La mayoría de estos son fuentes de eventos.

Llevo datos al oyente.

Un método addXxxListener() dice que un objeto es un _____ .

Cómo se registra un oyente.

El método donde va todo el código gráfico.

Normalmente estoy vinculado a una instancia.

La 'g' en (Gráficos g), es realmente de clase.

El método que hace funcionar paintComponent().

El paquete donde residen la mayoría de los Swingers.

394 capítulo 12
Machine Translated by Google

obteniendo gui

El archivo Java en esta página


representa un archivo fuente completo.
importar [Link].*;
Su trabajo es jugar al compilador y
importar [Link].*;
determinar si este archivo se
importar [Link].*; compilará. Si no se compila,
¿cómo lo solucionaría y, si se compila, qué
clase botón interno {

Marco JFrame;
JBotón b;

public static void main(String [] args) { InnerButton


gui = nuevo InnerButton(); [Link]();

public void go() { marco


= nuevo JFrame();

[Link]( JFrame.EXIT_ON_CLOSE);

b = nuevo JButton(“A”);
[Link]();

[Link]().add( [Link], b);


[Link](200,100);
[Link] (verdadero);
}

clase BListener extiende ActionListener {


actionPerformed public void(ActionEvent e) { if
([Link]().equals(“A”)) {
[Link](“B”); }
más
{ [Link](“A”);
}
}
}
}
usted está aquí 395
Machine Translated by Google

rompecabezas: rompecabezas de piscina


importar [Link].*; importar
[Link].*; clase pública Animar
{ int x = 1; int y = 1; public static void
main (String[]
Rompecabezas de piscina args) { Animate
gui = new Animate (); [Link]();

} público vacío ir() {


Marco J _________ = nuevo JFrame();
[Link]( JFrame.EXIT_ON_CLOSE);

______________________________________;
_________.getContentPane().add(drawP);

__________________________;
_________.setVisible(verdadero); para (int i=0;

i<124; _______________) {

_____________________;

_____________________; prueba

{ [Link](50); } captura
(Excepción ex) { } }

} clase MyDrawP extiende JPanel {

Componente de pintura public void (Gráfico _________) {

__________________________________;

__________________________________;

__________________________________;

__________________________________;
}
}
}

396 capítulo 12
Machine Translated by Google

obteniendo gui

Soluciones de ejercicio

Una vez que se


importar [Link].*;
corrija este código,
importar [Link].*;
¿Quién soy? importar [Link].*;
creará una GUI con un
botón que alterna
entre A y B cuando
Marco J clase botón interno { hace clic en él.

interfaz de escucha
Marco JFrame;
JBotón b;
acción realizada( )

establecerTamaño( )
public static void main(String [] args) { InnerButton
gui = nuevo InnerButton(); [Link]();

componente de pintura () }

public void go() { marco


evento
= nuevo JFrame();
[Link](
componentes del columpio
JFrame.EXIT_ON_CLOSE);
objeto de evento

El método addActionListener()
toma una clase que implementa la
fuente del evento
interfaz ActionLis­tener

agregarActionListener()

b = nuevo JButton(“A”);
componente de pintura () [Link]( nuevo BListener( ) );

clase interna

[Link]().add( [Link], b);


[Link](200,100);
Gráficos2d
[Link] (verdadero);
}
repintar ( )
clase BListener implementa ActionListener {
acción vacía pública realizada (ActionEvent e) {
[Link]
si ([Link]().equals(“A”)) {
[Link](“B”); }
ActionListener es una
más
interfaz, las interfaces
{ [Link](“A”);
están implementadas, no
} extendidas
}
}
}

usted está aquí 397


Machine Translated by Google

respuestas del rompecabezas

Rompecabezas de piscina

importar [Link].*; importar


[Link].*;
clase pública Animar {
entero x = 1;
int y = 1;
público estático vacío principal (String[] args) {
Animar gui = nuevo Animar ();
[Link]();

} public void go() { marco


JFrame = nuevo JFrame();
[Link](
JFrame.EXIT_ON_CLOSE);
MiDrawP drawP = new MiDrawP();
[Link]().add(drawP);
[Link](500,270);
[Link] (verdadero); para
(int i = 0; i < 124; i++,x++,y++ ) {
x++;
[Link]();
prueba
{ [Link](50); }
captura (excepción ex) { }
}
}
clase MyDrawP extiende JPanel {
componente de pintura público vacío (Gráficos g ) {
[Link]([Link]);
[Link](0,0,500,250);
[Link]([Link]);
[Link](x,y,500­x*2,250­y*2);
}
}
}

398 capítulo 12
Machine Translated by Google

13 usando columpio

Trabaja en tu ¿Por qué la

pelota no va a donde I desear

Balancearse debe ir? (como, una bofetada en la cara

de Suzy Smith) Tengo que aprender a


controlarlo.

El swing es fácil.

este es un nuevo capitulo 399


Machine Translated by Google

componentes y contenedores

Componentes del columpio

[Link]

Los componentes se pueden anidar

Cuatro pasos para hacer una GUI (revisión)


1 Hacer una ventana (un JFrame)
Marco JFrame = nuevo JFrame();

2 Cree un componente (botón, campo de texto, etc.)


Botón JButton = nuevo JButton(“haz clic en mí”);

3 Agregue el componente al marco.


[Link]().add([Link], botón);

4 Muéstralo (dale un tamaño y hazlo visible)


[Link](300,300);
[Link] (verdadero);

Poner componentes interactivos: En componentes de fondo:

JBotón
Marco J JPanel
JCheckBox

JTextField

400 capitulo 13
Machine Translated by Google

usando columpio

Administradores de diseño
Como administrador de
diseño, estoy a cargo del
tamaño y la ubicación de sus componentes.
En esta GUI, soy yo quien decide qué tan
grandes deben ser estos botones y dónde
están entre sí y con el marco.

El administrador de diseño del


Panel A controla el tamaño
El administrador de diseño y la ubicación del Panel B.
[Link](botón);
del Panel B controla el tamaño y la
ubicación de los tres botones.

botón 1

botón 2

botón 3

Grupo B

JPanel panelA = nuevo JPanel(); Grupo A

JPanel panelB = nuevo JPanel();


El administrador de diseño del Panel A no tiene
[Link](new JButton(“botón 1”));
NADA que decir sobre los tres botones. La
jerarquía de control es
[Link](new JButton(“botón 2”)); de un solo nivel: el

[Link](new JButton(“botón 3”)); administrador de diseño del Panel A controla solo las
cosas agregadas directamente al Panel A y no
[Link](panelB); controla nada anidado dentro de esos componentes agregados.

usted está aquí 401


Machine Translated by Google

administradores de diseño

¿Cómo decide el administrador de diseño?

A ver aquí... el primer

Un escenario de diseño: botón quiere ser


30 píxeles de ancho, y el campo de
1 Haz un panel y agrégale tres botones. texto necesita 50, y el marco tiene 200
píxeles de ancho y se supone que
2 El administrador de diseño del panel pregunta a cada debo organizar todo verticalmente...
botón qué tan grande prefiere ser.

3 El administrador de diseño del panel utiliza sus políticas de diseño


para decidir si debe respetar todas, parte o ninguna de las
preferencias de los botones.

4 Agregue el panel a un marco.

5 El administrador de diseño del marco le pregunta al panel qué tan grande


prefiere que sea.

6 El administrador de diseño del marco utiliza sus políticas de diseño para


decidir si debe respetar todas, parte o ninguna de las preferencias del
panel.
administrador de diseño

Diferentes administradores de diseño tienen políticas diferentes

402 capítulo 13
Machine Translated by Google

usando columpio

Los tres grandes administradores de


diseño: borde, flujo y cuadro.

Diseño de borde
Un administrador de BorderLayout divide un componente
de fondo en cinco regiones. Puede agregar solo un componente
por región a un fondo controlado por un administrador de
un componente
por región
BorderLayout. Los componentes dispuestos por este
administrador normalmente no llegan a tener su tamaño
preferido. BorderLayout es el administrador de diseño predeterminado
para un marco.

Diseño de flujo
Un administrador FlowLayout actúa como un procesador de
textos, excepto que tiene componentes en lugar de palabras.
componentes agregados de izquierda
Cada componente tiene el tamaño que desea y están dispuestos
a derecha, ajustándose a una línea
nuevo
de izquierda a derecha en el orden en que se agregan, con el cuando sea necesario

"ajuste de palabras" activado. Entonces, cuando un


componente no encaja horizontalmente, pasa a la siguiente
“línea” del diseño. ¡FlowLayout es el administrador de diseño
predeterminado para un panel!

Diseño de caja
Un administrador BoxLayout es como FlowLayout en el
sentido de que cada componente tiene su propio tamaño y
los componentes se colocan en el orden en que se agregan.
componentes agregados
Pero, a diferencia de FlowLayout, un administrador de BoxLayout de arriba a abajo, uno por 'línea'
puede apilar los componentes verticalmente (u horizontalmente,
pero normalmente solo nos preocupamos verticalmente). Es
como un FlowLayout pero en lugar de tener un 'ajuste de
componentes' automático, puedes insertar una especie de
'tecla de retorno de componente' y forzar
los componentes para iniciar una nueva línea.

estás aquí 403


Machine Translated by Google

diseño de borde

BorderLayout se preocupa
por cinco regiones: este,
oeste, norte, sur y
centro

Agreguemos un botón a la región este:

importar [Link].*;
BorderLayout está en el paquete [Link]
importar [Link].*;

Botón de clase pública1 {

público estático vacío principal (String[] args) {


Botón1 interfaz gráfica de usuario = nuevo Botón1();
[Link]();
}

vacío público ir () {
especificar la región
Marco JFrame = nuevo JFrame();
Botón JButton = nuevo JButton(“haz clic en mí”);
[Link]().add([Link], botón);
[Link](200,200);
[Link] (verdadero);
}
}

Barra cerebral
cerebro
con barra

¿Cómo se le ocurrió al administrador de BorderLayout este


tamaño para el botón?

¿Cuáles son los factores que debe considerar el administrador


de diseño?

¿Por qué no es más ancho o más alto?

404 capítulo 13
Machine Translated by Google

usando columpio

Mira lo que pasa cuando le damos más caracteres al


botón...
Cambiamos solo el texto.
en el botón
vacío público ir () {
Marco JFrame = nuevo JFrame();
Botón JButton = nuevo JButton ("haga clic en serio");
[Link]().add([Link], botón);
[Link](200,200);
[Link] (verdadero);
}

Primero, le pregunto
al botón su tamaño
Ahora tengo muchas
preferido.
palabras, así que preferiría
tener 60 píxeles de ancho y
25 píxeles de alto.

t
C
Btut t bj mi
ohnorte oh

Ya que está en el este

región de un diseño de borde,


respetaré su ancho preferido. Pero no me La próxima
importa qué tan alto quiera ser; Será tan alto
vez optaré por el diseño
como el marco, porque esa es mi política. de flujo. Entonces
obtengo TODO lo que
desear.

El botón obtiene
su ancho preferido,
t
pero no su altura. Btut t C
bj mi
ohnorte oh

estas aqui 405


Machine Translated by Google

diseño de borde

Probemos un botón en la región NORTE.

vacío público ir () {
Marco JFrame = nuevo JFrame();
Botón JButton = new JButton(“No hay cuchara...”);
[Link]().add([Link], botón);
[Link](200,200);
[Link] (verdadero);
}

El botón es tan alto como


quiere ser, pero tan ancho como
el marco.

Ahora hagamos que el botón pida ser más alto.

¿Como hacemos eso? El botón ya es más ancho que nunca: tan


ancho como el marco. Pero podemos intentar hacerlo más alto

dándole una fuente más grande.

vacío público ir () {
Marco JFrame = nuevo JFrame(); Una fuente más grande
Botón JButton = nuevo JButton ("¡Haga clic en esto!"); obligará al marco a asignar más
Fuente bigFont = nueva fuente ("serif", [Link], 28); espacio para la altura del botón.
botó[Link](bigFont);
[Link]().add([Link], botón);
[Link](200,200);
[Link] (verdadero);
}
El ancho sigue siendo el mismo, pero
ahora el botón es más alto. La
región norte se estiró para
adaptarse a la nueva altura preferida del botón.

406 capítulo 13
Machine Translated by Google

usando columpio

Creo que lo estoy entendiendo... si estoy en el


este o en el oeste, obtengo mi ancho preferido,
pero la altura depende del administrador de
diseño. Y si estoy en el norte o en el sur, es
todo lo contrario: obtengo mi altura preferida, pero
no el ancho.

t
C
Btut t bj mi
ohnorte oh

¡La región central se queda con lo que queda! (excepto en un caso especial
que veremos más adelante)

vacío público ir () {
Marco JFrame = nuevo JFrame();

JButton este = nuevo JButton(“Este”);


JButton oeste = nuevo JButton(“Oeste”);
JButton norte = nuevo JButton(“Norte”);
JButton sur = nuevo JButton(“Sur”);
Centro JButton = nuevo JButton(“Centro”);

[Link]().add([Link], este);
[Link]().add([Link], oeste);
[Link]().add([Link], norte);
[Link]().add([Link], sur);
[Link]().add([Link], centro);

[Link](300,300);
[Link] (verdadero);
}

Los componentes del centro ocupan


el espacio Cuando pones algo en el norte o
Residencia en sobrante,
en el sur, recorre todo el marco,
las dimensiones del marco
(300 x 300 en este código). por lo que las cosas al otro lado de

en el este y el
píxeles

oeste no serán tan


300

altas como lo serían si las

regiones norte y sur estuvieran


Los componentes del este y
vacías.
del oeste obtienen su ancho preferido.

Los componentes del norte y


del sur obtienen su preferencia
altura.
300 píxeles

estás aquí 407


Machine Translated by Google

diseño de flujo

FlowLayout se preocupa
por el flujo de los componentes:

de izquierda a derecha, de arriba a abajo,


en el orden en que fueron agregados.

Agreguemos un panel a la región este:

El administrador de diseño de un JPanel es FlowLayout, por defecto. Cuando


agregamos un panel a un marco, el tamaño y la ubicación del panel todavía
cosa el
están bajo el control del administrador de BorderLayout. pero cualquier adentro
panel (en otras palabras, los componentes agregados al panel llamando a
[Link](aComponent)) están bajo el control del administrador FlowLayout del
panel. Comenzaremos colocando un panel vacío en la región este del marco y en las
páginas siguientes agregaremos cosas al panel.
El panel no tiene nada, por
lo que no requiere mucho
ancho en la región este.

importar [Link].*;
importar [Link].*;

clase pública Panel1 {

público estático vacío principal (String[] args) {


Panel1 interfaz gráfica de usuario = nuevo Panel1();
[Link]();
}

vacío público ir () {
Marco JFrame = nuevo JFrame(); Panel Haga el panel gris para que podamos
JPanel = nuevo JPanel(); ver dónde está en el marco.
[Link]([Link]);
[Link]().add([Link], panel);
[Link](200,200);
[Link] (verdadero);
}
}

408 capítulo 13
Machine Translated by Google

usando columpio

Agreguemos un botón al panel.

vacío público ir () {
Marco JFrame = nuevo JFrame(); Panel JPanel
= nuevo JPanel();
Agregue el botón al panel y agregue el
[Link]([Link]);
panel al marco. El administrador de diseño del
panel (flujo) controla el botón y el
Botón JButton = nuevo JButton ("dame una sorpresa");
administrador de diseño del marco (borde) controla el panel.
panel.añadir(botón);
[Link]().add([Link], panel);

[Link](250,200);
[Link] (verdadero);
}

¡El panel se amplió!

Y el botón obtuvo su
panel panel
tamaño preferido en
ambas dimensiones, porque el panel
usos
diseño de flujo y el
El botón es parte del panel
(no del marco).

Ok... necesito Necesito

saber qué tan grande para saber qué tan grande


quiere ser el botón
quiere ser el panel ...

Según el tamaño de mi
Tengo un botón ahora fuente y el número de
así que mi administrador de caracteres, quiero que tengan 70
diseño tendrá que determinar píxeles de ancho y 20 píxeles de alto.
qué tan grande debo ser...

t
Btu mi C
t t oh ohbj
control S control S
a mi bjeC t
PAG
norte yo
oh
norte

el marco el panel
Administrador de diseño de bordes Administrador de diseño de flujo

estas aqui 409


Machine Translated by Google

diseño de flujo

¿Qué pasa si agregamos DOS botones al panel?

vacío público ir () {
Marco JFrame = nuevo JFrame(); Panel JPanel
= nuevo JPanel();
[Link]([Link]);

hacer DOS botones


Botón JButton = nuevo JButton ("dame una sorpresa");
JButton botónDos = nuevo JButton(“bienaventuranza”);

panel.añadir(botón);
[Link](botónDos); agregue AMBOS al panel

[Link]().add([Link], panel);
[Link](250,200);
[Link] (verdadero);
}

lo que nosotros buscado : lo que nosotros :


consiguió

Queremos que los botones


se apilen encima de cada uno. El panel expandido se ajusta a
otro a ambos lados de los botones.
al lado.

observe que el botón 'felicidad' es más pequeño que el


botón 'shock me'... así es como funciona el diseño
de flujo. El botón obtiene exactamente lo que
necesidades (y nada más).

Afila tu lápiz

Botón JButton = nuevo JButton ("dame una sorpresa");


JButton botónDos = nuevo JButton(“bienaventuranza”);
JButton botónTres = nuevo JButton(“¿Eh?”);
panel.añadir(botón);
[Link](botónDos);
[Link](botónTres);

410 capítulo 13
Machine Translated by Google

usando columpio

¡BoxLayout al rescate!
Mantiene los componentes
apilados, incluso si hay espacio para
colocarlos uno al lado del otro.

A diferencia de FlowLayout, BoxLayout puede forzar


una 'nueva línea' para hacer que los componentes
pasen a la siguiente línea, incluso si hay espacio para
que quepan horizontalmente.

Pero ahora tendrás que cambiar el administrador de diseño del panel del FlowLayout
predeterminado a BoxLayout.

vacío público ir () {
Marco JFrame = nuevo JFrame(); Panel JPanel
= nuevo JPanel(); Cambie el administrador de diseño para que sea una

[Link]([Link]); nueva instancia de BoxLayout.

[Link](nuevo BoxLayout(panel, BoxLayout.Y_AXIS));

Botón JButton = nuevo JButton ("dame una sorpresa"); El constructor BoxLayout necesita conocer el
JButton botónDos = nuevo JButton(“bienaventuranza”);
ycomponente
que eje usarque está diseñando
(usamos
(es decir, el panel).
panel.añadir(botón);
pila vertical). Y_AXIS para un
[Link](botónDos);
[Link]().add([Link], panel);
[Link](250,200);
[Link] (verdadero);
}

Observe cómo el panel vuelve a ser más estrecho, porque


no es necesario que ambos botones quepan horizontalmente.

Entonces el panel le dijo al marco que necesitaba suficiente

espacio solo para el más grande.


Botón, "Dame una descarga eléctrica".

usted está aquí 411


Machine Translated by Google

administradores de diseño

no existen
Preguntas tontas
PUNTOS DE VIÑETA

Los administradores de diseño controlan el tamaño y la ubicación


de los componentes anidados dentro de otros componentes.

Cuando agrega un componente a otro componente (a veces


denominado componente de fondo , pero eso no es una distinción
técnica), el administrador de diseño del componente de fondo
controla el componente agregado .

Un administrador de diseño pregunta a los componentes


cuál es su tamaño preferido antes de tomar una decisión sobre
el diseño. Dependiendo de las políticas del administrador de
diseño, es posible que respete todos, algunos o ninguno de los
deseos del componente.
[Link](miPanel);
El administrador BorderLayout le permite
agregar un componente a una de cinco regiones. Debe
especificar la región cuando agrega el componente,
utilizando la
siguiente sintaxis: add([Link], panel);
Con BorderLayout, los componentes del norte y del sur obtienen
su altura preferida, pero no su ancho.
Los componentes del este y del oeste obtienen su ancho preferido,
pero no su altura. El componente en el centro recibe lo que sobra
(a menos que uses pack()).

El método pack() es como un envoltorio retráctil para los


componentes; utiliza el tamaño completo preferido del
componente central, luego determina el tamaño del marco usando
el centro como punto de partida, construyendo el resto en función
de lo que hay en las otras regiones.

FlowLayout coloca los componentes de izquierda a derecha, de


arriba a abajo, en el orden en que se agregaron, y los ajusta a una
nueva línea de componentes solo cuando los componentes no
encajan horizontalmente.

FlowLayout proporciona a los componentes su tamaño preferido


en ambas dimensiones.

BoxLayout le permite alinear componentes apilados


verticalmente, incluso si pudieran caber uno al lado del otro. Al
igual que FlowLayout, BoxLayout utiliza el tamaño preferido del
componente en ambas dimensiones.

BorderLayout es el administrador de diseño predeterminado para

un marco; FlowLayout es el valor predeterminado para un panel.

establecer diseño (nulo) Si desea que un panel use algo más que flujo, debe llamar a
setLayout() en el panel.

412 capítulo 13
Machine Translated by Google

usando columpio

Jugar con componentes de swing

JTextField

JTextField
JLabel

20 significa 20 columnas, no 20 píxeles.


Constructores Esto define el ancho preferido de
el campo de texto.
Campo JTextField = nuevo JTextField(20);

Campo JTextField = nuevo JTextField ("Su nombre");

Cómo usarlo

1 Sacar texto de él
[Link]([Link]());

2 Ponle texto

[Link](“lo que sea”);


[Link](““); Esto despeja el campo

3 Obtener un ActionEvent cuando el usuario


También puedes registrarte para eventos clave si
presiona regresar o ingresar realmente quieres enterarte de ello cada tiempo el
El usuario presiona una tecla.

[Link](myActionListener);

4 Seleccione/resalte el texto en el campo


[Link]();

5 Vuelva a colocar el cursor en el campo (para que el usuario


pueda comenzar a escribir)

[Link]();

estás aquí 413


Machine Translated by Google

área de texto

JTextArea

A diferencia de JTextField, JTextArea puede tener más de una línea de texto. Se


necesita un poco de configuración para crear uno, porque no viene de fábrica con
barras de desplazamiento ni ajuste de líneas. Para hacer un desplazamiento JTextArea,
debes pegarlo en un ScrollPane. Un ScrollPane es un objeto al que realmente le encanta
desplazarse y se encargará de las necesidades de desplazamiento del área de texto.
10 significa 10 líneas (establece la altura preferida)
20 significa 20 columnas (establece el ancho preferido)
Constructor
Texto JTextArea = nuevo JTextArea(10,20);

Cómo usarlo
Cree un JScrollPane y asígnele el
área de texto por la que se desplazará.
1 Haz que tenga solo una barra de desplazamiento vertical.

Desplazador JScrollPane = nuevo JScrollPane (texto);


Dígale al panel de desplazamiento que use solo
[Link](verdadero); una barra de desplazamiento vertical
Activar ajuste de línea

[Link](ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
[Link](ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

[Link](desplazador);
¡¡Importante!! Le asigna el área de texto al panel de desplazamiento (a través del
constructor
al panel. ¡Nodel panel de
agregas desplazamiento)
el área y luego agrega
de texto directamente el panel de desplazamiento
al panel!
2 Reemplazar el texto que contiene.

[Link](“No todos los que se pierden están errantes”);

3 Agregar al texto que contiene.

[Link](“botón hecho clic”);

4 Seleccione/resalte el texto en el campo

[Link]();

5 Vuelva a colocar el cursor en el campo (para que el usuario


pueda comenzar a escribir)

[Link]();

414 capítulo 13
Machine Translated by Google

usando columpio

Ejemplo de JTextArea

importar [Link].*; importar


[Link].*; importar
[Link].*;

la clase pública TextArea1 implementa ActionListener {

Texto del área JText;

público estático vacío principal (String[] args) {


TextArea1 interfaz gráfica de usuario = nueva
TextArea1(); [Link]();
}

public void go() { marco


JFrame = nuevo JFrame(); Panel JPanel =
nuevo JPanel(); Botón JButton = nuevo
JButton ("Simplemente haga clic en él"); botó[Link](esto);
texto = nuevo JTextArea(10,20);
[Link](verdadero);

Desplazador JScrollPane = nuevo JScrollPane (texto);


[Link](ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
[Link](ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

[Link](desplazador);

[Link]().add([Link], panel);
[Link]().add([Link], botón);

[Link](350,300);
[Link] (verdadero);
}

public void actionPerformed(ActionEvent ev) { [Link](“botón hecho


clic \n ”);
}
}
Inserte una nueva línea para que las palabras
vayan en una línea separada cada vez que se
haga clic en el botón. De lo contrario, correrán juntos.

estás aquí 415


Machine Translated by Google

casilla de verificación

no existen
Preguntas tontas
JCheckBox

Constructor
JCheckBox check = new JCheckBox(“Va a 11”);

Cómo usarlo

1 Escuche un evento de elemento (cuando está seleccionado o deseleccionado)

[Link](esto);

2 Manejar el evento (y averiguar si está seleccionado o no)

itemStateChanged público vacío (ItemEvent ev) {


Cadena onOrOff = “apagado”; if
([Link]()) onOrOff = “activado”; [Link]
("La casilla de verificación es" + encendidoOApagado);

3 Seleccionarlo o deseleccionarlo en el código.

[Link](verdadero);
[Link](falso);

416 capítulo 13
Machine Translated by Google

usando columpio

Lista J

El constructor JList toma una matriz de cualquier tipo de


objeto. No es necesario que sean cadenas, pero
aparecerá una representación de cadena en la lista.
Constructor
Cadena [] listEntries = {“alfa”, “beta”, “gamma”, “delta”,
“épsilon”, “zeta”, “eta”, “theta”};

lista = nueva JList(listaEntries);

Cómo usarlo Esto es como con JTextArea: crea un


JScrollPane (y le da la lista), luego agrega el
1 Haz que tenga una barra de desplazamiento vertical.
panel de desplazamiento (NO la lista) al panel.
Desplazador JScrollPane = nuevo JScrollPane (lista);
[Link](ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
[Link](ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

[Link](desplazador);

2 Establecer el número de líneas que se mostrarán antes de desplazarse

[Link](4);

3 Restringir al usuario a seleccionar solo UNA cosa a la vez

[Link](ListSelectionModel.SINGLE_SELECTION);

4 Regístrese para eventos de selección de lista

[Link](este);

Obtendrás el evento DOS VECES si no

5 realizas esta prueba if.


Manejar eventos (descubra qué elemento de la lista se seleccionó) public void
valueChanged(ListSelectionEvent lse) {
si(![Link]()) {
Selección de cadena = (Cadena) [Link](); [Link](selección);
getSelectedValue() en realidad
devuelve un objeto. Una lista no
}
} se limita únicamente a objetos String.

estás aquí 417


Machine Translated by Google

Código Cocina

418 capítulo 13
Machine Translated by Google

usando columpio

Hacer el BeatBox

1 Cree una GUI que tenga 256 casillas de verificación (JCheckBox) que comienzan
sin marcar, 16 etiquetas (JLabel) para los nombres de los instrumentos y cuatro
botones.

2 Registre un ActionListener para cada uno de los cuatro botones. No necesitamos


oyentes para las casillas de verificación individuales, porque no estamos
intentando cambiar el patrón de sonido dinámicamente (es decir, tan pronto como
el usuario marca una casilla). En cambio, esperamos hasta que el usuario
presione el botón "iniciar" y luego recorremos las 256 casillas de verificación para
obtener su estado y crear una pista MIDI.

3 Configure el sistema MIDI (ya lo ha hecho antes), incluida la obtención de un


secuenciador, la creación de una secuencia y la creación de una pista. Estamos
utilizando un método de secuenciador que es nuevo en Java 5.0, setLoopCount().
Este método le permite especificar cuántas veces desea que se repita una
secuencia. También utilizamos el factor de tempo de la secuencia para ajustar el
tempo hacia arriba o hacia abajo y mantener el nuevo tempo de una iteración del
bucle a la siguiente.

4 Cuando el usuario presiona "iniciar", comienza la acción real. El método de manejo


de eventos para el botón 'inicio' llama al método buildTrackAndStart().
En ese método, recorremos las 256 casillas de verificación (una fila a la vez,
un solo instrumento en los 16 tiempos) para obtener su estado, luego usamos la
información para crear una pista MIDI (usando el práctico método makeEvent()
que usamos en el capítulo anterior). Una vez creada la pista, iniciamos el secuenciador,
que continúa reproduciéndose (porque lo estamos haciendo en bucle) hasta que
el usuario presiona "detener".

estás aquí 419


Machine Translated by Google

Código BeatBox

importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;

BeatBox de clase pública {

Panel principal de JPanel; Almacenamos las casillas de verificación en un ArrayList


ArrayList<JCheckBox> lista de casillas de verificación;
Secuenciador secuenciador;
Secuencia de secuencia;
Seguimiento de seguimiento;

JFrame el Marco; Estos son los nombres de los instrumentos, como una matriz de
cadenas, para construir las etiquetas de la GUI (en cada fila)
String[] nombres de instrumentos = {“Bambo”, “Charles cerrado”,
“Abrir charles”, “caja acústica”, “platillo crash”, “palmada”,
“High Tom”, “Hola Bongo”, “Maracas”, “Silbato”, “Conga Baja”,
“Cowbell”, “Vibraslap”, “Tom medio bajo”, “Agogo alto”,
“Abre Hola Conga”};
int[] instrumentos = {35,42,46,38,49,39,50,60,70,72,64,56,58,47,67,63};

Estos representan las "teclas" reales del tambor.


público estático vacío principal (String[] args) {
El canal de batería es como un piano, excepto
nuevo BeatBox2().buildGUI(); que cada "tecla" del piano es un tambor diferente.
}
Entonces, el número '35' es la clave para el bombo,
42 es el charles cerrado, etc.
buildGUI pública vacía() {
theFrame = nuevo JFrame(“Cyber BeatBox”);
[Link](JFrame.EXIT_ON_CLOSE);
Diseño BorderLayout = nuevo BorderLayout();
Fondo de JPanel = nuevo JPanel (diseño);
[Link]([Link](10,10,10,10));

checkboxList = nueva ArrayList<JCheckBox>();


Botón de cuadroBox = new Box(BoxLayout.Y_AXIS); Un 'borde vacío' nos da un margen entre
los bordes del panel y donde se colocan
Inicio de JButton = nuevo JButton(“Inicio”); los componentes.
Puramente estético.
[Link](new MyStartListener());
[Link](inicio);

Detener JButton = nuevo JButton(“Detener”);


[Link](new MyStopListener());
[Link](detener); No hay nada especial aquí, solo mucho
código GUI. Ya has visto la mayor parte antes.
JButton upTempo = new JButton(“Tempo arriba”);
[Link](new MyUpTempoListener());
[Link](upTempo);

JButton downTempo = new JButton(“Tempo abajo”);

420 capítulo 13
Machine Translated by Google

usando columpio

[Link](new MyDownTempoListener()); [Link](downTempo);

Nombre del cuadroBox = new Box(BoxLayout.Y_AXIS); para


(int i = 0; i < 16; i++) {
[Link](new Label(nombresdeinstrumentos[i]));
}
Aún más código de configuración de GUI.
[Link]([Link], buttonBox);
Nada destacable.
[Link]([Link], nameBox);

[Link]().add(fondo);

Cuadrícula GridLayout = new GridLayout(16,16); [Link](1);


[Link](2); panel
principal = nuevo
JPanel(cuadrícula);
[Link]([Link], panel principal);

para (int i = 0; i < 256; i++) {


JCheckBox c = nuevo JCheckBox();
[Link](falso); casilla de
verificació[Link](c); panel
Marque las casillas de verificación,
[Link](c); } // finalizar
configúrelas en 'falso' (para que no
bucle
estén marcadas) y agréguelas a
ArrayList Y al panel GUI.
configurarMidi();

[Link](50,50,300,300); [Link]();
[Link]
(verdadero); } // cerrar método

public void setUpMidi() { intentar

{ secuenciador = [Link](); Lo habitual de configuración MIDI


[Link](); para obtener el secuenciador, la
secuencia = nueva Secuencia([Link],4); pista = secuencia y la pista. De nuevo, nada especial.
[Link]();
[Link](120);

} catch(Exception e) {[Link]();} } // cerrar método

usted está aquí 421


Machine Translated by Google

Código BeatBox

¡Aquí es donde todo sucede! Donde


convertimos el estado de la casilla de verificación
Crearemos una matriz de 16 elementos para contener los
en eventos MIDI y los agregamos a la pista. valores de un instrumento en los 16 tiempos. Si se supone
que el instrumento debe tocar en ese tiempo, el valor en ese
public void buildTrackAndStart() { elemento será la clave. Si se supone que ese instrumento
int[] lista de pistas = nulo; NO debe tocar en ese ritmo, pon un cero.

[Link](pista);
deshazte de la pista vieja, haz una nueva.
pista = [Link]();

Haga esto para cada una de las 16 FILAS (es decir, Bass, Congo, etc.)
para (int i = 0; i < 16; i++) {
lista de pistas = nuevo int[16];
Establezca la 'clave'. que representa qué instrumento es (bajo,
charles, etc. La matriz de instrumentos contiene los números MIDI
clave int = instrumentos[i]; reales para cada instrumento).

para (int j = 0; j < 16; j++) { Haga esto para cada uno de los BEATS de esta fila.

JCheckBox jc = (JCheckBox) [Link](j + (16*i));


si ([Link]()) {
trackList[j] = clave;
¿Está seleccionada la casilla de verificación en este ritmo? En
} demás {
caso afirmativo, coloque el valor clave en esta ranura de la matriz
lista de pistas[j] = 0;
} (la ranura que representa este ritmo). De lo contrario, se supone
que el instrumento NO debe tocar en este ritmo, así que ajústelo a cero.
} // cerrar bucle interno

makeTracks(lista de pistas); Para este instrumento y para los 16


[Link](makeEvent(176,1,127,0,16)); } // cerrar exterior tiempos, cree eventos y agréguelos a la pista.

Siempre queremos asegurarnos de que HAY un evento en el tiempo


[Link](makeEvent(192,9,1,0,15)); intentar { 16 (va del 0 al 15). De lo contrario, es posible que el BeatBox no
alcance los 16 tiempos completos antes de comenzar de nuevo.

[Link](secuencia);
[Link](secuenciador.LOOP_CONTINUOUSLY); Especifiquemos el número de
[Link](); iteraciones del bucle o, en
[Link](120); este caso, bucles continuos.
} captura (Excepción e) {[Link]();}
} // cerrar el método buildTrackAndStart
¡¡AHORA JUEGA LA COSA!!

clase pública MyStartListener implementa ActionListener {


acción vacía pública realizada (ActionEvent a) {
buildTrackAndStart(); Primera de las clases
} internas, oyentes de los botones.
} // cerrar clase interna Nada especial aquí.

422 capítulo 13
Machine Translated by Google

usando columpio

clase pública MyStopListener implementa ActionListener {


acción vacía pública realizada (ActionEvent a) {
[Link]();
}
} // cerrar clase interna
Los otros oyentes de
clase pública MyUpTempoListener implementa ActionListener { clase interna para los botones.
acción vacía pública realizada (ActionEvent a) {
float tempoFactor = [Link]();
[Link]((float)(tempoFactor * 1.03));
}
} // cerrar clase interna
El Tempo Factor escala el tempo
clase pública MyDownTempoListener implementa ActionListener { del secuenciador según el
acción vacía pública realizada (ActionEvent a) { factor proporcionado. El valor
float tempoFactor = [Link](); predeterminado es 1.0, por
[Link]((float)(tempoFactor * .97)); lo que estamos ajustando
} +/­ 3% por clic.
} // cerrar clase interna

Esto crea eventos para un instrumento a la vez, para


los 16 tiempos. Por lo tanto, podría obtener un int[ ]
makeTracks público vacío (lista int []) { para el bombo, y cada índice en la matriz contendrá
la clave de ese instrumento o un cero. Si es un cero, se
para (int i = 0; i < 16; i++) { supone que el instrumento no debe tocar en ese ritmo.
clave int = lista[i]; De lo contrario, cree un evento y agréguelo a la pista.

si (clave! = 0) {
[Link](makeEvent(144,9,clave, 100, i)); Realice los eventos
[Link](makeEvent(128,9,clave, 100, i+1)); NOTA ON y NOT
} OFF y agréguelos a la pista.
}
}

public MidiEvent makeEvent(int comd, int chan, int uno, int dos, int tick) {
Evento MidiEvent = nulo;
intentar {
Mensaje Corto a = nuevo Mensaje Corto();
[Link](comd, chan, uno, dos);
evento = nuevo MidiEvent(a, marca);
Este es el método de utilidad del último
capítulos
CodeKitchen. Nada nuevo.
} catch(Excepción e) {[Link](); }
evento de regreso;
}

} // cerrar clase

estás aquí 423


Machine Translated by Google

ejercicio: ¿Qué diseño?

¿Qué código va con


qué diseño?
Cinco de las seis pantallas siguientes se hicieron a partir de una

de los fragmentos de código en la página opuesta. Haga coincidir


cada uno de los cinco fragmentos de código con el diseño que
produciría ese fragmento.

3 5

2 ? 4

424 capítulo 13
Machine Translated by Google

usando columpio

Fragmentos de código

Marco JFrame = nuevo JFrame(); Panel


D JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”);
[Link]().add([Link],panel);
[Link](botónDos);
[Link]().add([Link],botón);

Marco JFrame = nuevo JFrame(); Panel


B JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”); [Link](botónDos);

[Link]().add([Link],botón);
[Link]().add([Link], panel);

C Marco JFrame = nuevo JFrame(); Panel


JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”);
[Link](botónDos);
[Link]().add([Link],botón);

Marco JFrame = nuevo JFrame(); Panel


A
JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”);
panel.añadir(botón);
[Link]().add([Link],buttonTwo);
[Link]().add([Link], panel);

Marco JFrame = nuevo JFrame(); Panel


mi
JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”);
[Link]().add([Link],panel);
[Link](botónDos);
[Link]().add([Link],botón);

estás aquí 425


Machine Translated by Google

rompecabezas: crucigrama

GUI­Cross 7.0

426 capítulo 13
Machine Translated by Google

usando columpio

Soluciones de ejercicio

Marco JFrame = nuevo JFrame(); Panel


1 C JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”);
[Link](botónDos);
[Link]().add([Link],botón);

Marco JFrame = nuevo JFrame(); Panel


2 D JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”);
[Link]().add([Link],panel);
[Link](botónDos);
[Link]().add([Link],botón);

Marco JFrame = nuevo JFrame(); Panel


3 mi JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”);
[Link]().add([Link],panel);
[Link](botónDos);
[Link]().add([Link],botón);

Marco JFrame = nuevo JFrame(); Panel


4 A JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”);
panel.añadir(botón);
[Link]().add([Link],buttonTwo);
[Link]().add([Link], panel);

Marco JFrame = nuevo JFrame(); Panel


6 B JPanel = nuevo JPanel();
[Link]([Link]); Botón JButton =
nuevo JButton(“tesuji”);
Botón JButtonDos = nuevo JButton(“watari”); [Link](botónDos);

[Link]().add([Link],botón);
[Link]().add([Link], panel);

estás aquí 427


Machine Translated by Google

respuestas del rompecabezas

Respuestas de rompecabezas

GUI­Cross 7.0

PANEL DE DISEÑO S
W. CENTRO
METAL t G.W.
S mi OYENTE I
EVENTO AI OADD
t Ud. PAG YZ juego de rol
VCFLOWOE EL
ISAR l Ud. GOLPEAR
ESLANIMACIÓN C
I LMCC Ud. PAG

BBEYTEXTAREA A
LA I mi QN
ECHECKBOXR Ud. mi

KA norte ETIQUETA
S
ACCIÓN ESCUCHADOR

428 capítulo 13
Machine Translated by Google

14 serialización y E/S de archivos

Guardar objetos Si tengo que leer un

archivo más lleno de datos,

creo que tendré que matarlo. Él puedo guardar


sabe objetos enteros, pero ¿me deja?
NO , eso sería
demasiado fácil. Bueno, veremos cómo
él siente después de que yo...

Los objetos se pueden aplanar e inflar.

este es un nuevo capitulo 429


Machine Translated by Google

guardar objetos

Captura el ritmo

Si sus datos serán utilizados únicamente por el


programa Java que los generó:

1 Usar serialización
Escriba un archivo que contenga objetos aplanados
(serializados). Luego haga que su programa lea los
objetos serializados del archivo y los infle nuevamente para
convertirlos en objetos vivos, que respiran y que habitan en el montón.

Si sus datos serán utilizados por otro programas:

2 Escribir un archivo de texto plano

Escriba un archivo con delimitadores que otros programas puedan analizar.

Por ejemplo, un archivo delimitado por tabulaciones que puede utilizar una hoja

de cálculo o una aplicación de base de datos.

430 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Estado de ahorro

Personaje del juego

poder interno

Tipo de cadena

Arma[] armas

obtener arma()
usar arma()
potencia: 50
aumentar potencia()
1 Opcion uno // más tipo: elfo

Escriba los tres objetos de armas: arco,


espada, polvo
caracteres serializados en un archivo.
Cree un archivo y escriba tres objetos de oh bj miCt
potencia: 200
caracteres serializados. El archivo no tendrá
sentido si intentas leerlo como texto:
tipo: troll
armas: manos
Ì srGameCharacter
desnudas, hacha grande
%gê8MÛIpowerLjava/lang/
String;[arma[Ljava/lang/
Cadena;xp2tlfur[[Link];≠“VÁ
oh bj miCt potencia: 120
È{Gxptbowtswordtdustsq~»tTrolluq~tb
tipo: mago
son manos grandes axsq~xtMagicianuq~tspe
armas: hechizos,
invisibilidad
invisibilidad

2 Opción dos oh bj miCt


Escribir un archivo de texto plano

Crea un archivo y escribe tres líneas de texto, una por carácter, El archivo serializado es mucho más difícil de leer para los

separando las partes de estado con comas:


humanos, pero es mucho más fácil (y más seguro) para a
su programa restaurar los tres objetos desde la serialización que
leyendo los valores de las variables del objeto que se guardaron
50, elfo, arco, espada, polvo. en un archivo de texto. Por ejemplo, imagine todas las formas en
200, Troll, manos desnudas, hacha grande
las que accidentalmente podría leer los valores en el orden
120,mago,hechizos,invisibilidad incorrecto. El tipo podría convertirse en en
"polvo" en lugar de
"Elfo", mientras que el Elfo se convierte un arma...

usted está aquí 431


Machine Translated by Google

guardar objetos

Escribir un objeto serializado en un archivo

Si el archivo “[Link]” no existe, se


creará automáticamente.

1 Crear un FileOutputStream
FileOutputStream fileStream = new FileOutputStream(“[Link]”);

Hacer una

Objeto FileOutputStream.
sabe cómo conectarse
Flujo de salida de archivos
(y crear) un archivo.

2 Crear un ObjectOutputStream
ObjectOutputStream os = nuevo ObjectOutputStream(fileStream);

ObjectOutputStream le permite escribir objetos, pero


no puede conectarse directamente a un archivo.
Necesita ser alimentado con un "ayudante". En
realidad, esto se llama "encadenar" una corriente a otra.

3 Escribe el objeto
serializa los objetos a los que hace referencia personaje
[Link](personajeUno); Uno, personaje Dos y personaje Tres, y los escribe en
el archivo “[Link]”.
[Link](personajeDos);
[Link](personajeTres);

4 Cierre el ObjectOutputStream
[Link]();
Al cerrar la secuencia en la parte superior, se cierran
las que están debajo, por lo que FileOutputStream (y el
archivo) se cerrarán automáticamente.

432 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Los datos se mueven en flujos de un lugar a otro.


Los flujos de
conexión representan
una conexión
a un origen o

Destino destino (archivo,


socket, etc.), mientras
que los flujos en
cadena no pueden
conectarse por sí solos
y deben
Fuente encadenarse a un flujo de conexión.

destino

01101001
el objeto está aplanado (seriaizado) El objeto se escribe como bytes en
01101110
011010010110111001 01
está escrito para está encadenado a

Objeto
ObjectOutputStream (un flujo FileOutputStream (un Archivo
en cadena) flujo de conexión)
usted está aquí 433
Machine Translated by Google

objetos serializados

¿Qué le sucede realmente a un


objeto cuando se serializa?

1 objeto en el montón 2 Objeto serializado

Los objetos en el montón tienen estado: el Los objetos serializados guardan los
valor de las variables de instancia valores de las variables de instancia, de
del objeto. Estos valores hacen que modo que una instancia (objeto) idéntica
una instancia de una clase sea diferente pueda volver a la vida en el montón.
de otra instancia de la misma clase.

00100101
Objeto con dos variables de Los valores de las variables de
instancia primitivas. 01000110 instancia para ancho y alto se
guardan en el archivo “[Link]”,
00100101
01000110
Los valores son junto con un poco más de
aspirados y
información que la JVM necesita
bombeados al arroyo. para restaurar el objeto (como
[Link] cuál es su tipo de clase).
ancho altura FileOutputStream fs = nuevo FileOutputStream(“[Link]”);
ObjectOutputStream os = nuevo ObjectOutputStream(fs);
[Link](miFoo);
Cree un FileOutputStream que se conecte
Foo miFoo = nuevo Foo();
al archivo “[Link]”, luego encadene
[Link](37);
[Link](70); un ObjectOutputStream a él y dígale a
ObjectOutputStream que escriba el objeto.

434 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Pero, ¿qué ES exactamente el estado de un objeto?


¿Qué hay que salvar?

Barra cerebral
cerebro
con barra

El objeto Car tiene dos variables de


instancia que hacen referencia a
otros dos objetos.

mi Ct
i bj mi
norte
gramo
mi oh
norte

eng
llantas

Motor
Neumático [] t
t irmi C
jmi
[ ] ar ray ohb
Car bj miCt
oh

¿Qué se necesita para guardar


un objeto Car?

usted está aquí 435


Machine Translated by Google

objetos serializados

Cuando se serializa un objeto, se serializan todos los objetos a los que hace
referencia desde variables de instancia. Y todos los objetos a los que también
aquellos
se refieren los objetos están serializados. Y todos los objetos a los que se refieren
los objetos están serializados... ¡y la mejor parte es que sucede aquellos

automáticamente!

Este objeto Kennel tiene una referencia a un objeto de matriz Dog


[]. Dog [] contiene referencias a dos objetos Dog. Cada objeto Dog
contiene una referencia a un objeto String y Collar. Los objetos
String tienen una colección de caracteres y los objetos Collar tienen un int.

Cuando salvas la perrera, ¡todo esto se guarda! “Fido”

St r i t
norte
gramo bj mi C
oh

tamaño

perros

En t

nombre
Coh t
ar ohbj miC
Perro [ ]
yo
yo

columna
Cadena

kmi t
mi oh
nortenorte yo
bje C Cuello

Es necesario Doh bj miCt


gramo oh

guardar todo para


"Espiga"
restaurar el Kennel
a este estado. tonto vomitar

St r i t
norte
gramo oh bj mi C
Perro Perro

Ct
tamaño

Doh [ j mi
] ar ray ohb
gramo
En t

nombre
Coh t
ar ohbj miC
yo
yo

columna
Cadena

Cuello

Doh bj miCt
gramo oh

436 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Si desea que su clase sea serializable,


implemente Serializable

Lo que sea que vaya aquí DEBE implementar


[Link](miBox); Serializable o fallará en tiempo de ejecución.

Serializable está en el paquete [Link], por lo

importar [Link].*; que necesita importarlo. No hay métodos para implementar, pero cuando dice

public class Box implementa Serializable { "implementa Serializable", le dice a la JVM, "está bien serializar
objetos de este tipo".

ancho int privado;


altura interna privada; estos dos valores se guardarán

setWidth vacío público (int w) {


ancho = ancho;
}

conjunto vacío públicoHeight(int h) {


altura = h;
}

público estático vacío principal (String[] args) {

Caja miCaja = nueva Caja(); Conéctese a un archivo llamado "[Link]"


[Link](50); si existe. Si no es así, cree un nuevo
[Link](20); Las operaciones de E/S pueden generar excepciones.
archivo llamado “[Link]”.

intentar {
FileOutputStream fs = nuevo FileOutputStream(“[Link]”);
ObjectOutputStream os = nuevo ObjectOutputStream(fs);
[Link](miBox); Hacer una
[Link](); ObjectOutputStream
} captura (Excepción ex) { encadenado a la conexión
arroyo.
[Link]();
} Dígale que escriba el objeto.
}
}
usted está aquí 437
Machine Translated by Google

objetos serializados

La serialización es todo o nada.


¿Te imaginas lo que pasaría si
parte del estado del objeto no se
guardara correctamente? Eeewww! Eso

¡Me asusta solo pensarlo! ¿Qué


pasa si un perro regresa sin peso? O sin
orejas. O el collar vuelve a ser talla 3 en
lugar de 30. ¡Eso no se puede permitir!

O todo el

El gráfico de objetos se
serializa correctamente o la
serialización falla.

No puedes serializar un

objeto Pond si es una


importar [Link].*; instancia de Duck
Los objetos del estanque se pueden serializar. variable se niega a
clase pública Pond implementa Serializable {
ser serializado (al no
La clase Pond tiene una variable
pato pato privado = nuevo pato(); implementar Serializable).
de instancia, un Duck.

público estático vacío principal (String[] args) {


Estanque miEstanque = nuevo Estanque();
intentar {
FileOutputStream fs = nuevo FileOutputStream(“[Link]”); ObjectOutputStream os =
nuevo ObjectOutputStream(fs);

[Link](miEstanque); Cuando serializas myPond (un objeto


[Link](); Pond), su variable de instancia Duck
se serializa automáticamente.
} captura (Excepción ex) {
Cuando intentas ejecutar el estanque principal de la clase:
[Link]();
} Ventana de edición de archivos Ayuda Lamento

}
% estanque de java
}
[Link]: Pato
en [Link]([Link])
¡¡Ay!! ¡El pato no es serializable!
pato de clase pública { No implementa Serializable, por lo
// código de pato aquí que cuando intentas serializar un
} objeto Pond, falla porque la variable
de instancia de Pond's Duck no
se puede guardar.

438 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

¿Es inútil
entonces? Estoy
completamente jodido si el

idiota que escribió la clase para mi


variable de instancia se olvidó de crearla.
¿Serializable?

Marque una variable de instancia como transitoria si no se


puede (o no se debe) guardar.

transitorio

importar [Link].*;
transitorio dice: "no guarde clase Chat implementa Serializable {
esta variable durante la cadena transitoria ID actual;
serialización, simplemente omítala".

Nombre de usuario de cadena;

La variable nombre
// más código
de usuario se guardará
}
como parte del estado del
objeto durante la serialización.

usted está aquí 439


Machine Translated by Google

objetos serializados

440 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Deserialización: restaurar un objeto deserializado


serializado

Si el archivo “[Link]” no existe,


1 Crear un FileInputStream obtendrás una excepción.

FileInputStream fileStream = new FileInputStream(“[Link]”);

Hacer una

Objeto FileInputStream. Sabe cómo conectarse


a una red existente.
flujo de entrada de archivos
archivo.

2 Crear un ObjectInputStream
ObjectInputStream os = nuevo ObjectInputStream(fileStream);

ObjectInputStream le permite leer objetos, pero


no puede conectarse directamente a un archivo.
Debe estar encadenado a una secuencia de
conexión, en este caso un FileInputStream.

3 leer los objetos


Objeto uno = [Link](); Cada vez que dices readObject(), obtienes el
Objeto dos = [Link](); siguiente objeto en la secuencia. Así que los
Objeto tres = [Link](); volverás a leer en el mismo orden en que fueron
escritos. Obtendrás una gran excepción si intentas
leer más objetos de los que escribiste.

4 Lanza los objetos


GameCharacter elfo = (GameCharacter) uno;
El valor de retorno de
Troll GameCharacter = (GameCharacter) dos; readObject() es de tipo Objeto (al
Mago GameCharacter = (GameCharacter) tres; igual que con ArrayList), por lo que
debes devolverlo al tipo que
sabes que realmente es.

5 Cierre el ObjectInputStream
[Link]();
Al cerrar la secuencia en la parte superior, se cierran
las que están debajo, por lo que FileInputStream (y el
archivo) se cerrarán automáticamente.

usted está aquí 441


Machine Translated by Google

deserializar objetos

¿Qué sucede durante la deserialización?

¡Este paso generará una excepción si la JVM no


puede encontrar o cargar la clase!

la clase se encuentra y se carga, las

01101001 El objeto se lee como bytes. variables de instancia guardadas se reasignan

01101110 011010010110111001
es leído por está encadenado a
01
Objeto
FileInputStream (un ObjectInputStream (un flujo
flujo de conexión) en cadena)
Archivo

1 El objeto se lee de la secuencia.

2 La JVM determina (a través de la información almacenada


con el objeto serializado) el tipo de clase del objeto .

3 La JVM intenta encontrar y cargar el objeto.


clase del proyecto . Si la JVM no puede encontrar y/
o cargar la clase, la JVM genera una excepción y
la deserialización falla.

4 A un nuevo objeto se le asigna espacio en el montón,


¡pero el constructor del objeto serializado NO se
ejecuta! Obviamente, si el constructor se ejecutara,
restauraría el estado del objeto a su estado "nuevo"
original, y eso no es lo que queremos. Queremos que
el objeto vuelva al estado que tenía cuando se creó
por primera vez. cuando se serializó fue , no

442 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

5 Si el objeto tiene una clase no serializable en algún


lugar de su árbol de herencia, el constructor de
esa clase no serializable
se ejecutará junto con cualquier constructor
superior a ese (incluso si son serializables). Una vez
que comienza el encadenamiento del constructor, no
puedes detenerlo, lo que significa que todas las
superclases, comenzando con la primera no
serializable, reinicializarán su estado.

6 Las variables de instancia del objeto reciben los valores


del estado serializado. A las variables transitorias
se les asigna un valor nulo para referencias de
objetos y valores predeterminados (0, falso, etc.)
para primitivas.

no existen
Preguntas tontas

usted está aquí 443


Machine Translated by Google

ejemplo de serialización

Guardar y restaurar los personajes del juego.


importar [Link].*;

clase pública GameSaverTest { Haz algunos personajes...

público estático vacío principal (String [] argumentos) {


GameCharacter one = new GameCharacter(50, “Elf”, new String[] {“arco”, “espada”, “polvo”});
GameCharacter dos = new GameCharacter(200, “Troll”, new String[] {“manos desnudas”, “gran hacha”});
GameCharacter tres = new GameCharacter(120, “Mago”, new String[] {“hechizos”, “invisibilidad”});

// imagina un código que hace cosas con los caracteres que podrían cambiar sus valores de estado

intentar {

ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(“[Link]”));


[Link](uno);
[Link](dos);
[Link](tres);
[Link]();
} captura (IOException ex) {
[Link]();
}
uno = nulo; Los configuramos como nulos para que no
dos = nulo; podamos acceder a los objetos del montón.
tres = nulo;

Ahora léalos nuevamente desde el archivo...

intentar {

ObjectInputStream es = new ObjectInputStream(new FileInputStream(“[Link]”));


GameCharacter oneRestore = (GameCharacter) [Link]();
GameCharacter twoRestore = (GameCharacter) [Link]();
GameCharacter threeRestore = (GameCharacter) [Link]();
“ Comprueba si funcionó.
[Link](“Tipo de uno: + [Link]());

[Link](“Tipo de dos: + [Link]());

[Link](“Tipo de tres: } + [Link]());
catch(Exception ex) {
potencia: 50
[Link](); tipo: elfo
} armas: arco,
Ventana de edición de archivos Ayuda a resucitar
} espada, polvo
% java GameSaver potencia: 200

Duende
tipo: troll oh bj miCt
armas: manos

Troll desnudas, hacha grande


potencia: 120

Mago oh bj miCt tipo: mago


armas: hechizos,
invisibilidad

oh bj miCt
444 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

La clase GameCharacter

importar [Link].*;

clase pública GameCharacter implementa Serializable { int power;

Tipo de cadena; Esta es una clase básica solo para


Cadena[] armas; probar la serialización y no tenemos
un juego real, pero te dejaremos que
public GameCharacter(int p, String t, String[] w) { potencia = p; tipo = t;
armas = w;
experimentes con eso.

public int getPower() { devolver


potencia; }

cadena pública getType() { tipo de


retorno;
}

cadena pública getWeapons() {


Cadena lista de armas = “”;

for (int i = 0; i < [Link]; i++) { lista de armas +=


armas[i] + “ “;

} devolver lista de armas;


}
}

usted está aquí 445


Machine Translated by Google

guardar objetos

PUNTOS DE VIÑETA

Puede guardar el estado de un objeto serializándolo.

Para serializar un objeto, necesita un ObjectOutputStream (del paquete [Link])

Las transmisiones son transmisiones de conexión o transmisiones en cadena

Los flujos de conexión pueden representar una conexión a un origen o destino,


normalmente un archivo, una conexión de socket de red o la consola.

Los flujos en cadena no pueden conectarse a un origen o destino y deben

encadenarse a un flujo de conexión (u otro).

Para serializar un objeto en un archivo, cree un FileOuputStream y encadenelo en


un ObjectOutputStream.

Para serializar un objeto, llame a writeObject(theObject) en


ObjectOutputStream. No es necesario llamar a métodos en FileOutputStream.

Para ser serializado, un objeto debe implementar la interfaz Serializable.


Si una superclase de la clase implementa Serializable, la subclase será serializable
automáticamente incluso si no declara específicamente implements Serializable.

Cuando se serializa un objeto, se serializa todo su gráfico de objetos. Eso significa


que cualquier objeto al que hacen referencia las variables de instancia del objeto
serializado se serializa, y cualquier objeto al que hacen referencia esos
objetos... y así sucesivamente.

Si algún objeto en el gráfico no es serializable, se generará una excepción en


tiempo de ejecución, a menos que se omita la variable de instancia que hace
referencia al objeto.

Marque una variable de instancia con la palabra clave transitoria si desea que
la serialización omita esa variable. La variable se restaurará como nula (para
referencias de objetos) o valores predeterminados (para primitivas).

Durante la deserialización, la clase de todos los objetos del gráfico debe estar
disponible para la JVM.

Lees objetos (usando readObject()) en el orden en que fueron escritos


originalmente.

El tipo de retorno de readObject() es tipo Objeto, por lo que los objetos


deserializados deben convertirse a su tipo real.
¡Las variables estáticas no están serializadas! No tiene sentido guardar el valor

de una variable estática como parte del estado de un objeto específico, ya que
todos los objetos de ese tipo comparten un solo valor: el de la clase.

446 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Escribir una cadena en un archivo de texto

Cómo se verían los datos de los


personajes del juego si los escribieras
como un archivo de texto legible por humanos.

50, elfo, arco, espada, polvo.

200, Troll, manos desnudas, hacha grande

120,mago,hechizos,invisibilidad

Para escribir un objeto serializado:

[Link](algúnObjeto);

Para escribir una cadena:

[Link](“Mi primera cadena para guardar”);

Necesitamos el paquete [Link] para FileWriter

importar [Link].*;

clase WriteAFile {
Si el archivo "[Link]" no
público estático vacío principal (String[] args) {
existe, FileWriter lo creará.
intentar {
Escritor de FileWriter = nuevo FileWriter ("[Link]");

TODAS las cosas de E/S deben


[Link](“¡hola foo!”); El método write() toma una cadena

estar en un intento/captura. Todo puede arrojar un

¡¡IOExcepción!!
[Link]();
¡Ciérralo cuando hayas terminado!

} captura (IOException ex) {


[Link]();
}
}
}

usted está aquí 447


Machine Translated by Google

escribiendo un archivo de texto

Ejemplo de archivo de texto: e­Flashcards


frente Anticuado
índice 3x5
tarjetas didácticas

¿Cuál es el
primer país
atrás
extranjero al sur
de Detroit, Michigan?
Canadá (Ontario)

Tarjeta de prueba

Tarjeta de prueba(q, a)

pregunta
respuesta

obtenerPregunta()

obtener respuesta()

QuizCardBuilder QuizCardPlayer

Tiene un menú Archivo con la opción "Guardar" para guardar el Tiene un menú Archivo con una opción "Cargar" para cargar un

conjunto actual de tarjetas en un archivo de texto. conjunto de tarjetas desde un archivo de texto.

448 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Creador de tarjetas de prueba (esquema del código)

Crea y muestra la GUI, incluida la creación y el


registro de detectores de eventos.

clase interna

Se activa cuando el usuario presiona el botón "Siguiente


tarjeta"; significa que el usuario quiere almacenar esa
tarjeta en la lista e iniciar una nueva tarjeta.

clase interna

Se activa cuando el uso elige 'Guardar' en el menú


Menú Archivo; significa que el usuario quiere guardar
todas las tarjetas en la lista actual como un 'conjunto' (como,
Set de Mecánica
Reglas Cuántica, Trivia de Hollywood,
de Java, etc.).

clase interna

Se activa al elegir 'Nuevo' en el menú Archivo;


significa que el usuario quiere comenzar un
conjunto nuevo (por lo que limpiamos la lista
de tarjetas y las áreas de texto).

Llamado por SaveMenuListener;


hace la escritura del archivo real.

usted está aquí 449


Machine Translated by Google

Código del creador de tarjetas de prueba

importar [Link].*; importar


[Link].*; importar
[Link].*; importar
[Link].*; importar
[Link].*;

clase pública QuizCardBuilder {

pregunta privada de JTextArea;


respuesta privada de JTextArea; lista
de tarjetas privada ArrayList<QuizCard>; marco JFrame
privado;

público estático vacío principal (String[] args) {


Constructor QuizCardBuilder = nuevo QuizCardBuilder(); [Link]();

public void go() { // construir


interfaz gráfica de usuario

marco = nuevo JFrame ("Constructor de tarjetas de Esto es todo el código GUI aquí. Nada
prueba"); JPanel panel principal = nuevo especial, aunque es posible que
JPanel(); Fuente bigFont = nueva fuente ("sanserif", [Link], 24); desees consultar
MenuBar, Menu yel código de
MenuItems.
pregunta = nueva JTextArea(6,20);
[Link](verdadero);
[Link](verdadero);
[Link](bigFont);

JScrollPane qScroller = nuevo JScrollPane(pregunta);


[Link](ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
[Link](ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

respuesta = nueva JTextArea(6,20);


[Link](verdadero);
[Link](verdadero);
[Link](bigFont);

JScrollPane aScroller = nuevo JScrollPane(respuesta);


[Link](ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
[Link](ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

JButton nextButton = new JButton(“Tarjeta siguiente”);

cardList = nueva ArrayList<QuizCard>();

JLabel qLabel = new JLabel(“Pregunta:”);


JLabel aLabel = new JLabel(“Respuesta:”);

panel [Link](qLabel);
panel [Link](qScroller);
[Link](aLabel);
[Link](aScroller);
[Link](siguienteBotón);
[Link](new NextCardListener()); JMenuBar menuBar =
nuevo JMenuBar(); JMenu fileMenu = nuevo
JMenu(“Archivo”); JMenuItem nuevoMenuItem =
nuevo JMenuItem(“Nuevo”);

450 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

JMenuItem saveMenuItem = nuevo JMenuItem(“Guardar”);


[Link](nuevo NewMenuListener());
menú,
Hacemos una barra de menú, hacemos un Archivo.

[Link](new SaveMenuListener()); luego coloque el menú 'nuevo' y 'guardar' en


[Link](newMenuItem); menú
elementos en el menú Archivo. Agregamos el
[Link](saveMenuItem);
use elementos
la barra
para
de menú, luego dígale al marco que
barra de menú.add(menúarchivo); esta barra de
menú. Menú
[Link](barra de menú); disparar un
AcciónEvento
[Link]().add([Link], mainPanel);
[Link](500,600);
[Link] (verdadero);
}

la clase pública NextCardListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {

Tarjeta QuizCard = nueva QuizCard([Link](), [Link]());


[Link](tarjeta);
borrarTarjeta();
}
}

clase pública SaveMenuListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {
Tarjeta QuizCard = nueva QuizCard([Link](), [Link]());
[Link](tarjeta);
Abre un cuadro de diálogo de archivo y espera en esta
JFileChooser fileSave = nuevo JFileChooser();
línea hasta que el usuario elija "Guardar" en el
[Link](marco);
saveFile([Link]()); cuadro de diálogo. ¡JFileChooser realiza toda la
} navegación del cuadro de diálogo de archivos y la
} selección de un archivo, etc.! Realmente es así de fácil.

clase pública NewMenuListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {
[Link]();
borrarTarjeta();
}
}

El método que escribe el archivo real (llamado por el


tarjeta clara vacía privada () {
[Link](“”); controlador de eventos de SaveMenuListener).
[Link](“”); El argumento es el objeto 'Archivo' que el usuario está guardando.
[Link](); Veremos la clase Archivo en la página siguiente.
}

saveFile privado vacío (archivo de archivo) {


intentar {
Escritor BufferedWriter = nuevo BufferedWriter (nuevo FileWriter (archivo));

para (tarjeta QuizCard: lista de tarjetas) {


[Link]([Link]() + “/”); Encadenamos un BufferedWriter a un nuevo
[Link]([Link]() + “\n”); FileWriter para facilitar la escritura eficiente.
} (hablaremos de eso en unas pocas páginas).
[Link]();

} captura (IOException ex) { Recorra el ArrayList de tarjetas


[Link](“no se pudo escribir la lista de tarjetas”); y escríbalas, una tarjeta por línea,
[Link]();
}
con la pregunta y la respuesta
} separadas por “/”, y luego agregue
} un carácter de nueva línea (“\n”)

usted está aquí 451


Machine Translated by Google

escribir archivos

La clase [Link]

Un objeto Archivo representa el nombre y


la ruta de un archivo o directorio en el
disco, por ejemplo:
/Usuarios/Kathy/Datos/[Link]
¡Pero NO representa ni le da acceso a los datos del
archivo! en

Algunas cosas que puedes hacer con un objeto Archivo:

¡Una dirección NO es lo
1 Crear un objeto Archivo que represente un mismo que la casa
archivo existente real! Un objeto Archivo
es como una dirección
Archivo f = nuevo archivo ("MiCó[Link]");
postal... representa el
nombre y la ubicación
de un archivo en particular,
2 Crea un nuevo directorio
pero no es el archivo en sí.
Directorio de archivo = nuevo archivo
("Capítulo 7"); [Link]();

Un objeto Archivo representa el

nombre de archivo "[Link]"


[Link]
3 Enumerar el contenido de un directorio
si ([Link]()) { 50, elfo, arco, espada, polvo.
Cadena[] dirContents = [Link]();
200, Troll, manos desnudas, hacha grande
para (int i = 0; i < [Link]; i++) {
[Link](dirContents[i]); 120,mago,hechizos,invisibilidad
}
}
¡Un objeto Archivo NO
representa (ni le brinda
acceso directo a) los datos
4 Obtenga la ruta absoluta de un archivo o directorio dentro del archivo!
[Link]([Link]());

5 Eliminar un archivo o directorio (devuelve verdadero


si tiene éxito)
booleano isDeleted = [Link]();
452 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

La belleza de los amortiguadores


Si no hubiera amortiguadores, sería como
comprar sin carrito. Tendrías que llevar
cada cosa al coche, una lata de sopa o un rollo
de papel higiénico a la vez.

Los amortiguadores le brindan un lugar de


almacenamiento temporal para agrupar cosas
hasta que el soporte (como el carrito) esté lleno.
Puedes hacer muchos menos viajes cuando usas un buffer.

destino

Cuando el buffer está lleno, el


La cadena se coloca en un búfer Álamo temblón

con otras cadenas. Todas las cadenas están escritas en


Denver

"Roca" "Roca" “Aspen Denver Roca”


Roca
está encadenado a
está escrito para “Denver” “Aspen”
Cadena escritor de archivos
Escritor almacenado en búfer
Archivo

(una secuencia en cadena (un flujo de conexión que


escribe caracteres en lugar
que funciona con personajes)
de bytes)

Escritor BufferedWriter = nuevo BufferedWriter (nuevo FileWriter (un archivo));


Observe que
ni siquiera
debemos mantener una referencia
al objeto FileWriter. Lo único que
nos importa es BufferedWriter, porque
ese es el objeto al que llamaremos
métodos BufferedWriter, se encargará
encendido, y cuando
cerramos el
del resto de la cadena.

usted está aquí 453


Machine Translated by Google

leyendo archivos

Lectura de un archivo de texto

Un archivo con dos líneas de texto.

¿Cuánto es 2 + 2?/4

¿Cuánto es 20+22/42?

No olvides la importación. [Link]


importar [Link].*;

clase LeerArchivo {
público estático vacío principal (String[] args) {
Un FileReader es un flujo de conexión para
intentar { caracteres, que se conecta a un archivo de texto.
Archivo miArchivo = nuevo Archivo(“[Link]”);
FileReader fileReader = nuevo FileReader(miArchivo);

Lector BufferedReader = nuevo BufferedReader(fileReader);


Encadene FileReader a
BufferedReader para una
Cree una variable de cadena para contener
lectura más eficiente. Volverá
cada línea a medida que se lee la línea.
al archivo para leer solo
cuando el búfer esté vacío (porque
Línea de cadena = nula; el programa ha leído todo lo que contiene).

mientras ((línea = [Link]()) != nulo) {


[Link](línea);
}
[Link](); Esto dice: “Lea una línea de texto y asígnela a la variable
Cadena 'línea'. Si bien esa variable no es nula (porque
} captura (Excepción ex) { HABÍA
línea algo
que parade
acaba leer), imprima el
leerse”.
[Link]();
U otra forma de
} decirlo: “Mientras todavía queden líneas por
leer, léelas e imprímelas”.
}
}

454 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Reproductor de tarjetas de prueba (esquema del código)

usted está aquí 455


Machine Translated by Google

Código del jugador de tarjetas de prueba

importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;

clase pública QuizCardPlayer {

visualización privada de JTextArea;


respuesta privada de JTextArea;
lista de tarjetas privada ArrayList<QuizCard>;
tarjeta actual QuizCard privada;
privado int currentCardIndex; Sólo código GUI en
marco JFrame privado; esta página;
nada especial
JButton privado nextButton;
booleano privado esShowAnswer;

público estático vacío principal (String[] args) {


Lector QuizCardPlayer = nuevo QuizCardPlayer();
[Link]();
}

vacío público ir () {

// construir interfaz gráfica de usuario

marco = nuevo JFrame ("Reproductor de tarjetas de prueba");


JPanel panel principal = nuevo JPanel();
Fuente bigFont = nueva fuente ("sanserif", [Link], 24);

mostrar = nueva JTextArea(10,20);


[Link](bigFont);

[Link](verdadero);
[Link](falso);

JScrollPane qScroller = nuevo JScrollPane(pantalla);


[Link](ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
[Link](ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); nextButton = new
JButton(“Mostrar pregunta”); panel [Link](qScroller);

[Link](siguienteBotón);
[Link](new NextCardListener());

JMenuBar menuBar = nuevo JMenuBar();


JMenu fileMenu = nuevo JMenu(“Archivo”);
JMenuItem loadMenuItem = new JMenuItem(“Cargar conjunto de tarjetas”);
[Link](nuevo OpenMenuListener());
[Link](loadMenuItem); barra de
menú.add(menúarchivo);
[Link](barra de menú);
[Link]().add([Link], mainPanel);
[Link](640,500);
[Link] (verdadero);

} // cerrar ir

456 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

la clase pública NextCardListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {
si (isShowAnswer) {
// muestra la respuesta porque han visto la pregunta
[Link]([Link]());
[Link](“Tarjeta siguiente”);
isShowAnswer = falso;
} demás { ver
//muestra la siguiente pregunta Verifique el indicador booleano isShowAnswer
if (currentCardIndex <[Link]()) { para saber si actualmente están viendo una
pregunta o una respuesta, y haga lo
mostrarTarjetaSiguiente();
apropiado dependiendo la de
respuesta.

} demás {
// ¡no hay más cartas!
[Link](“Esa fue la última tarjeta”);
[Link](falso);
}
}
}
}

clase pública OpenMenuListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {
JFileChooser fileOpen = nuevo JFileChooser();
[Link](marco);
loadFile([Link]());
} Abra el cuadro de diálogo del archivo y permítales
} navegar y elegir el archivo para abrir.

loadFile vacío privado (archivo de archivo) {

cardList = nueva ArrayList<QuizCard>();


intentar {
Lector BufferedReader = nuevo BufferedReader (nuevo FileReader (archivo));
Línea de cadena = nula;
mientras ((línea = [Link]()) != nulo) { Haga un BufferedReader encadenado a
hacerTarjeta(línea); un nuevo FileReader, dándole al
} FileReader el objeto Archivo que el usuario
[Link](); eligió en el cuadro de diálogo de abrir archivo.

} captura (Excepción ex) { Lea una línea a la vez, pasándola al


[Link](“no se pudo leer el archivo de la tarjeta”); método makeCard() que la analiza, la
[Link]();
} convierte en una QuizCard real y la agrega
al
// ahora es el momento de comenzar mostrando la primera tarjeta Lista de arreglo.
showNextCard();
}

tarjeta vacía privada (String lineToParse) { Cada línea de texto corresponde a una
Cadena[] resultado = [Link](“/”); única tarjeta didáctica, pero tenemos que
Tarjeta QuizCard = nueva QuizCard(resultado[0], resultado[1]);
analizar la pregunta y la respuesta como
[Link](tarjeta);
partes separadas. Usamos el método String
[Link](“hizo una tarjeta”);
}
split() para dividir la línea en dos tokens (uno
para la pregunta y otro para la respuesta).
showNextCard privado vacío () { Veremos el método split() en la página siguiente.
tarjetaactual = [Link](currentCardIndex);
currentCardIndex++;
[Link]([Link]());
[Link](“Mostrar respuesta”);
isShowAnswer = verdadero;
}
} // cerrar clase
usted está aquí 457
Machine Translated by Google

analizando cadenas con split()

Analizando con String split()


Guardado en un archivo de preguntas como este:
Imagina que tienes una tarjeta flash como esta:

¿Qué es azul + amarillo?/verde


pregunta
¿Qué es rojo + azul?/púrpura
¿Qué es azul + amarillo?
respuesta

verde

¿Cómo se separa la pregunta y la respuesta?


Cuando lee el archivo, la pregunta y la respuesta se juntan en
una línea, separadas por una barra diagonal “/” (porque así es
como escribimos el archivo en el código de QuizCardBuilder).

String split() te permite romper un String en pedazos.


El método split() dice: "dame un separador y dividiré todas las
piezas de esta cadena para ti y las colocaré en una matriz de cadenas".

ficha 1 ficha separadora 2


En la aplicación QuizCardPlayer,
así es como se ve una sola
línea cuando se lee del archivo.
String toTest = “¿Qué es azul + amarillo?/verde”;

Cadena[] resultado = [Link](“/”); El método split() toma el “/” y lo usa para dividir
la cadena en (en este caso) dos partes. (Nota:
para (token de cadena: resultado) {
split() es MUCHO más poderoso que para lo que
[Link](token); lo usamos aquí. Puede realizar un análisis
extremadamente complejo con filtros, comodines, etc.)
}
Recorra la matriz e imprima cada ficha
(pieza). En este
ejemplo, sólo hay dos
fichas: "¿Qué es azul + amarillo?" y verde".
458 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

no existen
Preguntas tontas

hazlo pegado

PUNTOS DE VIÑETA

Para escribir un archivo de texto, comience con una


secuencia de conexión FileWriter.

Encadene FileWriter a BufferedWriter para mayor

eficiencia.

Un objeto Archivo representa un archivo en una ruta


particular, pero no representa el contenido
real del archivo.

Con un objeto Archivo puede crear, recorrer y


eliminar directorios.

La mayoría de las transmisiones que pueden usar un nombre de

archivo String también pueden usar un objeto File, y un objeto File


puede ser más seguro de usar.

Para leer un archivo de texto, comience con una


secuencia de conexión FileReader.

Encadene FileReader a BufferedReader para mayor

eficiencia.

Para analizar un archivo de texto, debe asegurarse


de que el archivo esté escrito de alguna manera para
reconocer los diferentes elementos. Un enfoque
común es utilizar algún tipo de carácter para
separar las piezas individuales.

Utilice el método String split() para dividir un String


en tokens individuales. Una Cadena con un
separador tendrá dos tokens, uno a cada lado del
separador. El separador no cuenta como token.

usted está aquí 459


Machine Translated by Google

guardar objetos

ID de versión: un gran problema de serialización


1 Escribes una clase para perros
101101
101101
10101000010
1010 10 0
ID de versión de clase
01010 1
1010101

¡El control de versiones es crucial! 10101010 #343


1001010101

clase de perro

2 Serializas un objeto Perro


usando esa clase

D oh gramo b j mi C t
oh

Doh bj miCt gramo oh


El objeto
está estampado
Cambios en una clase que pueden perjudicar la deserialización: con la versión #343.

3 Cambias la clase de Perro


101101
101101
101000010 ID de versión de clase
1010 10 0
01010 1
100001 1010
0 00110101 #728
1 0 1 10 10

clase de perro

4 Deserializas un objeto Perro


usando la clase modificada
Cambios en una clase que normalmente están bien: 101101
101101
101000010
D b j mi C t
oh gramo oh
1010 10 0
01010 1
100001 1010 0
00110101
1 0 1 10 10
El objeto
clase de perro
está estampado
con la versión #343.
la versión de clase
es #728

5 ¡¡ La serailización falla!!
La JVM dice: "no se puede
enseñar código nuevo a un perro viejo".

460 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Usando el serialVersionUID

Cuando crees que tu clase podría


evolucionar después de que alguien
haya serializado objetos de ella...

1 Utilice la herramienta de línea de comandos


serialver para obtener el ID de versión de su clase
Si cree que existe CUALQUIER posibilidad de que
su clase coloque una evolucionar,
ID de versión en serie en su clase. Ventana de edición de archivos Ayuda serialKiller

% número de serie Perro


Perro: serialVersionUID largo final estático =
­
5849794470654667210L;

2 Pega el resultado en tu clase

perro de clase pública {

serialVersionUID largo final estático =


­6849794470754667710L;

nombre de cadena privada;


tamaño int privado;

// código del método aquí


}

3 ¡ Asegúrese de que cuando realice cambios en


la clase, asuma la responsabilidad en su código
por las consecuencias de los cambios que realizó
en la clase! Por ejemplo, asegúrese de que su
Ventana de edición de archivos Ayuda serialKiller nueva clase Dog pueda manejar la deseriaización
de un Dog antiguo con valores predeterminados,
% número de serie Perro por ejemplo, variables agregadas a la clase.
Perro: serialVersionUID largo final estático = después El Perro fue serializado.

­
5849794470654667210L;

usted está aquí 461


Machine Translated by Google

Código Cocina

Cuando haces clic en "serializeIt", el


patrón actual
ser salvado.

“restaurar” vuelve a cargar el


patrón guardado y restablece las
casillas de verificación.

462 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Guardar un patrón BeatBox

Serializando un patrón

Esta es una clase interna


dentro del código BeatBox.

la clase pública MySendListener implementa ActionListener {


Todo sucede cuando el usuario hace
clic en el botón y se activa ActionEvent.
acción vacía pública realizada (ActionEvent a) {

boolean[] checkboxState = nuevo booleano[256];


Cree una matriz booleana para contener el
estado de cada casilla de verificación.
para (int i = 0; i < 256; i++) {

JCheckBox comprobar = (JCheckBox) [Link](i);


Recorra checkboxList (ArrayList de casillas
si ([Link]()) {
de verificación), obtenga el estado de cada
estado de casilla de verificación [i] = verdadero;
una y agréguelo a la matriz booleana.
}
}

intentar {
FileOutputStream fileStream = nuevo FileOutputStream (nuevo archivo ("[Link]"));
ObjectOutputStream os = nuevo ObjectOutputStream(fileStream);
[Link] (estado de casilla de verificación);
} captura (Excepción ex) { Esta parte es pan comido. ¡Simplemente
[Link](); escriba/serialice la matriz
booleana!
}

} // cerrar método
} // cerrar clase interna

usted está aquí 463


Machine Translated by Google

deserializar el patrón

Restaurar un patrón BeatBox

Restaurando un patrón
Esta es otra clase interna
dentro de la clase BeatBox.

clase pública MyReadInListener implementa ActionListener {

acción vacía pública realizada (ActionEvent a) {


booleano[] estado de casilla de verificación = nulo;
intentar {
FileInputStream fileIn = nuevo FileInputStream(nuevo archivo(“[Link]”));
ObjectInputStream es = nuevo ObjectInputStream(fileIn);
checkboxState = (boolean[]) [Link](); Lea el único objeto en el archivo (la matriz
booleana) y conviértalo nuevamente en
} catch(Excepción ex) {[Link]();} una matriz booleana (recuerde, readObject()
devuelve una referencia de tipo Objeto.

para (int i = 0; i < 256; i++) {


JCheckBox comprobar = (JCheckBox) [Link](i);
si (checkboxState[i]) {
[Link](verdadero); Ahora restaure el estado de cada una de
} demás { las casillas de verificación en ArrayList de
[Link](falso); objetos JCheckBox reales (checkboxList).
}
}

[Link]();
Ahora detenga lo que se esté reproduciendo
buildTrackAndStart();
actualmente y reconstruya la secuencia usando
el nuevo estado de las casillas de verificación en ArrayList.
} // cerrar método
} // cerrar clase interna

Afila tu lápiz

464 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Afila tu lápiz ¿Podrán salvarse?

Tipo de objeto ¿Serializable? ¿Si no, porque no?

Objeto Sí No ______________________________________

Cadena Sí No ______________________________________

Archivo Sí No ______________________________________

Fecha Sí No ______________________________________

Flujo de salida Sí No ______________________________________

Marco J Sí No ______________________________________

Entero Sí No ______________________________________

Sistema Sí No ______________________________________

¿Qué es legal? FileReader fileReader = nuevo FileReader();


Lector BufferedReader = nuevo BufferedReader(fileReader);
Encierra en un círculo los fragmentos

de código que se compilarían (asumiendo


FileOutputStream f = nuevo FileOutputStream (nuevo archivo ("[Link]"));
que están dentro de una clase legal).
OS ObjectOutputStream = nuevo ObjectOutputStream(f);

Lector BufferedReader = nuevo BufferedReader (nuevo FileReader (archivo));


Línea de cadena = nula;
mientras ((línea = [Link]()) != nulo) {
hacerTarjeta(línea);
}

ObjectInputStream es = new ObjectInputStream(new FileOutputStream(“[Link]”));


GameCharacter oneAgain = (GameCharacter) [Link]();

usted está aquí 465


Machine Translated by Google

ejercicio: Verdadero o Falso

466 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

clase DungeonGame implementa Serializable {


intentar {

FileOutputStream fos = nuevo


getZ corto()
FileOutputStream(“[Link]”);
{ return z;

[Link]();
[Link]();

ObjectInputStream ois = nuevo


int getX() {
ObjectInputStream(fis);
devolver x;

[Link]([Link]()+[Link]()+[Link]());

FileInputStream fis = nuevo público int x = 3;

FileInputStream(“[Link]”); transitorio largo y = 4;

privado corto z = 5;

largo getY() {
clase Prueba de mazmorra {
devolver y;

[Link]();
importar [Link].*;

[Link](d);
} captura (Excepción e) {

d = (DungeonGame) [Link]();

ObjectOutputStream oos = nuevo


Ventana de edición de archivos Ayuda Tortura

ObjectOutputStream(fos); [Link](d);
% java MazmorraPrueba 12

8
público estático vacío principal (String [] argumentos) {

Juego de mazmorra d = nuevo Juego de mazmorra();

usted está aquí 467


Machine Translated by Google

soluciones de ejercicio

FALSO

FALSO

Verdadero

FALSO

Verdadero

FALSO

FALSO

FALSO

FALSO

Verdadero

Verdadero

Verdadero

FALSO

FALSO

Verdadero

FALSO

FALSO

468 capítulo 14
Machine Translated by Google

serialización y E/S de archivos

Menos mal que


finalmente tenemos las respuestas.
Me estaba cansando un
poco de este capítulo.

importar [Link].*;

class DungeonGame implementa Serializable { public int x = 3; transitorio


largo y = 4; privado corto z
= 5; int getX() { devolver x;

} largo getY() { return


} short getZ() { return z;

}
}

clase Prueba de mazmorra {


public static void main(String [] args) { DungeonGame d = new
DungeonGame(); [Link]([Link]() + [Link]() +
[Link]()); intente { FileOutputStream fos = nuevo FileOutputStream(“[Link]”);

ObjectOutputStream oos = nuevo ObjectOutputStream(fos); [Link](d); [Link]();


FileInputStream fis = nuevo FileInputStream(“[Link]”); ObjectInputStream ois = nuevo
ObjectInputStream(fis); d =
(DungeonGame)
[Link](); [Link](); } captura (Excepción e) { [Link]();
Ventana de edición de archivos Ayuda Escape

% java MazmorraPrueba 12

}
[Link]([Link]() + [Link]() + [Link]());
}
}

usted está aquí 469


Machine Translated by Google
Machine Translated by Google

15 redes e hilos

Hacer una conexión

Conéctate con el mundo exterior.

este es un nuevo capitulo 471


Machine Translated by Google

chat de caja de ritmo

Chat Beat Box en tiempo real

prueba este... es mejor para


secuencia 8

Escriba un mensaje
skyler4: rápido y original, bueno para y presione el botón enviar
secuencia 12
para enviar su mensaje.
Y tu ritmo actual
evster2: como skyler2, pero más
Roble plegable patrón
skyler5: ¡DESEAS! demasiado alegre

Al hacer clic en un mensaje


recibido se carga el patrón que se envió.
con eso

Podrás tener conversaciones


de chat completamente
auténticas e

intelectualmente
estimulantes. Cada se envía a todos.
participantes del mensaje.
Envía tu mensaje al servidor

472 capítulo 15
Machine Translated by Google

redes e hilos

Descripción general del programa de chat ¿Por qué


estoy aquí? No
esperes que
YO responda eso.

El Cliente debe conocer Actualmente hay 3


participantes en esta
el Servidor. sesión de chat:

Cliente A Cliente A, Cliente B y


Cliente C
El Servidor debe conocer
TODOS los Clientes. ¿Por qué
estoy aquí? No
Servidor
esperes que
YO responda eso.

¿Por qué
estoy aquí? No
esperes que
YO responda eso.

Cliente B

Cliente C
Cómo funciona:
1 cliente se conecta al servidor Esperando
Servidor, me gustaría
solicitudes de clientes
conectarme al servicio de chat.

Cliente A
Servidor

Participantes:
2 El servidor realiza una Bien, estás dentro. 1. Cliente A
conexión y agrega el cliente a la
Cliente A Servidor
lista de participantes.
Servidor, me gustaría
¿Por qué estoy aquí?
No esperes que
conectarme al servicio de chat. Participantes:
YO responda

1. Cliente A
3 Otro cliente se conecta eso. Entonces, ¿por qué estoy

Bien, estás dentro. 2. Cliente B

Cliente B Servidor

¿Por qué estoy aquí?


No esperes que
YO responda
“¿Quién se llevó la lámpara Mensaje
4 El cliente A envía un mensaje al
eso. Entonces, ¿por qué estoy

de lava de mi dormitorio?” recibido


servicio de chat
Cliente A
Servidor

“¿Quién se llevó la lámpara


¿Por qué estoy aquí?
No esperes que
Mensaje
5 El servidor distribuye el
YO responda
eso. Entonces, ¿por qué estoy de lava de mi dormitorio?” distribuido a
¿Por qué estoy aquí?
todos los participantes
mensaje a TODOS los No esperes que
YO responda
eso. Entonces, ¿por qué estoy

Cliente A
participantes (incluido el remitente original) Servidor
Cliente B

usted está aquí 473


Machine Translated by Google

conexiones de enchufe

Conexión, envío y recepción

1 conectar
El cliente se conecta al servidor
estableciendo una conexión Socket .
servidor de chat
Realice una conexión de socket
en [Link],
a [Link] en el puerto 5000
puerto 5000

Cliente A Servidor

2 enviar
El cliente envía un mensaje al servidor.

Máquina
[Link](unMensaje) servidor en
[Link]

Cliente A Servidor

3 recibir
El cliente recibe un mensaje del servidor.

Servidor
Cadena s = [Link]() máquina en
[Link]

Cliente A Servidor

474 capítulo 15
Machine Translated by Google

redes e hilos

Hacer una conexión de red Socket


Para realizar una
conexión Socket,
necesita saber dos
cosas sobre el servidor:
quién es y en qué
puerto se está ejecutando.
En otras palabras,

dirección IP y número
de puerto TCP.

número de puerto TCP

Socket chatSocket = nuevo socket(“[Link]”, 5000);

dirección IP para el servidor

El servidor de chat está en Este cliente está en


[Link], puerto 5000. [Link], puerto 4242.
Conexión de enchufe
Cuando necesito hablar con él, Cuando necesito hablar con
Conexión de socket al
ahí es donde lo enviaré. puerto 5000
en de vuelta al cliente en [Link], puerto él, ahí es donde lo enviaré.
el mensaje.
el servidor
[Link]
en 4242 el mensaje.

Cliente Servidor

Una conexión Socket significa que las dos máquinas


tienen información entre sí, incluida la ubicación de la
red (dirección IP) y el puerto TCP.
usted está aquí 475
Machine Translated by Google

puertos conocidos

Un puerto TCP es solo un número.


Un número de 16 bits que identifica un Números de puertos TCP conocidos
para aplicaciones de servidor comunes
programa específico en el servidor.
Telnet SMTP
ftp

20 23 25
37 Tiempo

Servidor

443 110 80

HTTPS POP3 HTTP

Un servidor puede tener hasta 65536


aplicaciones de servidor diferentes en
ejecución, una por puerto.

Los números de
puerto TCP del 0 al 1023
están reservados para
servicios conocidos. ¡No los

utilices para tus propios


programas de servidor!*

El servidor de chat que

estamos escribiendo
usa el puerto 5000.
Simplemente elegimos un
número entre 1024 y 65535.

*Bueno, es posible que puedas usar uno de


estos, pero el administrador del sistema
donde trabajas probablemente te matará.

476 capítulo 15
Machine Translated by Google

redes e hilos

no existen
Preguntas tontas

El número de puerto es la tienda


La dirección IP es el centro comercial. específica del centro comercial.

La dirección IP es como especificar un centro

comercial en particular, digamos,

“Mercado de Flatirons”

El número de puerto es como nombrar

una tienda específica, digamos,

“Tienda de CD de Bob”

Barra cerebral
cerebro
con barra

¿Cómo se programa de
hablan servidor de chat
realmente estos dos?

Cliente Servidor

usted está aquí 477


Machine Translated by Google

leyendo desde un enchufe

Para leer datos de un Socket, use un


flujos de entrada y salida
hacia y desde las
Lector almacenado en búfer
conexiones Socket

El número de puerto, que usted


conoce porque le DIJEMOS que 5000 es
1 Realice una conexión de socket al servidor el número de puerto de nuestro servidor de chat.

Socket chatSocket = nuevo Socket(“[Link]”, 5000);

otras palabras, el
[Link]
puedo usar es la dirección IP de “localhost”, en
este código ejecuta en. Tu
esto
servidor en un cuando
único, estás probando tu cliente y
máquina independiente.
2 Haga un InputStreamReader encadenado al flujo de entrada
(conexión) de bajo nivel del Socket
Flujo InputStreamReader = nuevo InputStreamReader([Link]());

InputStreamReader es un 'puente' entre un flujo de


bytes de bajo nivel (como el que proviene del ¡Todo lo que tenemos que hacer es PEDIRle al
Socket) y un flujo de caracteres de alto nivel (como el socket un flujo de entrada! Es un flujo de conexión
BufferedReader que buscamos como nuestro principal de bajo nivel, pero simplemente lo
el flujo en cadena). encadenaremos a algo más compatible con texto.

Encadene BufferedReader al
InputStreamReader (que estaba encadenado al flujo de
3 ¡ Crea un BufferedReader y lee! conexión de bajo nivel que obtuvimos del Socket).

Lector BufferedReader = nuevo BufferedReader (flujo);


Mensaje de cadena = [Link]();

fuente
destino caracteres almacenados en buffer convertidos en personajes bytes del servidor
datos sobre el
caracteres
caracteres 011010011 servidor
almacenados en buffer encadenado a encadenado a

Lector almacenado en búfer Lector de flujo de entrada Flujo de entrada del


Cliente socket (no necesitamos
conocer la clase real) Servidor

478 capítulo 15
Machine Translated by Google

redes e hilos

Para escribir datos en un Socket, utilice un


Imprenta

Esta parte es la misma que estaba en la


página opuesta: para escribir en el
servidor, todavía tenemos que conectarnos a él.
1 Realice una conexión de socket al servidor
Socket chatSocket = nuevo Socket(“[Link]”, 5000);

2 Haga un PrintWriter encadenado al nivel bajo del Socket


(conexión) flujo de salida
Escritor PrintWriter = new PrintWriter([Link]());

PrintWriter actúa como su propio puente entre los


El Socket nos proporciona un flujo de
datos de caracteres y los bytes que obtiene del flujo de
salida de bajo nivel del Socket. Al encadenar un
conexión de bajo nivel y lo encadenamos al
PrintWriter entregándoselo al constructor PrintWriter.
PrintWriter al flujo de salida del Socket, podemos
escribir cadenas en la conexión del Socket.

3 Escribe (imprime) algo


println() agrega una nueva línea al final de lo que envía.
[Link](“mensaje a enviar”);
[Link](“otro mensaje”); print() no agrega la nueva línea.

destino
fuente
caracteres bytes al servidor
servidor de chat

"mensaje..."
011010011 programa
encadenado a

Imprenta Flujo de salida


Cliente del socket (no Servidor
necesitamos conocer la clase real)

usted está aquí 479


Machine Translated by Google

escribiendo a un cliente

El cliente de asesoramiento diario


Dígale a su jefe
¡Date un capricho
que el informe
con uno frío! Tú
tendrá que esperar. hay
¡merecerlo!
¡Polvo en Aspen!

Ese tono de

verde realmente no
te funciona...

El chico de los consejos

1 conectar
El cliente se conecta al servidor y obtiene un flujo de entrada

de él

Realice una conexión de socket servidor de

a [Link] en el puerto 4242 asesoramiento en

[Link], puerto 4242

[Link]()
Cliente Servidor

2 leer
El cliente lee un mensaje del servidor.
servidor de asesoramiento

consejo = [Link]() redacta un


consejo y lo
envía

Servidor
Cliente A

480 capítulo 15
Machine Translated by Google

redes e hilos

DailyAdviceCódigo de cliente
Este programa crea un Socket, crea un BufferedReader (con la ayuda de otras
secuencias) y lee una sola línea de la aplicación del servidor (lo que sea que
se esté ejecutando en el puerto 4242).

importar [Link].*; clase Socket está en [Link]

importar [Link].*;

clase pública DailyAdviceClient {

Realice una conexión de socket a lo que sea que se esté

vacío público ir () { ejecutando en el puerto 4242, en el mismo host en el que se

muchas cosas pueden salir mal aquí ejecuta este código. (El 'host local')
intentar {

Enchufe s = nuevo enchufe ("[Link]", 4242);

InputStreamReader streamReader = nuevo InputStreamReader([Link]());


Lector BufferedReader = nuevo BufferedReader(streamReader); encadenar un BufferedReader a un
InputStreamReader al flujo de
entrada desde el
Enchufe.

Consejo de cadena = [Link]();


este readLine() es EXACTAMENTE
[Link](“Hoy deberías: “ + consejo);
el mismo que si estuviera usando un
BufferedReader encadenado a un ARCHIVO..
llama a un
[Link](); esto cierra TODAS las transmisiones En otras palabras, cuando usted
método BufferedWriter, el

} captura (IOException ex) {


vinieron losno
El escritor
de.
sabe ni le importa de dónde
personajes.

[Link]();
}

público estático vacío principal (String [] argumentos) {

Cliente DailyAdviceClient = nuevo DailyAdviceClient();

[Link]();
}

usted está aquí 481


Machine Translated by Google

conexiones de enchufe

Afila tu lápiz

fuente

escribir/dibujar en la cadena de transmisiones que el


Cliente
cliente usa para leer desde el servidor Servidor

destino

escribir/dibujar en la cadena de transmisiones que el


Cliente cliente usa para enviar algo al servidor
Servidor

Afila tu lápiz

482 capítulo 15
Machine Translated by Google

redes e hilos

Escribiendo un servidor simple

Cómo funciona:

1 La aplicación de servidor crea un ServerSocket, en un puerto específico


ServidorSocket
ServerSocket serverSock = nuevo ServerSocket(4242);

Esto inicia la aplicación del servidor escuchando las


solicitudes de los clientes que llegan al puerto 4242. 4242

2 El cliente realiza una conexión Socket a la aplicación del servidor.


ServidorSocket
Calcetín de enchufe = nuevo enchufe ("[Link]", 4242);
Enchufe
El cliente conoce la dirección IP y el número de puerto
(publicados o proporcionados por quien configura 4242
la aplicación del servidor para que esté en ese puerto)

3 El servidor crea un nuevo socket para comunicarse con este cliente


Calcetín de enchufe = [Link]();

El método aceptar() se bloquea (simplemente permanece allí)


ServerSocket (esperando
el próximo cliente)
mientras espera una conexión de socket del cliente. Cuando un Enchufe

cliente finalmente intenta conectarse, el método devuelve un


diferente 4242
antiguo Socket (en un puerto) que sabe cómo comunicarse con
el cliente (es decir, conoce el
2789
clientela Dirección IP y número de puerto). El enchufe está encendido

un puerto diferente al de ServerSocket, para que ServerSocket


Enchufe
pueda volver a esperar a otros clientes.

usted está aquí 483


Machine Translated by Google

escribiendo un servidor

Código del servidor DailyAdvice

(Recuerde, estas cadenas fueron

importar [Link].*; recuerda las importaciones empaquetadas por el editor de


importar [Link].*; código. ¡Nunca presione
regresar en medio de una
clase pública DailyAdviceServer { cadena!)
Los consejos diarios provienen de esta matriz.

String[] counselList = {“Toma bocados más pequeños”, “Ve por los jeans ajustados. No ellos no
hacerte ver gorda”, “Una palabra: inapropiado”, “Sólo por hoy, sé honesto. Dile a tu jefe lo que *realmente* piensas”, “Quizás quieras
reconsiderar ese corte de pelo”.};

vacío público ir () {
ServerSocket hace que esta aplicación
intentar {
deelservidor
en "escuche"
puerto 4242 en el las solicitudes de los clientes
ServerSocket serverSock = nuevo ServerSocket(4242); la maquina esta
en.
código se está ejecutando
El servidor entra en un bucle permanente,
esperando (y atendiendo) las solicitudes de los clientes.
mientras (verdadero) { el método de aceptación se bloquea (simplemente permanece
allí) hasta que llega una solicitud, y luego el método devuelve un

Calcetín de enchufe = [Link](); Socket (en algún puerto anónimo) para comunicarse con el cliente

Escritor PrintWriter = nuevo PrintWriter([Link]());


Consejo de cadena = getAdvice();
[Link](consejo); ahora usamos
[Link](); la conexión de Socket al cliente para
[Link](consejo);
mensaje de [Link]
crea un PrintWriter envíale (println()) una cadena
} cerramos el Socket porque
Hemos terminado con este cliente.

} captura (IOException ex) {


[Link]();
}
} // cerrar ir

cadena privada getAdvice() {


int aleatorio = (int) ([Link]() * [Link]);
devolver lista de consejos [aleatorio];
}

público estático vacío principal (String [] argumentos) {


Servidor DailyAdviceServer = nuevo DailyAdviceServer();
[Link]();
}
}

484 capítulo 15
Machine Translated by Google

redes e hilos

PUNTOS DE VIÑETA

Las aplicaciones cliente y servidor se comunican a través de una


Barra cerebral
cerebro
con barra conexión Socket.

Un Socket representa una conexión entre dos aplicaciones que pueden


(o no) ejecutarse en dos máquinas físicas diferentes.

Un cliente debe conocer la dirección IP (o nombre de dominio) y el


número de puerto TCP de la aplicación del servidor.

Un puerto TCP es un número sin firmar de 16 bits asignado a una


aplicación de servidor específica. Los números de puerto TCP permiten
que diferentes clientes se conecten a la misma máquina pero se

comuniquen con diferentes aplicaciones que se ejecutan en esa máquina.

Los números de puerto del 0 al 1023 están reservados para


"servicios conocidos", incluidos HTTP, FTP, SMTP, etc.
no existen
Preguntas tontas Un cliente se conecta a un servidor creando un socket de servidor
Socket s = new Socket(“[Link]”, 4200);

Una vez conectado, un cliente puede obtener flujos de entrada y salida


del socket. Éstas son corrientes de "conexión" de bajo nivel.
calcetí[Link]();

Para leer datos de texto del servidor, cree un BufferedReader,


encadenado a un InputStreamReader, que está encadenado al flujo
de entrada del Socket.

InputStreamReader es una secuencia 'puente' que toma


bytes y los convierte en datos de texto (caracteres). Se utiliza
principalmente para actuar como cadena intermedia entre el
BufferedReader de alto nivel y el flujo de entrada de Socket de bajo nivel.

Para escribir datos de texto en el servidor, cree un PrintWriter


encadenado directamente al flujo de salida del Socket. Llame a
los métodos print() o println() para enviar cadenas al servidor.

Los servidores utilizan un ServerSocket que espera las solicitudes de los clientes

en un número de puerto particular.

Cuando un ServerSocket recibe una solicitud, la "acepta" estableciendo


una conexión de Socket con el cliente.

usted está aquí 485


Machine Translated by Google

un cliente de chat simple

Escribir un cliente de chat

Versión uno: solo envío

Escriba un mensaje y luego presione


'Enviar' para enviarlo al servidor. No
recibiremos ningún mensaje DEL servidor
en esta versión, por lo que no hay un
área de texto con desplazamiento.

Esquema del código

clase pública SimpleChatClientA {

JTextField saliente;
Escritor impresor;
calcetín;

vacío público ir () {
// crea una interfaz gráfica de usuario y registra un oyente con el botón enviar
// llama al método setUpNetworking()
}

private void setUpNetworking() { // crea un Socket,


luego crea un PrintWriter
// asigna el PrintWriter a la variable de instancia del escritor
}

la clase pública SendButtonListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {
// obtener el texto del campo de texto y // enviarlo al servidor
usando el escritor (un PrintWriter)
}
} // cerrar la clase interna SendButtonListener

} // cerrar clase externa

486 capítulo 15
Machine Translated by Google

redes e hilos

importar [Link].*;
importar [Link].*; importaciones para las transmisiones
importar [Link].*; ([Link]), Socket ([Link]) y la GUI
importar [Link].*; cosa
importar [Link].*;

clase pública SimpleChatClientA {

JTextField saliente;
Escritor impresor;
calcetín;

vacío público ir () {
JFrame frame = new JFrame(“Cliente de chat ridículamente simple”);
JPanel panel principal = nuevo JPanel();
saliente = nuevo JTextField(20);
cree la GUI, nada nuevo
JButton sendButton = nuevo JButton(“Enviar”);
aquí y nada relacionado
[Link](nuevo SendButtonListener()); [Link](saliente);
con redes o E/S.
[Link](enviarBotón);
[Link]().add([Link], mainPanel);
configurarRedes();
[Link](400,500);
[Link] (verdadero);
} // cerrar ir Estamos usando localhost
para que puedas probar el
setUpNetworking vacío privado() { intentar { cliente y el servidor en una máquina.

calcetín = nuevo enchufe ("[Link]", 5000); escritor = nuevo Aquí es donde creamos el Socket
PrintWriter([Link]()); [Link](“red establecida”); y el PrintWriter (se llama desde
el método go() justo antes de mostrar
} captura (IOException ex) {
la GUI de la aplicación)
[Link]();
}
} // cerrar setUpNetworking

la clase pública SendButtonListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {
intentar {
[Link]([Link]()); Ahora realmente hacemos la escritura.
[Link](); Recuerde, el escritor está encadenado
al flujo de entrada del Socket, por lo
} captura (Excepción ex) { que cada vez que hacemos println(),
[Link](); ¡va a través de la red al servidor!
}
[Link](“”);
[Link]();
}
Si desea probar esto ahora, escriba el código del
} // cerrar la clase interna SendButtonListener
servidor de chat Ready­bake que aparece al final
de este capítulo.
público estático vacío principal (String [] argumentos) {
Primero, inicie el servidor en una terminal.
nuevo SimpleChatClientA().go();
A continuación, utilice otra terminal para iniciar este
}
cliente.
} // cerrar clase externa

usted está aquí 487


Machine Translated by Google

mejorando el cliente de chat

Versión dos: enviar y recibir

El servidor envía un mensaje a todos


los clientes participantes tan pronto
como el servidor recibe el mensaje.
Cuando un cliente envía un mensaje,
no aparece en el área de
visualización de mensajes
mensajes
entrantes hasta que el servidor lo envía a todos.
entrantes

mensaje saliente

Gran pregunta: CÓMO ¿Recibes mensajes del servidor?

Pregunta más importante: CUANDO ¿Recibes mensajes del servidor?

1 Opción uno: sondear el servidor cada 20 segundos

2 Opción dos: leer algo del servidor cada vez que el usuario
envía un mensaje.

3 Opción tres: leer los mensajes tan pronto como se envían desde el servidor

488 capítulo 15
Machine Translated by Google

redes e hilos

En Java realmente PUEDES


caminar y masticar chicle
al mismo tiempo.

Subprocesos múltiples en Java

Hilo t = nuevo hilo();


Ya sabes que vamos con la opción [Link]();
tres.

usted está aquí 489


Machine Translated by Google

hilos y hilo

Java tiene varios subprocesos pero Un hilo es un "hilo de


solo una clase Thread ejecución" separado.
En otras palabras, una

pila de llamadas separada.

Un Thread es una
clase Java que
representa un thread.

Para hacer un hilo,


haz un Hilo.

hilo Hilo

[Link]() hacer más( ) Hilo


unión nula()
[Link]( ) ir( )
inicio vacío()

[Link]() hacer cosas( )


sueño vacío estático()
principal( ) correr( )

Hilo principal Otro hilo iniciado por el clase [Link]


código.

490 capítulo 15
Machine Translated by Google

redes e hilos

¿Qué significa tener más de una pila


de llamadas?

el hilo activo

1 La JVM llama al método main().


principal( )
público estático vacío principal (String [] argumentos) {
... Hilo principal
}

Se inicia un nuevo
hilo y se convierte en el
2 main() inicia un nuevo hilo. El principal hilo activo.
El hilo se congela temporalmente mientras el nuevo
[Link]()
hilo comienza a ejecutarse.
correr( )
principal( )

Ejecutable r = new MyThreadJob();


Hilo principal hilo de usuario A
Hilo t = nuevo hilo (r);
aprenderás lo que
[Link]();
esto significa en solo
Perro d = nuevo Perro(); un momento...

el hilo activo nuevamente

Perro( ) [Link]( )
3 La JVM cambia entre el nuevo
hilo (hilo de usuario A) y el hilo principal original, principal( ) correr( )
hasta que ambos hilos se completen.
Hilo principal hilo de usuario A

usted está aquí 491


Machine Translated by Google

lanzando un hilo

Cómo iniciar un nuevo hilo:

1 Crear un objeto Runnable (el trabajo del hilo)


ThreadJob ejecutable = new MyRunnable();

Runnable es una interfaz que conocerá en la página siguiente.


Escribirás una clase que implemente la interfaz Runnable y esa R C
tu mi
clase es donde definirás el trabajo que realizará un subproceso. En
ab mi ohb j
norte
norte yo

otras palabras, el método que se ejecutará desde la nueva pila


de llamadas del hilo.

2 Crea un objeto Thread (el trabajador) y dale un


Runnable (el trabajo)
Hilo miHilo = nuevo Hilo(threadJob);
t
t hrmi j mi
C
Pase el nuevo objeto Runnable al constructor Thread. ad
transmisión exterior

Esto le dice al nuevo objeto Thread qué método colocar en


la parte inferior de la nueva pila: el método run() de Runnable.

3 Iniciar el hilo
[Link]();
correr()

No sucede nada hasta que llamas al método start()


del Thread. Ahí es cuando pasas de tener solo
una instancia de Thread a tener un nuevo hilo de
C
ejecución. Cuando se inicia el nuevo hilo, toma el
t hrmi t
mi C
Rtu b jmi
ad j ab
norte
oh
método run() del objeto Runnable y lo coloca en transmisión exterior
norte
mi yo

la parte inferior de la pila del nuevo hilo.

492 capítulo 15
Machine Translated by Google

redes e hilos

Cada hilo necesita un trabajo que hacer.


Un método para colocar la nueva pila de subprocesos.

Todo lo que necesito es un trabajo de verdad.

¡Solo dame un Runnable y Runnable es para un


me pondré a trabajar!
hilo lo que un trabajo es para
un trabajador. Un Runnable

es el trabajo que se supone


que debe ejecutar un hilo.

Un Runnable contiene el

método que va al final de


la pila del nuevo hilo: run().

Hilo

La interfaz Runnable define solo un


método, public void run(). (Recuerde, es una
ejecución pública vacía() {
interfaz, por lo que el método es público
// código que será ejecutado por el nuevo hilo
} independientemente de si lo escribe de esa manera).

usted está aquí 493


Machine Translated by Google

Interfaz ejecutable

Para hacer un trabajo para su


hilo, implemente la interfaz Runnable
Runnable está en el paquete [Link],
por lo que no es necesario importarlo.

clase pública MyRunnable implementa Runnable {

ejecución pública vacía() {


ir(); Runnable tiene solo un método
} para implementar: public void run()
(sin argumentos). Aquí es donde pones
vacío público ir () { el TRABAJO que se supone que debe
2 hacer más();
ejecutar el hilo. Este es el método que va
} al final de la nueva pila.

público vacío hacerMás() {


[Link](“parte superior de la pila”);
}
}

clase ThreadTester {
Pase la nueva instancia Runnable al nuevo
constructor Thread. Esto le dice al hilo qué
público estático vacío principal (String[] args) { método poner en la parte inferior de la nueva pila.
En otras palabras, el primer método que
ThreadJob ejecutable = new MyRunnable();
se ejecutará el nuevo hilo.
Hilo miHilo = nuevo Hilo(threadJob);

1 miHilo .start();
No recibirá una nueva
[Link](“volver a principal”); llamada start() hilo de ejecución hasta que no
en la instancia de Thread. un hilo es
}
} seas realmente un hilo hasta que lo inicies. Antes de
eso, es sólo una instancia de Thread, como cualquier
otro objeto, pero no tendrá ningún "hilo" real.

2
1
hacer más( ) Barra cerebral
cerebro
con barra

[Link]()
ir( )
¿Cuál crees que será el resultado si ejecutas la clase
principal( )
correr( ) ThreadTester? (lo descubriremos en unas pocas páginas)
Hilo principal
nuevo hilo

494 capítulo 15
Machine Translated by Google

redes e hilos

Los tres estados de un nuevo hilo ¡aquí es donde un hilo


quiere estar!

Hilo t = nuevo hilo (r);

NUEVO EJECUTABLE CORRER

[Link](); Seleccionado para ejecutar

"¿Puedo

agrandar
"Estoy esperando eso para ti?"
"¡Estoy listo para irme!"
comenzar".

Hilo t = nuevo hilo (r); [Link]();

Pero hay más. Una vez que el subproceso se vuelve ejecutable,


puede avanzar y retroceder entre ejecutable, en ejecución y un estado
adicional: (también conocido como "bloqueado").
temporalmente no ejecutable

usted está aquí 495


Machine Translated by Google

estados del hilo

Bucle ejecutable/en ejecución típico

EJECUTABLE CORRER

Seleccionado para ejecutar

Enviado de nuevo a ejecutable para

que otro hilo pueda tener una

oportunidad.

Se puede hacer que un hilo no se


pueda ejecutar temporalmente
EJECUTABLE CORRER

OBSTRUIDO
Enviado a un estado temporal
no ejecutable hasta que

pueda volver a ser ejecutable.

durmiendo, esperando a que termine otro hilo,


esperando que los datos estén disponibles en la
secuencia, esperando el bloqueo de un objeto...

496 capítulo 15
Machine Translated by Google

redes e hilos

El programador de hilos

Número cuatro, ya has tenido


suficiente tiempo. Volver a ejecutable.
Número dos, ¡parece que estás despierto!

Oh, ahora parece que vas a tener que dormir.


Número cinco, ven a ocupar su lugar. Número
dos, todavía estás durmiendo...

El programador
de subprocesos toma
todas las decisiones
sobre quién se ejecuta
y quién no. Suele
hacer que los hilos se
turnen, muy bien.
Pero no hay garantía al
respecto. Podría dejar
que un hilo corra
hasta el contenido de su
corazón mientras
que los otros hilos "mueren de hambre

usted está aquí 497


Machine Translated by Google

programación de hilos

Un ejemplo de lo impredecible que puede ser el planificador...

Ejecutando este código en una máquina: Produjo esta salida:

clase pública MyRunnable implementa Runnable { Ventana de edición de archivos Ayuda PickMe

% java ThreadTestDrive
ejecución pública vacía() { ir();
de vuelta en principal
}
arriba de la pila
público vacío ir() { hacerMás(); % java ThreadTestDrive
arriba de la pila
}
de vuelta en principal
public void doMore()
% java ThreadTestDrive
{ [Link](“parte superior de la pila”);
} arriba de la pila
}
de vuelta en principal

% java ThreadTestDrive

clase ThreadTestDrive { arriba de la pila


de vuelta en principal
público estático vacío principal (String[] args) {
% java ThreadTestDrive
ThreadJob ejecutable = new MyRunnable();
arriba de la pila
Hilo miHilo = nuevo Hilo(threadJob);
de vuelta en principal
[Link]();
% java ThreadTestDrive
[Link](“volver a principal”); arriba de la pila
}
de vuelta en principal
}
Observe cómo el orden cambia % java ThreadTestDrive
aleatoriamente. A veces, el hilo nuevo
de vuelta en principal
termina primero y, a veces, el hilo
principal termina primero. arriba de la pila

498 capítulo 15
Machine Translated by Google

redes e hilos

¿Cómo terminamos con resultados diferentes?

A veces se ejecuta así:

main() inicia el nuevo El planificador envía el hilo El programador deja El nuevo hilo desaparece
hilo principal fuera de que el nuevo hilo porque se completó su

ejecución y vuelve a ser se ejecute hasta su ejecución (). El hilo principal

ejecutable, de modo que finalización, imprimiendo "top o'vuelve a ser el hilo en


el nuevo hilo puede la pila" ejecución y se imprime "de
correr. nuevo en principal".
hacer más( )

[Link]() [Link]() ir( )

principal( ) principal( ) correr( ) principal( )

Hilo principal Hilo principal nuevo hilo Hilo principal

tiempo

Y a veces funciona así:

main() inicia el nuevo El planificador envía el hilo El programador deja que el el planificador el planificador Vuelve el nuevo hilo
hilo principal fuera de nuevo hilo se ejecute por envía el nuevo selecciona el principal
al estado de ejecución e
ejecución y vuelve a ser un tiempo, no lo hilo de nuevo a hilo para ser el hilo
imprime "la parte superior
ejecutable, de modo que suficiente para que se ejecutable. en ejecución de la pila".
el nuevo hilo puede complete el método run(). nuevamente. Principal

correr. se imprime “de vuelta en principal”


hacer más( )

[Link]() ir( ) ir( ) ir( )


[Link]()
principal( ) correr( ) principal( )
principal( ) correr( ) correr( )

Hilo principal Hilo principal nuevo hilo nuevo hilo Hilo principal nuevo hilo

tiempo

usted está aquí 499


Machine Translated by Google

conexiones de enchufe

no existen
Preguntas tontas

PUNTOS DE VIÑETA

Un hilo con una 't' minúscula es un hilo de ejecución separado en


Java.

Cada hilo en Java tiene su propia pila de llamadas.

Un Thread con 'T' mayúscula es la clase [Link]. Un


objeto Thread representa un hilo de ejecución.

Un Thread necesita un trabajo que hacer. El trabajo de un


Thread es una instancia de algo que implementa la interfaz Runnable.

La interfaz Runnable tiene un solo método, ejecutar().


Este es el método que va al final de la nueva pila de llamadas. En otras
palabras, es el primer método que se ejecuta en el nuevo hilo.

Para iniciar un nuevo hilo, necesita un Runnable para pasarlo al


constructor del hilo.

Un hilo está en estado NUEVO cuando ha creado una


instancia de un objeto Thread pero aún no ha llamado a start().

Cuando inicia un hilo (llamando al método start() del objeto Thread), se


crea una nueva pila, con el método run() de Runnable en la
parte inferior de la pila.
El subproceso ahora está en estado EJECUTABLE, esperando a ser
elegido para ejecutarse.

Se dice que un hilo está EN EJECUCIÓN cuando el

programador de hilos de la JVM lo ha seleccionado como el hilo


que se está ejecutando actualmente. En una máquina con un solo
procesador, sólo puede haber un hilo en ejecución actualmente.

A veces, un subproceso se puede mover del estado EN EJECUCIÓN

a un estado BLOQUEADO (temporalmente no ejecutable).


Un subproceso puede estar bloqueado porque está esperando datos de
una secuencia, porque se ha puesto en suspensión o porque está
esperando el bloqueo de un objeto.

No se garantiza que la programación de subprocesos funcione de


ninguna manera en particular, por lo que no puede estar seguro de
que los subprocesos se turnarán correctamente. Puedes ayudar a influir
en la toma de turnos poniendo tus hilos a dormir periódicamente.

500 capitulo 15
Machine Translated by Google

redes e hilos

Poniendo un hilo a dormir

Pon tu hilo en suspensión si


quieres estar seguro de
[Link](2000);
que otros hilos tendrán la
oportunidad de ejecutarse.

Cuando el subproceso se

activa, siempre vuelve al


estado ejecutable y espera
a que el programador de
intentar {
[Link](2000); subprocesos elija que se
} captura (excepción interrumpida ex) {
[Link]();
ejecute nuevamente.
}

usted está aquí 501


Machine Translated by Google

usando [Link]()

Esto es lo que queremos: un orden coherente de


Usar el sueño para hacer que nuestro
declaraciones impresas:
programa sea más predecible. Ventana de edición de archivos Ayuda SnoozeButton

% java ThreadTestDrive
de vuelta en principal

arriba de la pila
% java ThreadTestDrive
de vuelta en principal

arriba de la pila
% java ThreadTestDrive
de vuelta en principal

arriba de la pila
% java ThreadTestDrive
de vuelta en principal

arriba de la pila

clase pública MyRunnable implementa Runnable { % java ThreadTestDrive


de vuelta en principal
ejecución pública vacía() { ir();
arriba de la pila
}

vacío público ir () { Llamar a dormir aquí obligará al nuevo hilo


a abandonar el hilo actualmente en ejecución.
prueba ¡estado!
{ [Link](2000);
El hilo principal volverá a ser el hilo
} catch(InterruptedException ex) { [Link]();
que se está ejecutando actualmente y se imprimirá
"de nuevo en principal". Luego habrá una pausa
}
(durante unos dos segundos) antes de llegar a
hacer más(); esta línea, que llama a doMore() e imprime "la
} parte superior de la pila".

público vacío hacerMás() {


[Link](“parte superior de la pila”);
}
}

clase ThreadTestDrive { public static


void main (String[] args) { Runnable theJob = new MyRunnable();
Hilo t = nuevo hilo (el trabajo); [Link]();
[Link](“volver a principal”);

}
}

502 capítulo 15
Machine Translated by Google

redes e hilos

haciendo y comenzando dos hilos

La clase pública RunThreads implementa Runnable {

público estático vacío principal (String [] argumentos) {


Cree una instancia ejecutable.
Corredor RunThreads = nuevo RunThreads();
Hilo alfa = nuevo hilo (corredor);
Hilo beta = nuevo hilo (corredor); Cree dos subprocesos, con el mismo Runnable (el
[Link](“Hilo alfa”); mismo trabajo; hablaremos más sobre los "dos subprocesos
y uno
[Link](“Hilo Beta”); Runnable” en unas pocas páginas).
[Link](); Nombra los hilos.
[Link](); Iniciar los hilos.
}
Cada hilo pasará por este bucle e
ejecución pública vacía () imprimirá su nombre cada vez.
{ para (int i = 0; i < 25; i++) {
Cadena threadName = [Link]().getName();
[Link](threadName + “se está ejecutando”);
}
}
} Ayuda de la ventana de edición de archivos Centauri

El hilo alfa se está ejecutando


Parte de la salida cuando
el bucle se repite 25 El hilo alfa se está ejecutando
¿Lo que sucederá? veces. El hilo alfa se está ejecutando
El hilo beta se está ejecutando
El hilo alfa se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo beta se está ejecutando
El hilo alfa se está ejecutando

usted está aquí 503


Machine Translated by Google

¿No son maravillosos los hilos?

¡Guau! Los hilos son

¡Lo mejor desde el MINI Cooper!


No se me ocurre ninguna
desventaja del uso de hilos, ¿a
ti?

Mmm, sí. HAY un lado oscuro.


Los subprocesos pueden provocar "problemas" de concurrencia.

504 capítulo 15
Machine Translated by Google

redes e hilos

Matrimonio en problemas.
¿Podrá salvarse esta pareja?
A continuación, en un programa muy especial del Dr. Steve

[Transcripción del episodio 42]

Bienvenido al programa del Dr. Steve.

Hoy tenemos una historia que se centra en las dos razones principales por las que las
parejas se separan: las finanzas y el sueño.

La problemática pareja de hoy, Ryan y Monica, comparten una cama y


una cuenta bancaria. Pero no por mucho tiempo si no podemos encontrar
una solución. ¿El problema? Lo clásico de “dos personas, una cuenta bancaria”.

Así me lo describió Mónica:

“Ryan y yo acordamos que ninguno de nosotros sobregirará la cuenta corriente.


Entonces el procedimiento es, quien quiera retirar el saldo de dinero de la debe Compruebe el
cuenta antes realizando el retiro. Todo parecía tan
simple. ¡Pero de repente estamos sintiendo cheques y sufriendo cargos por sobregiro!
Ryan y Monica: víctimas
del problema de “dos
Pensé que no era posible, pensé que nuestro procedimiento era seguro. Pero entonces personas, una cuenta”.
este sucedió:

Ryan necesitaba $50, así que revisó el saldo de la cuenta y vio que
eran $100. Ningún problema. Entonces, planea retirar el Ryan se queda
dinero. ¡Pero primero se queda dormido! dormido después de
comprobar el saldo
Y ahí es donde I Entra mientras Ryan todavía duerme y quiere
pero antes de realizar el
ahora I retirar $100. Reviso el saldo y son $100 (porque Ryan
retiro. Al despertar,
todavía está dormido y aún no ha hecho su retiro), así que creo que inmediatamente
no hay problema. Entonces hago el retiro y nuevamente no hay realiza el retiro sin volver a consultar el saldo.
problema. Pero entonces Ryan se despierta, completa el retiro y ¡de repente
su
estamos en descubierto! Ni siquiera sabía que se había quedado dormido, así
que siguió adelante y completó su transacción sin volver a verificar el saldo. Tienes
que ayudarnos Dr.
¡Steve!

¿Hay alguna solución? ¿Están condenados? No podemos evitar que Ryan se


duerma, pero ¿podemos asegurarnos de que Monica no pueda poner sus manos en la
cuenta bancaria hasta que él se despierte?

Tómate un momento y piensa en eso mientras vamos a una pausa comercial.

usted está aquí 505


Machine Translated by Google

Código de Ryan y Mónica

El problema de Ryan y Monica, en clave


Ejecutable

Cuenta bancaria

saldo interno

obtenerSaldo() RyanAndMonicaJob
retirar() Cuenta bancaria

correr()

hacerRetiro()

1 Cree una instancia de RyanAndMonicaJob.


La clase RyanAndMonicaJob es Runnable (el trabajo a realizar),
y dado que tanto Monica como Ryan hacen lo mismo
(verificar saldo y retirar dinero), solo necesitamos una instancia. En el método run(), haz exactamente
lo que harían Ryan y Mónica:
RyanAndMonicaJob theJob = nuevo RyanAndMonicaJob();
comprobar el saldo y, si hay suficiente
dinero, realizar el retiro.
2 Cree dos subprocesos con el mismo Runnable (la instancia de
RyanAndMonicaJob)
Hilo uno = nuevo hilo (el trabajo);
Esto debería proteger contra
Hilo dos = nuevo hilo (el trabajo);
sobregiros en la cuenta.

3 Nombra e inicia los hilos.


Excepto... Ryan y Mónica
[Link](“Ryan”);
siempre se quedan dormidos
[Link](“Mónica”);
[Link](); después de consultar el
[Link](); saldo pero antes de terminar el
retiro.

4 Observe cómo ambos subprocesos ejecutan el método run() (verifique


el saldo y realice un retiro)

Un hilo representa a Ryan, el otro representa a Mónica.


Ambos hilos verifican continuamente el saldo y luego realizan un retiro,
¡pero solo si es seguro! if
([Link]() >= monto) {
intentar {
[Link](500);
} catch(InterruptedException ex) {[Link](); }
}

506 capítulo 15
Machine Translated by Google

redes e hilos

El ejemplo de Ryan y Mónica


clase Cuenta Bancaria {
saldo int privado = 100; La cuenta comienza con
un saldo de $100.
público int getSaldo() {
saldo de devolución;
}
retiro público nulo (monto int) {
saldo = saldo ­ monto;
}
}
Solo habrá UNA instancia de
la clase pública RyanAndMonicaJob implementa Runnable { RyanAndMonicaJob. Eso significa
solo UNA instancia de la cuenta
cuenta de cuenta bancaria privada = nueva cuenta bancaria(); bancaria. Ambos hilos accederán a esta cuenta.

público estático vacío principal (String [] args) {


RyanAndMonicaJob theJob = nuevo RyanAndMonicaJob();
Hilo uno = nuevo hilo (el trabajo); Crear una instancia del Runnable (trabajo)
Hilo dos = nuevo hilo (el trabajo);
[Link](“Ryan”); trabajo. Eso significa
Cree dos subprocesos y proporcione a cada subproceso la misma
[Link](“Mónica”);
ambos hilos accederán al uno
[Link](); variable de instancia de cuenta Runnable en la clase Runnable.
[Link]();
}

ejecución pública vacía () { En el método run(), un hilo recorre e intenta realizar


para (int x = 0; x < 10; x++) { un retiro con cada iteración. Después del retiro,
hacerRetiro(10); verifica el saldo una vez más para ver si
si ([Link]() < 0) {
la cuenta está sobregirada.
[Link](“¡Sobregirado!”);
}
} Verificamos el saldo de la cuenta y, si no hay suficiente
} dinero, simplemente imprimimos un mensaje. Si HAY
suficiente, nos vamos a dormir, luego nos despertamos y
makeWithdrawal anulado privado ( monto int) { completamos la retirada, tal como lo hizo Ryan.
if ([Link]() >= monto) {
[Link]([Link]().getName() + prueba { “está a punto de retirarse”);

[Link]([Link]().getName() + [Link](500); “se va a dormir”);

} catch(InterruptedException ex) {[Link](); }


[Link]([Link]().getName() + “despertó.”);
[Link](monto);
[Link]([Link]().getName() + } “completa el retiro”);

demás {
[Link](“Lo siento, no es suficiente para” + [Link]().getName());
}
} Colocamos un montón de declaraciones impresas para que
} podamos ver lo que sucede mientras se ejecuta.

usted está aquí 507


Machine Translated by Google

Salida de Ryan y Monica

Ventana de edición de archivos Ayuda Visa

Ryan está a punto de retirarse


ryan se va a dormir El método makeWithdrawal() siempre verifica el
saldo antes de realizar un retiro, pero aun
Mónica se despertó.
así sobregiramos la cuenta.
Mónica completa el retiro.
Mónica está a punto de retirarse.

mónica se va a dormir
Aquí hay un escenario:
Ryan se despertó.
Ryan completa la retirada Ryan comprueba el saldo, ve que hay
Ryan está a punto de retirarse suficiente dinero y luego se queda dormido.
ryan se va a dormir
Mónica se despertó. Mientras tanto, entra Mónica y consulta el saldo. Ella
Mónica completa el retiro. también ve que hay suficiente dinero. No tiene idea
Mónica está a punto de retirarse. de que Ryan se despertará y completará un
retiro.
mónica se va a dormir
Ryan se despertó.
Ryan completa la retirada Mónica se queda dormida.

Ryan está a punto de retirarse Ryan se despierta y completa su retirada.


ryan se va a dormir
Mónica se despertó. Mónica se despierta y completa su retirada.
Mónica completa el retiro. ¡Gran problema! Entre el momento en que comprobó
el saldo y
Lo siento, no es suficiente para Mónica.
Después de realizar el retiro, Ryan se despertó y
Lo siento, no es suficiente para Mónica. sacó dinero de la cuenta.
Lo siento, no es suficiente para Mónica.
El cheque de Mónica de la cuenta fue
Lo siento, no es suficiente para Mónica. no es válido, porque Ryan ya había verificado y
Lo siento, no es suficiente para Mónica. todavía estaba en medio de un retiro.

Ryan se despertó.
Ryan completa la retirada Se debe impedir que Monica ingrese a la cuenta
¿Cómo ¡Girado en descubierto! hasta que Ryan se despierte y finalice su transacción.
pasó esto? Y viceversa.
Lo siento, no es suficiente para Ryan.
¡Girado en descubierto!

Lo siento, no es suficiente para Ryan.


¡Girado en descubierto!

Lo siento, no es suficiente para Ryan.


¡Girado en descubierto!

508 capítulo 15
Machine Translated by Google

redes e hilos

¡Necesitan un candado para acceder a la cuenta!

La cerradura funciona así:

1 Hay un candado asociado al banco.


La transacción de la cuenta
transacción de cuenta (consultar el saldo bancaria se desbloquea
y retirar dinero). Solo hay una llave cuando nadie está
y permanece en la cerradura hasta
usando la cuenta.
que alguien quiera acceder a la cuenta.

Cuando Ryan
2 Cuando Ryan quiere acceder al banco quiere acceder a la cuenta,
cuenta (para consultar el saldo y retirar dinero),
cierra la cerradura y
cierra la cerradura y se guarda la llave en el toma la llave.
bolsillo. Ahora nadie más podrá acceder a la
cuenta, ya que la clave ya no existe.

3 Ryan guarda la llave en su bolsillo hasta que finaliza la


Cuando Ryan termina,
transacción. Él tiene la única llave, por lo que Mónica no
abre la cerradura
puede acceder a la cuenta (o a la chequera) hasta y devuelve la llave. Ahora
que Ryan desbloquee la cuenta y devuelva la llave. la clave está disponible
para que Monica (o Ryan
Ahora, incluso si Ryan se queda dormido después nuevamente) acceda a
de verificar el saldo, tiene la garantía de que el saldo la cuenta.
será el mismo cuando se despierte, ¡porque guardó la
llave mientras dormía!

usted está aquí 509


Machine Translated by Google

usando sincronizado

Necesitamos que el método makeWithdrawal () se


ejecute como un elemento atómico .

La palabra clave
sincronizada significa que un
hilo necesita una clave para
acceder al código sincronizado.
sincronizado

Para proteger su (como datos


la cuenta bancaria), sincronice los
que actúan sobre esos
métodos datos.

makeWithdrawal anulado sincronizado privado (monto int) {

if ([Link]() >= monto) {


[Link]([Link]().getName() + prueba { “está a punto de retirarse”);

[Link]([Link]().getName() + “se va a dormir”);


[Link](500);
} catch(InterruptedException ex) {[Link](); }
[Link]([Link]().getName() + “despertó.”);
[Link](monto);
[Link]([Link]().getName() + } más { “completa el retiro”);

[Link](“Lo siento, no es suficiente para” + [Link]().getName());


}
}

(Nota para los lectores expertos en física: sí, la convención de usar la palabra "atómica" aquí no refleja todo el asunto
de las partículas subatómicas. Piense en Newton, no en Einstein, cuando escuche la palabra "atómica" en el
contexto de hilos o Oye, no es NUESTRA convención. Si NOSOTROS estuviéramos a cargo, aplicaríamos el
Principio de Incertidumbre de Heisenberg a prácticamente todo lo relacionado con subprocesos).

510 capítulo 15
Machine Translated by Google

redes e hilos

Usando el bloqueo de un objeto

Oye, el método
takeMoney() de este objeto
está sincronizado. Necesito
obtener la clave de este objeto
antes de poder entrar...

Cada objeto Java tiene un candado.


Una cerradura tiene una sola llave.

La mayoría de las veces, la cerradura

está abierta y a nadie le importa.

Pero si un objeto
tiene métodos
sincronizados, un hilo puede
ingresar a uno de los métodos
sincronizados SÓLO si la clave
para el bloqueo del objeto
está disponible. En otras
palabras, sólo si otro hilo aún no ha tomado

usted está aquí 511


Machine Translated by Google

la sincronización importa

El temido problema de la “Actualización perdida”

int i = saldo;

saldo = i + 1;

saldo++;

clase TestSync implementa Runnable {

saldo privado;
cada hilo se ejecuta 50 veces,
ejecución pública vacía() { incrementando el equilibrio en
para(int i = 0; i < 50; i++) { cada iteración
incremento();
[Link](“el saldo es” + saldo);
}
}

incremento de vacío público () {


int i = saldo;
saldo = i + 1;
}
¡Aquí está la parte crucial! Incrementamos el
} saldo sumando 1 al valor del saldo EN EL
el valor ACTUAL
TIEMPO QUE LOes)
LEÍMOS (en lugar de agregar 1 a cualquier
clase pública TestSyncTest {
público estático vacío principal (String[] args) {
Trabajo TestSync = nuevo TestSync();
Hilo a = nuevo hilo (trabajo);
Hilo b = nuevo hilo (trabajo);
un inicio();
[Link]();
}
}

512 capítulo 15
Machine Translated by Google

redes e hilos

Ejecutemos este código...

1 El hilo A se ejecuta por un tiempo.


Coloque el valor del saldo en la variable i.

El saldo es 0, entonces i ahora es 0.


Establezca el valor del saldo al resultado de i + 1.
Ahora el saldo es 1.

A Coloque el valor del saldo en la variable i.

El saldo es 1, entonces i ahora es 1.


Establezca el valor del saldo al resultado de i + 1.

B
Ahora el saldo es 2.

2 El hilo B se ejecuta por un tiempo.


Coloque el valor del saldo en la variable i.

El saldo es 2, entonces i ahora es 2.


Establezca el valor del saldo al resultado de i + 1.
Ahora el saldo es 3.

B Coloque el valor del saldo en la variable i.

El saldo es 3, por lo que ahora soy 3.

[ahora el subproceso B se devuelve a ejecutable,


antes de establecer el valor del saldo en 4]

3 El hilo A se ejecuta de nuevo y continúa donde lo dejó.


Coloque el valor del saldo en la variable i.

El saldo es 3, por lo que ahora soy 3.


Establezca el valor del saldo al resultado de i + 1.
Ahora el saldo es 4.

A Coloque el valor del saldo en la variable i.

El saldo es 4, por lo que ahora soy 4.


Establezca el valor del saldo al resultado de i + 1.
Ahora el saldo es 5.

4 ¡ El hilo B se ejecuta nuevamente y continúa exactamente donde lo dejó!


¡Perdimos las últimas actualizaciones
Establezca el valor del saldo al resultado de i + 1.
que realizó el hilo A!
Ahora el saldo es 4.

¡¡Ay!! El hilo B había realizado previamente


una 'lectura' del valor

B El hilo A lo actualizó a 5, pero ahora B


de equilibrio, y cuando B despertó,
regresó y se puso encima de la siguió adelante como si nunca perdiera
actualización que realizó A, como si el ritmo.
la actualización de A nunca hubiera ocurrido.

usted está aquí 513


Machine Translated by Google

métodos de sincronización

Haga que el método increment() sea atómico.

¡Sincronízalo!

Una vez que un hilo ingresa al


método, debemos asegurarnos
de que todos los pasos del

incremento vacío sincronizado público () { método se completen (como un


int i = saldo; proceso atómico) antes de
saldo = i + 1; que cualquier otro hilo pueda ingresar
} al método.

no existen
Preguntas tontas
B

doStuff() no necesita
sincronizarse, por lo que
no sincronizamos todo el método.
vacío público ir () {
hacer cosas();

sincronizado (esto) {
Cosas críticas();
másCosasCríticas();
}
}

en uno solo estas dos llamadas a métodos están


Ahora,
agrupadas en unidades atómicas.
Cuando usa la palabra clave sincronizada
DENTRO de un método, en lugar de en una
declaración de método, debe proporcionar un
argumento que sea el objeto cuya clave el hilo necesita obtener.

Aunque hay otras formas de hacerlo, casi siempre


sincronizará en el objeto actual (este). Ese es el
mismo objeto que bloquearías si todo el método
estuviera sincronizado.

514 capítulo 15
Machine Translated by Google

redes e hilos

1 El hilo A se ejecuta por un tiempo.

Intente ingresar el método increment().

El método está sincronizado, así que obtenga la clave para este objeto.
Coloque el valor del saldo en la variable i.

A El saldo es 0, entonces i ahora es 0.


Establezca el valor del saldo al resultado de i + 1.
Ahora el saldo es 1.

Devuelve la clave (completa el método increment()).


Vuelva a ingresar el método increment() y obtenga la clave.
Coloque el valor del saldo en la variable i.

El saldo es 1, entonces i ahora es 1.

[ahora el subproceso A se devuelve a ejecutable, pero como no ha completado


el método sincronizado, el subproceso A conserva la clave]

2 El hilo B está seleccionado para ejecutarse

Intente ingresar el método increment(). El método está


sincronizado, por lo que necesitamos obtener la clave.

B La clave no está disponible.

[ahora el hilo B se envía a una sala de 'bloqueo de objeto no disponible]

3 El hilo A se ejecuta nuevamente, retomando donde lo


dejó (recuerde, todavía tiene la clave)
Establezca el valor del saldo al resultado de i + 1.
Ahora el saldo es 2.

A Devuelve la llave.

[ahora el hilo A se devuelve a ejecutable, pero como ha


completado el método increment(), el hilo NO retiene la clave]

4 El hilo B está seleccionado para ejecutarse

Intente ingresar el método increment(). El método está sincronizado,


por lo que necesitamos obtener la clave.

B Esta vez, la clave ESTÁ disponible, consíguela.

Coloque el valor del saldo en la variable i.

[continúa corriendo...]

usted está aquí 515


Machine Translated by Google

punto muerto del hilo

El lado mortal de la sincronización

Todo lo que se
necesita para llegar a un
punto muerto son dos
objetos y dos hilos.

foo

AB
bar

Un escenario de punto muerto simple:

El hilo A entra en un El hilo B entra en un


1 2 3 El hilo A se despierta (todavía
método sincronizado del método sincronizado de la mantiene presionada la
objeto foo y obtiene la clave. barra de objetos y obtiene la tecla foo ) e intenta ingresar un

A foo
B clave.
A método sincronizado en la barra

bar de objetos, pero no puede


obtener esa clave porque B la

El hilo B intenta entrar. tiene. A va a la sala de espera,


El hilo A va a
hasta que la llave del bar esté
duerme, sosteniendo un método sincronizado del
disponible (¡nunca lo estará!)
la tecla fo . objeto foo, pero no puede
obtener esa clave (porque
A A la tiene). B va a la
El hilo A no puede ejecutarse hasta

B sala de espera, hasta que A puede obtener la llave de la barra ,

foo pero B está sosteniendo la tecla


la llave foo esté
bar y B no puede correr hasta que
disponible. B se queda con
bar foo obtenga la tecla foo que A está
la llave de la barra .
sosteniendo y...

516 capítulo 15
Machine Translated by Google

redes e hilos

PUNTOS DE VIÑETA

El método estático [Link]() obliga a un subproceso a abandonar el


estado de ejecución durante al menos el tiempo pasado al método de suspensión.
[Link](200) pone un hilo en suspensión durante 200 milisegundos.

El método sleep() genera una excepción marcada (InterruptedException), por lo que


todas las llamadas a sleep() deben incluirse en un try/catch o declararse.

Puede usar sleep() para asegurarse de que todos los subprocesos tengan la
oportunidad de ejecutarse, aunque no hay garantía de que cuando un subproceso se
active vaya al final de la línea ejecutable. Podría, por ejemplo, volver al frente.
En la mayoría de los casos, todo lo que necesita son llamadas a sleep() en el momento adecuado para

mantener los hilos cambiando correctamente.

Puedes nombrar un hilo usando el (otra sorpresa más) método setName(). Todos los
subprocesos obtienen un nombre predeterminado, pero darles un nombre explícito puede
ayudarle a realizar un seguimiento de los subprocesos, especialmente si está depurando
con declaraciones impresas.

Puede tener serios problemas con los subprocesos si dos o más subprocesos tienen
acceso al mismo objeto en el montón.

Dos o más subprocesos que acceden al mismo objeto pueden provocar daños
en los datos si un subproceso, por ejemplo, deja el estado de ejecución mientras aún
está manipulando el estado crítico de un objeto.

Para que sus objetos sean seguros para subprocesos, decida qué declaraciones
deben tratarse como un proceso atómico. En otras palabras, decida qué métodos
deben ejecutarse hasta su finalización antes de que otro hilo ingrese el mismo método
en el mismo objeto.

Utilice la palabra clave sincronizado para modificar la declaración de un método,


cuando desee evitar que dos subprocesos entren en ese método.

Cada objeto tiene una única cerradura, con una única llave para esa cerradura. La
mayoría de las veces no nos importa ese candado; Los bloqueos entran en juego
sólo cuando un objeto tiene métodos sincronizados.

Cuando un hilo intenta ingresar un método sincronizado, el hilo debe


obtener la clave del objeto (el objeto cuyo método el hilo está intentando
ejecutar). Si la clave no está disponible (porque otro hilo ya la tiene),
el hilo entra en una especie de sala de espera, hasta que la clave esté
disponible.

Incluso si un objeto tiene más de un método sincronizado, todavía hay una sola clave.
Una vez que cualquier hilo ha ingresado un método sincronizado en ese objeto, ningún
hilo puede ingresar ningún otro método sincronizado en el mismo objeto. Esta
restricción le permite proteger sus datos sincronizando cualquier método que manipule
los datos.

usted está aquí 517


Machine Translated by Google

cliente de chat final

Nuevo y mejorado SimpleChatClient

Sí, realmente HAY un final


importar [Link].*;
para este capítulo.
importar [Link].*;
Pero no todavía...
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;

clase pública SimpleChatClient {

JTextArea entrante;
JTextField saliente;
Lector BufferedReader;
Escritor impresor;
calcetín;

público estático vacío principal (String [] argumentos) {


Cliente SimpleChatClient = nuevo SimpleChatClient();
[Link](); Esto es principalmente código GUI que
} has visto antes. Nada especial excepto
la parte resaltada donde comenzamos el
vacío público ir () { Nuevo hilo de 'lector'.

JFrame frame = new JFrame(“Cliente de chat ridículamente simple”);


JPanel panel principal = nuevo JPanel(); entrante =
nuevo JTextArea(15,50);
[Link](verdadero);
[Link](verdadero);
[Link](falso); JScrollPane
qScroller = nuevo JScrollPane (entrante);
[Link](ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
[Link](ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); saliente = nuevo JTextField(20);
JButton sendButton = nuevo JButton(“Enviar”);

[Link](nuevo SendButtonListener()); panel [Link](qScroller);

Estamos iniciando un nuevo hilo,


[Link](saliente);
usando una nueva clase
[Link](enviarBotón);
interna como Runnable (trabajo)
configurarRedes();
para el hilo. El trabajo del hilo
Hilo lectorThread = nuevo hilo (nuevo IncomingReader()); es leer desde el flujo de socket
[Link](); del servidor, mostrando
cualquier mensaje entrante en el
[Link]().add([Link], mainPanel); área de texto de desplazamiento.
[Link](400,500);
[Link] (verdadero);

} // cerrar ir

518 capítulo 15
Machine Translated by Google

redes e hilos

setUpNetworking vacío privado() {

intentar {
calcetín = nuevo enchufe ("[Link]", 5000);
InputStreamReader streamReader = nuevo InputStreamReader([Link]());
lector = nuevo BufferedReader(streamReader);
escritor = nuevo PrintWriter([Link]()); [Link](“red
establecida”);
Estamos usando el socket para obtener los
} captura (IOException ex) {
flujos de entrada y salida. Ya estábamos
[Link]();
} usando el flujo de salida para enviar al
} // cerrar setUpNetworking servidor, pero ahora estamos usando el
flujo de entrada para que el nuevo hilo
'lector' pueda recibir mensajes del servidor.

la clase pública SendButtonListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {
intentar {
[Link]([Link]());
[Link]();
Nada nuevo aquí. Cuando el usuario
} captura (Excepción ex) { hace clic en el botón enviar, este método
[Link](); envía el contenido del campo de texto al servidor.
}
[Link](“”);
[Link]();
}
} // cerrar clase interna

la clase pública IncomingReader implementa Runnable {


ejecución pública vacía() { ¡¡Esto es lo que hace el hilo!!
Mensaje de cadena;
En el método run(), permanece en un
intentar {
bucle (siempre que lo que obtiene del
while ((mensaje = [Link]()) != nulo) { [Link](“leer “ + servidor no sea nulo), leyendo una
mensaje); línea a la vez y agregando cada línea
[Link](mensaje + “\n”); al área de texto de desplazamiento
(junto con un carácter de nueva línea) .
} // cerrar mientras
} catch(Excepción ex) {[Link]();}
} // cerrar ejecución
} // cerrar clase interna

} // cerrar clase externa

usted está aquí 519


Machine Translated by Google

código del servidor de chat

El servidor de chat realmente simple

Para ejecutar el cliente de chat, necesita dos terminales.


Primero, inicie este servidor desde una terminal, luego
importar [Link].*; importar inicie el cliente desde otra terminal
[Link].*; importar [Link].*;

clase pública VerySimpleChatServer {

Cliente ArrayListOutputStreams;

la clase pública ClientHandler implementa Runnable {


Lector BufferedReader;
calcetín;

public ClientHandler(Socket clienteSocket) {


prueba
{ calcetín = clientSocket;
InputStreamReader isReader = new InputStreamReader([Link]()); lector = nuevo BufferedReader(isReader);

} catch(Exception ex) {[Link]();} } // cerrar constructor

ejecución pública vacía()


{ Mensaje de cadena;
intente
{ while ((mensaje = [Link]()) != nulo) { [Link](“leer “ +
mensaje); decirle a todos (mensaje);

} // cerrar mientras
} catch(Excepción ex) {[Link]();}
} // cerrar ejecución } //
cerrar clase interna

520 capítulo 15
Machine Translated by Google

redes e hilos

public static void main (String[] args) { nuevo


VerySimpleChatServer().go();
}

public void go()


{ clientOutputStreams = nueva ArrayList(); intentar {

ServerSocket serverSock = nuevo ServerSocket(5000);

while(true) { Socket
clientSocket = [Link](); Escritor PrintWriter = new
PrintWriter([Link]()); [Link](escritor);

Hilo t = nuevo hilo (nuevo ClientHandler (clientSocket)); [Link](); [Link](“obtuve


una conexión”);

} catch(Excepción ex)
{ [Link]();
}
} // cerrar ir

public void tellEveryone (mensaje de cadena) {

Iterador it = [Link](); while([Link]()) { intentar


{ PrintWriter escritor = (PrintWriter)
[Link]();
[Link](mensaje); [Link](); } captura (Excepción ex) {

[Link]();
}

} // terminar mientras

} // cerrar informar a todos } //


cerrar clase

usted está aquí 521


Machine Translated by Google

preguntas de sincronización

no existen
Preguntas tontas

522 capítulo 15
Machine Translated by Google

redes e hilos

tu mensaje se envía a los otros


jugadores, junto con tu patrón
ritmo de baile
de ritmo actual, cuando

presionas
"mándalo"

Andy: ritmo #2

Chris: groove2 revisado

Nigel: ritmo de baile Reproductores de desde


mensajes entrantes. Haga
hasta cargar

clic en el patrón que lo acompaña


y luego haga clic en "Iniciar" para

reproducirlo.

usted está aquí 523


Machine Translated by Google

Ejercicio: Código Imanes

clase pública TestThreads { clase ThreadOne

clase acumulada {
clase HiloDos

Ventana de edición de archivos Ayuda para coser

% java TestThreads uno


98098
dos 98099

524 capítulo 15
Machine Translated by Google

redes e hilos

Acumular a = [Link]();

Hilo uno = nuevo hilo (t1); [Link](“dos “+[Link]());

ThreadTwo t2 = nuevo ThreadTwo(); intentar {


} captura (Excepción interrumpida ex) { }

contador de devoluciones; contador += agregar;

Hilo dos = nuevo hilo (t2); implementa ejecutable { [Link]();

[Link](50);
Acumular a = [Link]();

} captura (Excepción interrumpida ex) { }


acumulación estática pública getAccum() {

Acumulación estática privada a = nueva Acumulación();

contador int privado = 0;


ejecución pública vacía() {

[Link](1); [Link](50);

para(int x=0; x < 99; x++) { implementa ejecutable {

[Link](1000);
público int getCount() { devolver un;

[Link](“uno “+[Link]());
contador de actualización vacío público (int agregar) {

público estático vacío principal (String [] argumentos) {


[Link]();
para(int x=0; x < 98; x++) {

intentar {
ejecución pública vacía() { acumulación privada() { } ThreadOne t1 = nuevo ThreadOne();

usted está aquí 525


Machine Translated by Google

soluciones de ejercicio

clase pública TestThreads {

público estático vacío principal (String [] argumentos) {

ThreadOne t1 = nuevo ThreadOne();

ThreadTwo t2 = nuevo ThreadTwo();

Hilo uno = nuevo hilo (t1);

Hilo dos = nuevo hilo (t2);

[Link]();

[Link]();
Los subprocesos de dos clases diferentes están
} actualizando el mismo objeto en una tercera clase,
crear una instancia estática
} porque ambos subprocesos acceden a una única instancia de Accum.
de la clase Accum La línea de código:

clase acumulada { crea un


Acumulación estática privada a = nueva Acumulación(); instancia estática de Accum (recuerde que estático significa
contador int privado = 0; uno por clase), y el constructor privado en Accum
significa que nadie más puede crear un objeto Accum. Estas
acumulación privada() { } Un constructor privado dos técnicas (constructor privado y método getter estático)
utilizadas juntas crean lo que se conoce como 'Singleton', un
acumulación estática pública getAccum() { patrón OO para restringir el número de instancias de un
devolver un; objeto que pueden existir en una aplicación. (Por lo
} general, solo hay una instancia de un Singleton, de ahí el
nombre), pero puede usar el patrón para restringir la
contador de actualización vacío público (int agregar) { creación de la instancia de la forma que elija).
contador += agregar;
}

público int getCount() {


contador de devoluciones;
clase ThreadTwo implementa Runnable {
}
} Acumular a = [Link]();
ejecución pública vacía() {
clase ThreadOne implementa Runnable {
para(int x=0; x < 99; x++) {
Acumular a = [Link]();
[Link](1);
ejecución pública vacía() { intentar {
para(int x=0; x < 98; x++) { [Link](50);
[Link](1000); } captura (Excepción interrumpida ex) { }

intentar { }

[Link](50); [Link](“dos “+[Link]());

} captura (Excepción interrumpida ex) { } }


}
}

[Link](“uno “+[Link]());

526 capítulo 15
Machine Translated by Google

redes e hilos

Casi accidente en la esclusa de aire


Cuando Sarah se unió a la reunión de revisión del diseño del equipo de desarrollo a bordo, contempló el portal al
amanecer sobre el Océano Índico. Aunque la sala de conferencias de la nave era increíblemente claustrofóbica, la
visión de la creciente media luna azul y blanca que se apoderaba de la noche en el planeta de abajo llenó a Sarah de
asombro y aprecio.

Cinco minutos La reunión de esta mañana se centró en los sistemas de control de las esclusas de aire del orbitador.

Misterio A medida que las fases finales de construcción estaban llegando a su fin, el número de caminatas espaciales fue
Estaba previsto que aumentara dramáticamente, y el tráfico era alto tanto dentro como fuera del barco.
esclusas de aire. "Buenos días Sarah", dijo Tom, "tu momento es perfecto, apenas estamos comenzando la
revisión detallada del diseño".

“Como todos saben”, dijo Tom, “cada esclusa de aire está equipada con terminales GUI resistentes al
espacio, tanto por dentro como por fuera. Siempre que los caminantes espaciales entren o salgan del orbitador
Utilizarán estas terminales para iniciar las secuencias de las esclusas de aire”. Sarah asintió, "Tom,
¿puedes decirnos cuáles son las secuencias de métodos para entrar y salir?" Tom se levantó y flotó hacia
la pizarra. "Primero, aquí está el pseudocódigo del método de secuencia de salida", escribió rápidamente Tom
en la pizarra.

orbitadorAirlockExitSequence()

verificarEstadoPortal();

presurizarAirlock();

openInnerHatch();

confirmarAirlockOccupied();

cerrarInnerHatch();

descomprimirAirlock();

openOuterHatch();

confirmarAirlockVacated();

cerrarOuterHatch();

"Para garantizar que la secuencia no se interrumpa, hemos sincronizado todos los métodos llamados
por el método orbiterAirlockExitSequence()", explicó Tom. "¡Odiaríamos ver a un caminante espacial que regresa y
atrapa sin darse cuenta a un amigo con los pantalones espaciales bajados!"

Todos se rieron entre dientes mientras Tom borraba la pizarra, pero algo no le parecía bien a Sarah y
finalmente hizo clic cuando Tom comenzó a escribir el pseudocódigo de la secuencia de entrada en la pizarra.
“¡Espera un momento, Tom!”, gritó Sarah, “Creo que tenemos un gran defecto en el diseño de la secuencia de
salida, volvamos a revisarlo, ¡podría ser crítico!”

¿Por qué Sarah detuvo la reunión? ¿Qué sospechaba ella?

usted está aquí 527


Machine Translated by Google

respuestas del rompecabezas

¿Qué sabía Sara?

orbitadorEsclusa de aireSalidaSecuencia

orbita
erAirlockExitSequence( )

528 capítulo 15
Machine Translated by Google

16 colecciones y genéricos.

Datos Joder... y todo este

estructuras tiempo podría haber dejado que


Java pusieran las cosas en orden alfabético.
¿orden? El tercer grado realmente
apesta. Nunca aprendemos
nada útil...

Ordenar es muy sencillo en Java.

este es un nuevo capitulo 529


Machine Translated by Google

ordenar una lista

Seguimiento de la popularidad de las canciones en su máquina de discos

Lista de [Link]

Desafío #1
Luna Rosa/Nick Drake Ordenar las canciones en orden alfabético.
Salto mortal/Cero 7
Shiva Luna/Prem Joshua
Círculos/BT
Canal profundo/celtas afro
Pasajero/mezcla principal
Escuchar/Tahití 80

Este es el archivo que escribe el dispositivo


jukebox. Su código debe leer el archivo y
luego manipular los datos de la canción.

530 capítulo 16
Machine Translated by Google

colecciones con genéricos

Esto es lo que tienes hasta ahora, sin el tipo:


importar [Link].*;
importar [Link].*;
Almacenaremos los títulos de las
canciones en una ArrayList de cadenas.
clase pública Jukebox1 {

ArrayList<String> songList = new ArrayList<String>();

público estático vacío principal (String [] argumentos) {


nuevo Jukebox1().go();
}
El método que comienza a cargar el archivo y
luego imprime el contenido de songList ArrayList.
public void go() { getSongs();

[Link](lista de canciones);
}

No hay nada especial aquí... simplemente lea el archivo y


llame al método addSong() para cada línea.
void getCanciones() {
intentar {
Archivo archivo = nuevo archivo ("[Link]");
Lector BufferedReader = nuevo BufferedReader (nuevo FileReader (archivo));
Línea de cadena = nula;
mientras ((línea= [Link]()) != nulo) {
agregarCanción(línea);
}

} captura (Excepción ex) {


[Link]();
}
} El método addSong funciona igual que el método Quiz­
Tarjeta en el capítulo de E/S: tú (que
piezas romper la línea
void addSong(String lineToParse) { tiene tanto el título como el artista) en dos
(tokens) usando el método split().
String[] tokens = [Link](“/”);
[Link](tokens[0]);
}
Solo queremos el título de la
} canción, así que agregue solo el
primer token a SongList (ArrayList).

Ventana de edición de archivos Ayuda Dance

SongList se imprime con las


%java Jukebox1
[Luna rosada, salto mortal, canciones en el orden en que se
agregaron a ArrayList (que es el mismo
luna de shiva, círculos, orden en que se encuentran las
Canal Profundo, Pasajero, canciones dentro del archivo de texto original).
Escuchar]
¡Esto definitivamente NO es alfabético!

usted está aquí 531


Machine Translated by Google

API de lista de matrices

¡Pero la clase ArrayList NO tiene un método sort()!

ArrayList tiene muchos métodos,


pero no hay nada aquí que
parezca que se pueda ordenar...

532 capítulo 16
Machine Translated by Google

colecciones con genéricos

Veo una clase de colección


llamada TreeSet... y los documentos
decir que mantiene sus datos
ordenados. Me pregunto si debería
usar un TreeSet en lugar de un
ArrayList...

ArrayList no es la única colección

No te preocupes por intentar


aprender estos otros ahora
mismo. Entraremos en
Conjunto de árboles
más detalles un poco más adelante.
Mantiene los elementos ordenados y evita duplicados.

HashMap

Almacenemos y accedamos a elementos como pares de nombre/valor.

LinkedList
Diseñado para brindar un mejor rendimiento al insertar o eliminar
elementos del medio de la colección. (En la práctica, lo que
normalmente sigue siendo una ArrayList).

Conjunto de hash

Evita duplicados en la colección y, dado un elemento, puede encontrarlo


rápidamente en la colección.

LinkedHashMap

Como un HashMap normal, excepto que puede recordar el orden


en que se insertaron los elementos (pares nombre/valor), o puede
configurarse para recordar el orden en que se accedió a los elementos
por última vez.

usted está aquí 533


Machine Translated by Google

[Link]()

podría utilizar un TreeSet...

Usted o podría utilizar el método [Link]()

[Link]

copia vacía estática pública (lista de destino, lista de origen)

Lista pública estática Lista vacía()

relleno de vacío estático público (lista listToFill, objeto objToFillItWith)

frecuencia int estática pública (Colección c, Objeto o)

reversa vacía estática pública ( lista de lista)

rotación de vacío estático público ( lista de lista, distancia int)

barajado vacío estático público ( lista de lista)

clasificación de vacío estático público (lista de lista)

reemplazar todo booleano estático público ( lista de lista, objeto oldVal, objeto newVal)

// muchos más métodos...

Hmmm... HAY un método sort() en la


clase Colecciones. Se necesita una Lista

y, dado que ArrayList implementa

la interfaz List, ArrayList ES­A List.


Gracias al polimorfismo, puedes

pasar un ArrayList a un método declarado

para tomar Lista.

Nota: esta NO es la API de clase


Colecciones real; Lo simplificamos aquí
omitiendo la información de tipo genérico
(que verá en algunas páginas).

534 capítulo 16
Machine Translated by Google

colecciones con genéricos

Agregar [Link]() al código de Jukebox


importar [Link].*;
importar [Link].*;

clase pública Jukebox1 {


El método [Link]()
ordena una lista de
ArrayList<String> songList = new ArrayList<String>();
cadenas alfabéticamente.
público estático vacío principal (String [] argumentos) {
nuevo Jukebox1().go();
}

public void go() { getSongs();


Llame al método estático sort() de
[Link](lista de canciones); Colecciones y luego imprima la lista
[Link](lista de canciones); nuevamente. ¡La segunda impresión está
[Link](lista de canciones); en orden alfabético!
}

void getCanciones() {
intentar {
Archivo archivo = nuevo archivo ("[Link]");
Lector BufferedReader = nuevo BufferedReader (nuevo FileReader (archivo));
Línea de cadena = nula;
mientras ((línea= [Link]()) != nulo) {
agregarCanción(línea);
}

} captura (Excepción ex) {


[Link]();
}
}

void addSong(String lineToParse) {


String[] tokens = [Link](“/”);
[Link](tokens[0]);
}
}
Ventana de edición de archivos Ayuda Chill

%java Jukebox1

Antes de llamar a sort().


[Luna rosa, salto mortal, luna de Shiva, círculos, profundidad
Canal, Pasajero, Escuchar]
Después de llamar a sort().
[Círculos, Canal profundo, Escuchar, Pasajero, Rosa
Luna, Luna de Shiva, Salto mortal]

usted está aquí 535


Machine Translated by Google

ordenar tus propios objetos

Pero ahora necesitas objetos Song,


no sólo cadenas simples.

ListadecancionesMá[Link]

Luna Rosa/Nick Drake/5/80


Salto mortal/Cero 7/4/84
Shiva Luna/Prem Joshua/6/120
Círculos/BT/5/110
Canal Profundo/Afro Celtas/4/120
Pasajero/Headmix/4/100
Escuchar/Tahití 80/5/90

El nuevo archivo de canción tiene


cuatro atributos en lugar de sólo dos.
Y queremos TODOS ellos en nuestra lista,
canción de clase {
Cuatro variables de instancia para los por lo que necesitamos crear una clase
Título de cadena;
Song con variables de instancia para los
Artista de cuerdas; cuatro atributos de canción del archivo. cuatro
atributos de la canción.
Clasificación de cadena;
bpm de cadena;

Canción (Cadena t, Cadena a, Cadena r, Cadena b) {


título = t;
artista = a; Todas las variables se
calificación = r; configuran en el constructor
lpm = b;
cuando se crea la nueva canción.
}

cadena pública getTitle() {


título de devolución;
}

public String getArtist() { devolver artista;

} Los métodos getter para


los cuatro atributos.
cadena pública getRating() {
calificación de retorno;
}

cadena pública getBpm() {


devolver bpm;
}

cadena pública toString() { Anulamos toString(), porque cuando haces un System.


[Link](aSongObject), queremos ver el título.
título de devolución;
}
Cuando haces un [Link](aListOfSongs),
} llama al método toString() de CADA elemento de la lista.

536 capítulo 16
Machine Translated by Google

colecciones con genéricos

Cambiar el código de Jukebox para usar


canciones en lugar de cadenas

importar [Link].*;
Cambie a una ArrayList de
importar [Link].*;
objetos Song en lugar de String.
clase pública Jukebox3 {

ArrayList< Canción> lista de canciones = nueva ArrayList<Canción>();


público estático vacío principal (String [] argumentos) {
nuevo Jukebox3().go();
}
public void go() { getSongs();

[Link](lista de canciones);
[Link](lista de canciones);
[Link](lista de canciones);
}
void getCanciones() {
intentar {
Archivo archivo = nuevo archivo ("[Link]");
Lector BufferedReader = nuevo BufferedReader (nuevo FileReader (archivo));
Línea de cadena = nula;
mientras ((línea= [Link]()) != nulo) {
agregarCanción(línea);
}
} captura (Excepción ex) {
[Link]();
}
}

void addSong(String lineToParse) {


String[] tokens = [Link](“/”);

Canción nextSong = nueva canción(tokens[0], tokens[1], tokens[2], tokens[3]);


[Link](siguienteCanción);
}
} Cree un nuevo objeto Canción usando los cuatro tokens (lo que significa

las cuatro piezas de información en la canción para esta línea), luego archivo

agregue la Canción a la lista.

usted está aquí 537


Machine Translated by Google

[Link]()

¡No se compilará!

Ayuda de la ventana de edición de archivos

%javac [Link]
[Link]: no se puede encontrar el símbolo
símbolo: método sort([Link]<Song>) ubicación: clase
[Link] [Link](songList);

^
1 error

538 capítulo 16
Machine Translated by Google

colecciones con genéricos

¿Qué carajo? No tengo idea de


cómo leer la declaración del método.
en este. Dice que sort() toma
una Lista<T>, pero ¿qué es T?
¿Y qué es eso tan importante antes
del tipo de devolución?

La declaración del método sort()

usted está aquí 539


Machine Translated by Google

tipos genéricos

Los genéricos significan más seguridad de tipos

Antes de los genéricos, no había Con los genéricos, puede crear


SIN genéricos forma de declarar el tipo de
ArrayList, por lo que su método colecciones con seguridad de tipos
Los objetos entran como referencia a add() tomaba el tipo Objeto.
Balón de fútbol, pez, guitarra y donde se detectan más problemas
Objetos de coche
en tiempo de compilación en
lugar de en tiempo de ejecución.

Sin genéricos, el compilador


Lista de arreglo
felizmente le permitiría colocar una

calabaza en una ArrayList que se


Objeto Objeto Objeto Objeto
suponía que debía contener solo
Y SALIR como referencia de tipo Objeto
objetos Cat.

CON genéricos

Los objetos entran como referencia


solo a los objetos Fish

Lista de matrices<pez> Ahora con los genéricos, puedes poner sólo


el
objetos Fish en ArrayList<Fish>, por lo que
los objetos salen como referencias de peces.
No tienes que preocuparte
sobre alguien
por meter un Volkswagen allí, o lo que
que referencia
una obtengas no
de se podrá convertir en
Fish.

Y salir como referencia de tipo Pez

540 capítulo 16
Machine Translated by Google

colecciones con genéricos

Aprender genéricos

1 Crear instancias de clases generificadas (como ArrayList)


nueva ArrayList<Canción>()

2 Declarar y asignar variables de tipos genéricos


Lista<Canción> lista de canciones
= nueva Lista de Array<Canción>()

3 Declarar (e invocar) métodos que toman tipos genéricos

void foo (lista <canción> lista)

[Link] (lista de canciones)

usted está aquí 541


Machine Translated by Google

clases genéricas

Usando CLASES genéricas

Piense en "E" como un sustituto

de "el tipo de elemento que desea


que esta colección contenga y
devuelva". (E es para Elemento.)
Comprender la documentación de ArrayList
(O, ¿cuál es el verdadero significado de “E”?)

La “E” es un marcador de posición para el


ArrayList es una subclase de AbstractList,
Tipo REAL que usas cuando declaras por lo que cualquier tipo que especifique
y creas un ArrayList
para ArrayList se utiliza automáticamente
para el tipo de AbstractList.

la clase pública ArrayList<E> extiende AbstractList<E> implementa List<E> ... {

agregar booleano público (E o)


El tipo (el valor de <E>)
también se convierte en el tipo
¡Aquí está la parte importante! Lo que sea de la interfaz Lista.
que sea "E" determina qué tipo de cosas se le
permite agregar a ArrayList.

// más código
}

542 capítulo 16
Machine Translated by Google

colecciones con genéricos

Usando parámetros de tipo con ArrayList

ESTE código:

ArrayList<String> thisList = nueva ArrayList<String>

Significa ArrayList:

clase pública ArrayList<E> extiende AbstractList<E> ... { exte

agregar booleano público (E o)


// más código
}

El compilador lo trata como:

clase pública ArrayList<String> extiende AbstractList<String>... {

agregar booleano público (cadena o)


// más código
}

usted está aquí 543


Machine Translated by Google

métodos genéricos

Usando MÉTODOS genéricos

1 Usando un parámetro de tipo definido en la declaración de clase

clase pública ArrayList<E> extiende AbstractList<E> ... {


agregar booleano público (E o) Puedes usar

la “E” aquí SÓLO porque es


ya ha sido definido como parte de la clase.

2 Usar un parámetro de tipo que NO estaba definido en la declaración de clase

público <T extiende Animal> void takeThing(ArrayList<T> lista)

Aquí podemos usar <T> porque usamos


declarado
"T" anteriormente en la declaración del método.

544 capítulo 16
Machine Translated by Google

colecciones con genéricos

Espera... eso no puede estar bien. Si


puedes tomar una lista de animales, ¿por
qué no lo dices? ¿Qué hay de malo en simplemente
tomar cosa (lista ArrayList <animal>) ?

Aquí es donde se pone raro...

público <T extiende Animal> void takeThing(ArrayList<T> lista)

takeThing público vacío ( lista ArrayList<Animal>)

usted está aquí 545


Machine Translated by Google

ordenar una canción

Esto todavía no
explica por qué el método de
clasificación falló en una ArrayList de
canciones pero funcionó para una
ArrayList de cadenas...

Recuerda dónde estábamos...


Ayuda de la ventana de edición de archivos

% javac [Link]
[Link]: no se puede encontrar el símbolo
símbolo: método sort([Link]<Song>)
ubicación: clase [Link]
[Link](lista de canciones);
^
1 error

importar [Link].*;
importar [Link].*;

clase pública Jukebox3 {


ArrayList<Canción> lista de canciones = nueva ArrayList<Canción>();
público estático vacío principal (String [] argumentos) {
nuevo Jukebox3().go();
}
public void go() { getSongs();

[Link](lista de canciones); ¡Aquí es donde se rompe! Funcionó bien


[Link](lista de canciones); cuando se pasó un ArrayList<String>, pero tan pronto
[Link](lista de canciones);
como intentamos ordenar un ArrayList<Song>, falló.

} void getCanciones() {
intentar {
Archivo archivo = nuevo archivo ("[Link]");
Lector BufferedReader = nuevo BufferedReader (nuevo FileReader (archivo));
Línea de cadena = nula;
mientras ((línea= [Link]()) != nulo) {
agregarCanción(línea);
}
} captura (Excepción ex) {
[Link]();
}
}
void addSong(String lineToParse) {
String[] tokens = [Link](“/”);
Canción nextSong = nueva canción(tokens[0], tokens[1], tokens[2], tokens[3]);
[Link](siguienteCanción);
}
}

546 capítulo 16
Machine Translated by Google

colecciones con genéricos

Revisando el método sort()

El método sort() sólo puede tomar listas de objetos


comparables .

La canción NO es un subtipo de
Comparable, por lo que no puede ordenar() la
lista de canciones.

Al menos no todavía...

public static <T extiende Comparable<? super T>> clasificación vacía (lista <T> lista)

Puede pasar sólo una Lista (o


(Ignore esta parte por ahora. Pero
Esto dice "Cualquiera que sea la 'T' subtipo de lista, como ArrayList)
si no puede, simplemente que utilice un tipo parametrizado
debe ser de tipo Comparable".
significa que el parámetro de tipo que "extienda Comparable".
para Comparable debe ser del tipo
o uno
T de los supertipos de T).

Um... Acabo de revisar los documentos


para String y String no se EXTIENDE
Comparable: lo IMPLEMENTA.
Comparable es una interfaz. Entonces no tiene
se <T
sentido decir extiende
Comparable>.

clase final pública Cadena extiende Objeto implementa Serializable,


Comparable<Cadena>, CharSequence

usted está aquí 547


Machine Translated by Google

el método ordenar()

En genérico, "extiende"
significa "extiende o implementa"

En genéricos, la palabra clave


"extiende" realmente significa "es­
a" y funciona TANTO para clases
como para interfaces.

Comparable es una interfaz, por lo


que REALMENTE dice: "Debe ser un tipo
que implemente la interfaz Comparable".

public static <T extiende Comparable<? super T>> clasificación vacía (lista <T> lista)

No importa si lo de la derecha es una clase


o una interfaz... igual dices "extiende".

548 capítulo 16
Machine Translated by Google

colecciones con genéricos

Por fin sabemos qué pasa...


La clase Song necesita implementar Comparable

La gran pregunta es: ¿qué hace que la


canción seauno
menor, igual o mayor que la
canción?
otro

No puede implementar la interfaz


[Link] Comparable hasta que tome esa decisión.

interfaz pública Comparable<T> {


int compararA(T o);
}

Afila tu lápiz

Devoluciones:

un entero negativo, cero o un entero positivo


ya que este objeto es menor, igual o mayor
que el objeto especificado.

usted está aquí 549


Machine Translated by Google

la interfaz comparable

La nueva clase Song, mejorada y comparable.

Por lo general, estos coinciden... estamos especificando el tipo


con el que se puede comparar la clase de implementación.

Esto significa que los objetos Song se pueden comparar con


clase Canción implementa Comparable<Canción> {
Título de cadena; otros objetos Song con el fin de clasificarlos.
Artista de cuerdas;
Clasificación de cadena; El método sort() envía una canción a compareTo() para ver
bpm de cadena; cómo se compara esa canción con la canción en la que
se invocó el método.
public int comparar con (canción s) {
devolver tí[Link]([Link]()); ¡Simple! Simplemente pasamos el
trabajo a los objetos String del título,
}
ya que sabemos que los Strings

Canción (Cadena t, Cadena a, Cadena r, Cadena b) {


tienen un método compareTo().
título = t;
artista = a;
calificación = r;
lpm = b;
}

cadena pública getTitle() {


título de devolución;
} Esta vez funcionó. Imprime la lista, luego llama a ordenar,
que coloca las canciones en orden alfabético por título.
public String getArtist() { devolver artista;
Ambiente de ayuda de la ventana de edición de archivos

} %java Jukebox3

cadena pública getRating() {


calificación de retorno; [Luna rosa, salto mortal, luna de Shiva, círculos, profundidad
} Canal, Pasajero, Escuchar]

cadena pública getBpm() {


devolver bpm; [Círculos, Canal profundo, Escuchar, Pasajero, Rosa
} Luna, Luna de Shiva, Salto mortal]

cadena pública toString() {


título de devolución;
}
}

550 capítulo 16
Machine Translated by Google

colecciones con genéricos

Podemos ordenar la lista, pero...


Eso no es lo suficientemente bueno.
A veces quiero que se ordene por
artista en lugar de por título.

Mire la API de la clase Colecciones nuevamente. Hay un


segundo método sort() y requiere un Comparador.

El método sort() está sobrecargado para

tomar algo llamado Comparador.

Nota personal: descubre cómo

conseguir/hacer un Comparador que


pueda comparar y ordenar las

canciones por artista en lugar de por título...

usted está aquí 551


Machine Translated by Google

la interfaz del comparador

Usando un comparador personalizado


[Link]

Comparador de interfaz pública<T> {


int comparar(T o1, T o2);
}

Si pasa un Comparador al
método sort(), el orden de
clasificación lo determina el
Comparador en lugar del propio
método compareTo() del elemento.

Invocar el método sort(List o) de un argumento


significa que el método compareTo() del elemento
de la lista determina el orden. Entonces, los elementos
de la lista DEBEN implementar la interfaz Comparable.

Invocar sort(List o, Comparator c) significa que NO


se llamará al método compareTo() del elemento de
lista, y en su lugar se utilizará el método compare()
del Comparador. Eso significa que los elementos de
la lista NO necesitan implementar la interfaz
Comparable.

552 capítulo 16
Machine Translated by Google

colecciones con genéricos

Actualización del Jukebox para utilizar un comparador

importar [Link].*;
importar [Link].*;

clase pública Jukebox5 {


ArrayList<Canción> lista de canciones = nueva ArrayList<Canción>(); público Cree una nueva clase interna que implemente
estático vacío principal (String [] argumentos) { Comparador (tenga en cuenta que
nuevo Jukebox5().go();
su parámetro de tipo coincide con el tipo que
}
vamos a comparar; en este caso, objetos Song).

clase ArtistCompare implementa Comparador<Canción> {


public int compare(Canción uno, Canción dos) { return
[Link]().compareTo([Link]());
}
} Esto se convierte en una Cuerda (el artista)
Estamos dejando que las variables de cadena (para

public void go() { getSongs(); artista) hagan la comparación real, ya que las cadenas
ya saben cómo ordenarse alfabéticamente.

[Link](lista de canciones);
[Link](lista de canciones);
[Link](lista de canciones);
Cree una instancia de la clase
interna Comparator.
ArtistCompare artistaCompare = nuevo ArtistCompare(); [Link](lista
de canciones, comparación de artistas);
Invoque sort(), pasándole la lista
[Link](lista de canciones); y una referencia al nuevo
}
objeto Comparador personalizado.

void getCanciones() {
// código de E/S aquí
}

void addSong(String lineToParse) {


// analiza la línea y la agrega a la lista de canciones
}
}

usted está aquí 553


Machine Translated by Google

ejercicio de colecciones

importar __________________;
Afila tu lápiz
clase pública OrdenarMontañas {

ListaEnlazada______________ mtn = nueva ListaEnlazada____________();

clase NombreComparar ___________________________________ {


public int compare(Montaña uno, Montaña dos) {

devolver ___________________________; Supongamos que este código


}
existe en un solo archivo. Su
trabajo es completar los espacios
} class HeightCompare public int _______________________________ {
compare(Montaña uno, Montaña dos) {
en blanco para que el programa cree
el resultado que se muestra.
devolver (__________________________);
}

} público estático vacío principal (String [] argumentos) {


nuevo OrdenarMontaña().go();

} público vacío ir() {


[Link](nueva Montaña(“Largos”, 14255)); [Link](nueva
Montaña(“Elbert”, 14433)); [Link](nueva Montaña(“Granate”, 14156));
[Link](nueva Montaña(“Castillo”, 14265));

[Link](“como se ingresó:\n” + mtn);


NombreCompare nc = nuevo NombreCompare();

_________________________________; [Link](“por
nombre:\n” + mtn); Comparación de alturas hc = nueva Comparación de
alturas();

_________________________________; [Link](“por
altura:\n” + mtn);
}
}

clase montaña {

__________________;

_________________;
Ayuda de la ventana de edición de archivos ThisOne'sForBob

%java OrdenarMontañas
______________________ {
como se ingresó:
_________________;
[Largos 14255, Elbert 14433, Granate 14156, Castillo 14265]
_________________;
por nombre:
}

__________________________ { [Castillo 14265, Elbert 14433, Longs 14255, Granate 14156]


por altura:
______________________________;
} [Elbert 14433, Castillo 14265, Longs 14255, Granate 14156]
}

554 capítulo 16
Machine Translated by Google

colecciones con genéricos

Afila tu lápiz

Respuestas posibles:

comparador,

Comparable,

comparar con( ),

comparar( ),

Sí,
No

[Link](myArrayList);

miListaArray

miListaArray

miListaArray
Comparador Comparable

[Link](myArrayList, myCompare);

miListaArray Comparable

miListaArray Comparador

miListaArray Comparable

miListaArray Comparador

miComparar

miComparar

usted está aquí 555


Machine Translated by Google

lidiar con duplicados

UH oh. La clasificación funciona, pero ahora tenemos duplicados...

Ayuda de la ventana de edición de archivos TooManyNotes

%java Jukebox4

[Luna rosa: Nick Drake, Salto mortal: Zero 7, Shiva Moon: Prem Antes de clasificar.
Joshua, Círculos: BT, Canal profundo: Afro Celtas, Pasajero:
Headmix, Escuchar: Tahiti 80, Escuchar: Tahiti 80, Escuchar: Tahiti
80, Círculos: BT]

[Círculos: BT, Círculos: BT, Canal profundo: Afro Celts, Escuche: Después de ordenar
Tahití 80, Escuchar: Tahití 80, Escuchar: Tahití 80, Pasajero: usando el método
Mezcla de cabeza, Pink Moon: Nick Drake, Shiva Moon: Prem Joshua, compareTo() propio de la
Salto mortal: Zero 7] canción (ordenar por título).

[Canal profundo: Afro Celts, Círculos: BT, Círculos: BT, Pasajero:


Mezcla de cabeza, Pink Moon: Nick Drake, Shiva Moon: Prem Joshua, Escucha: Después de ordenar
usando el comparador
Tahití 80, Escuchar: Tahití 80, Escuchar: Tahití 80, Voltereta:
ArtistCompare (ordenar por
Cero 7] nombre de artista).

ListadecancionesMá[Link]

Luna Rosa/Nick Drake/5/80


El archivo de texto SongListMore
Salto mortal/Cero 7/4/84 ahora tiene duplicados
Shiva Luna/Prem Joshua/6/120
porque la máquina de discos está escribiendo cada canción
Círculos/BT/5/110 tres veces seguidas,
reproducidos, en orden. Alguien decidió tocar "Escuchar"
Canal Profundo/Afro Celtas/4/120 que se habían jugado antes.
seguido de “Circles”, una canción
Pasajero/Headmix/4/100
Escuchar/Tahití 80/5/90 No podemos cambiar la
Escuchar/Tahití 80/5/90 forma en que se escribe el
Escuchar/Tahití 80/5/90 archivo de texto porque a veces vamos a necesitar
Círculos/BT/5/110 toda esa información. Tenemos que cambiar el código java.

556 capítulo 16
Machine Translated by Google

colecciones con genéricos

Necesitamos un conjunto en lugar de una lista

Duplicados OK.

LISTA ­ cuando la secuencia importa


Colecciones que conocen la posición del índice.
0 1 23
Las listas saben dónde está algo en la lista. Puede
tener más de un elemento que haga referencia al Lista
mismo objeto.

SET: cuando la unicidad importa NO duplicados.

Colecciones que no permiten duplicados.

Los conjuntos saben si algo ya está en la colección.


Nunca puedes tener más de un elemento que haga referencia
al mismo objeto (o más de un elemento que haga referencia a
dos objetos que se consideran iguales; veremos qué significa
Colocar
igualdad de objetos en un momento).

Los valores duplicados están bien, pero NO hay claves duplicadas.


MAPA: al encontrar algo por cuestiones clave
Colecciones que utilizan pares clave­valor.
Los mapas conocen el valor asociado a una clave determinada.
Puede tener dos claves que hagan referencia al mismo valor, pero no
puede tener claves duplicadas. Aunque las claves suelen ser “Bola” “Pez”
“Bola1” “Bola2” “Coche”
“Pez” “Coche”
nombres de cadenas (para que pueda crear listas de propiedades de
nombre/valor, por ejemplo), una clave puede ser cualquier objeto. Mapa

usted está aquí 557


Machine Translated by Google

la API de colecciones

La API de colección (parte de ella)

Recopilación
(interfaz)

Colocar Lista
(interfaz) (interfaz)

Conjunto ordenado

(interfaz)

Conjunto de árboles LinkedHashSet HashSet Lista de arreglo Lista enlazada Vector

LLAVE

Los mapas no se extienden


desde [Link],
pero todavía se consideran
Conjunto de hash Mapa parte del "marco de
(interfaz) colecciones" en Java. Por
Colocar lo tanto, todavía se hace
referencia a un mapa
como una colección.

Mapa ordenado
(interfaz)

ÁrbolMapa HashMap LinkedHashMap Tabla de picadillo

558 capítulo 16
Machine Translated by Google

colecciones con genéricos

Usando un HashSet en lugar de ArrayList

importar [Link].*;
importar [Link].*;

clase pública Jukebox6 {


ArrayList<Canción> lista de canciones = nueva ArrayList<Canción>(); // método
principal, etc.

vacío público ir () {
No cambiamos getSongs(), por lo que todavía coloca las canciones en una ArrayList
getCanciones();

[Link](lista de canciones);
Aquí creamos un nuevo HashSet
[Link](lista de canciones);
parametrizado para contener canciones.
[Link](lista de canciones);

HashSet<Song> songSet = nuevo HashSet<Song>();


[Link](listadecanciones);
HashSet tiene un método addAll() simple que puede
[Link](conjunto de canciones);
tomar otra colección y usarla para completar el
} HashSet. Es lo mismo que si agregáramos cada
canción una a la vez (excepto que es mucho más simple).
// métodos getSongs() y addSong()
}

Ayuda de la ventana de edición de archivos GetBetterMusic

%java Jukebox6
Antes de
ordenar ArrayList.
[Luna rosa, salto mortal, luna de Shiva, círculos, canal profundo,
Pasajero, Escucha, Escucha, Escucha, Círculos]
Después de
[Círculos, Círculos, Canal Profundo, Escuchar, Escuchar, Escuchar, ordenar ArrayList
Pasajero, Luna Rosa, Luna Shiva, Salto Voltereta] (por título).

[Luna Rosa, Escucha, Luna Shiva, Círculos, Escucha, Canal Profundo,


Después de colocarlo
Pasajero, círculos, escucha, salto mortal] en un HashSet e
imprimir el HashSet
(no volvimos a llamar
¡¡El Set no ayudó!! (Y perdió su orden de clasificación a sort()).
cuando pusimos la lista en un
¡Aún tenemos todos los duplicados!
HashSet, pero nos preocuparemos
de eso más adelante...)

usted está aquí 559


Machine Translated by Google

igualdad de objetos

¿Qué hace que dos objetos sean iguales? Si dos objetos son foo y bar son
iguales y [Link](barra) foo debe ser
verdadero, ambos devuelven el bar debe
mismo valor de
código hash(). Para un set para tratar
dos objetos como duplicados, debes anular los
métodos hashCode() y equals() heredados de
la clase Object, para que puedas hacer que dos
objetos diferentes se vean como iguales.

Igualdad de referencia
Dos referencias, un objeto en el montón.

Dos referencias que hacen referencia al mismo objeto


en el montón son iguales. Período. Si llamas al método hashCode() en ambas
título: Círculos
referencias, obtendrás el mismo resultado. Si no anula el método hashCode(),
código hash: 254
el comportamiento predeterminado (recuerde, lo heredó de la clase Objeto) es
foo
que cada objeto obtendrá un número único (la mayoría de las versiones de Java
asignan un código hash basado en la dirección de memoria del objeto en el
montón, por lo que no habrá dos objetos que tengan el mismo código hash). Canción
bar

Si desea saber si dos referencias realmente se refieren al mismo objeto, use el


Canción
operador ==, que (recuerde) compara los bits en las variables. Si ambas
referencias apuntan al mismo objeto, los bits serán idénticos. si (foo == barra) {

// ambas referencias se refieren // al mismo objeto en


el montón

Igualdad de objetos
título: Círculos
Dos referencias, dos objetos en el montón, pero
código hash: 254
los objetos se consideran significativamente equivalentes.

Si desea tratar dos objetos Song diferentes como iguales (por ejemplo, título: Círculos
si decide que dos canciones son iguales si tienen variables de título código hash: 254
foo
coincidentes ), debe anular los métodos hashCode() y equals() heredados de
la clase Object.

Canción
Como dijimos anteriormente, si no anula hashCode(), el comportamiento
predeterminado (de Objeto) es darle a cada objeto un valor de código hash bar

único. Por lo tanto, debe anular hashCode() para asegurarse de que


dos objetos equivalentes devuelvan el mismo código hash. Pero también
Canción
debes anular el valor igual a() para que si lo llamas en cualquiera de los
objetos y pasas el otro objeto, siempre devuelva verdadero.
si ([Link](bar) && [Link]() == [Link]()) {

// ambas referencias se refieren a un

// un solo objeto, o dos objetos iguales

560 capítulo 16
Machine Translated by Google

colecciones con genéricos

Cómo un HashSet busca duplicados: hashCode() y equals()

Necesito saber si los


Objeto que estás intentando
valores de su código código hash() agregar al HashSet.
hash son los mismos.
título: Círculos
Código hash: 742

foo
742
Canción
Conjunto de hash
código hash()
bar
Objeto que ya está
título: Círculos EN el HashSet.
Canción 742 Código hash: 742

Tus códigos hash son


los mismos, pero ¿eres
El objeto que estás
REALMENTE igual?
es igual (barra) intentando agregar ejecuta
título: Círculos su método equals(),
Código hash: 742 comparándose con la barra y devuelve verdadero.
foo verdadero

Canción

Conjunto de hash

bar
Objeto que ya está EN
título: Círculos el HashSet.
Canción Código hash: 742

usted está aquí 561


Machine Translated by Google

anulando hashCode() y es igual()

La clase Song con hashCode()


y equals() anulados
clase Canción implementa Comparable<Canción>{
Título de cadena;
Artista de cuerdas; El HashSet (o cualquier otra persona que llame
Clasificación de cadena; a este método) le envía otra canción.
bpm de cadena;

La GRAN noticia es que el título es una Cadena y


público booleano es igual (Objeto una canción) {
las Cadenas tienen un método igual a() anulado.
Canción s = (Canción) aCanción;
Entonces todo lo que tenemos que hacer es
return getTitle().equals([Link]());
preguntar un título si es igual al título de la otra canción.
}

público int código hash() {


Lo mismo ocurre aquí... la clase String tiene un método
devolver tí[Link]();
hashCode()
llamando anulado, por lo que puedes devolver el resultado de
a hashCode()
}
en el título. Observe cómo hashCode()
y equals() están usando la MISMA variable de instancia.
public int comparar con (canción s) {
devolver tí[Link]([Link]());
}

Canción (Cadena t, Cadena a, Cadena r, Cadena b) {


título = t;
artista = a; ¡Ahora funciona! No hay duplicados
calificación = r; cuando imprimimos el HashSet. Pero
lpm = b; no volvimos a llamar a sort(), y
}
cuando colocamos ArrayList en
HashSet, HashSet no conservó el orden de clasificación.
cadena pública getTitle() {
título de devolución; Ventana de edición de archivos Ayuda Reiniciar Windows

}
%java Jukebox6
public String getArtist() { devolver artista;

[Luna rosa, salto mortal, luna de Shiva, círculos,


}
Canal Profundo, Pasajero, Escucha, Escucha,
cadena pública getRating() { Escuchen, círculos]
calificación de retorno;
} [Círculos, Círculos, Canal Profundo, Escuchar,
Escucha, Escucha, Pasajero, Luna Rosa, Shiva
cadena pública getBpm() {
devolver bpm;
Luna, salto mortal]
}
[Luna Rosa, Escucha, Luna Shiva, Círculos,
cadena pública toString() {
Canal profundo, pasajero, salto mortal]
título de devolución;
}
}

562 capítulo 16
Machine Translated by Google

colecciones con genéricos

no existen
Preguntas tontas
Ley de objetos de Java para HashCode()
y es igual a()

Los documentos API para la clase Objeto establecen


las reglas que DEBE seguir:

Si dos objetos son iguales, DEBEN tener códigos


hash coincidentes.

Si dos objetos son iguales, llamar a equals()


en cualquiera de los objetos DEBE devolver
verdadero. En otras palabras, si ([Link](b)) entonces
([Link](a)).

Si dos objetos tienen el mismo código hash


valor, NO es necesario que sean iguales.
Pero si son iguales, DEBEN tener el mismo valor de código
hash.

Entonces, si anulas equals(), DEBES


anular el código hash().

El comportamiento predeterminado de
hashCode() es generar un número entero único para
cada objeto en el montón. Entonces, si no anula hashCode()
en una clase, dos objetos de ese tipo NUNCA podrán
considerarse iguales.

El comportamiento predeterminado de equals() es hacer


una comparación ==. En otras palabras, probar si las dos
referencias se refieren a un único objeto en el montón. Entonces,
si no anulas equals() en una clase, dos objetos NUNCA podrán
considerarse iguales, ya que las referencias a dos objetos
diferentes siempre contendrán un patrón de bits diferente.

[Link](b) también debe significar que


[Link]() == b.códigohash()

Pero [Link]() == b.códigohash()


NO tiene por qué significar [Link] igual a(b)

usted está aquí 563


Machine Translated by Google

TreeSets y clasificación

Y si queremos que el conjunto


permanezca ordenado, tenemos TreeSet

importar [Link].*;
importar [Link].*;
clase pública Jukebox8 {
ArrayList<Canción> lista de canciones = nueva ArrayList<Canción>();
valor int;

público estático vacío principal (String [] argumentos) {


nuevo Jukebox8().go();
}

Cree una instancia de un TreeSet en lugar de un HashSet.


public void go() { getSongs(); Llamar al constructor TreeSet sin argumentos significa
que el conjunto utilizará el método compareTo() del
[Link](lista de canciones);
objeto Song para la clasificación.
[Link](lista de canciones);
[Link](lista de canciones); (Podríamos haber pasado en un Comparador).

TreeSet<Song> songSet = nuevo TreeSet<Song>();


[Link](listadecanciones);
[Link](conjunto de canciones); Podemos agregar todas las canciones del HashSet
} usando addAll(). (O podríamos haber agregado
las canciones individualmente usando
void getCanciones() { [Link]() tal como agregamos canciones a ArrayList).
intentar {
Archivo archivo = nuevo archivo ("[Link]");
Lector BufferedReader = nuevo BufferedReader (nuevo FileReader (archivo));
Línea de cadena = nula;
mientras ((línea= [Link]()) != nulo) {
agregarCanción(línea);
}

} captura (Excepción ex) {


[Link]();
}
}

void addSong(String lineToParse) {


String[] tokens = [Link](“/”);
Canción nextSong = nueva canción(tokens[0], tokens[1], tokens[2], tokens[3]);
[Link](siguienteCanción);
}
}

564 capítulo 16
Machine Translated by Google

colecciones con genéricos

Lo que DEBES saber sobre TreeSet...

Afila tu lápiz importar [Link].*;

clase pública TestTree { principal vacío


estático público (String [] args) {
nuevo TestTree().go();
}

vacío público ir () {
Libro b1 = nuevo libro ("Cómo funcionan los gatos");
Libro b2 = nuevo Libro(“Remix your Body”);
Libro b3 = nuevo libro ("Buscando a Emo");

TreeSet<Libro> árbol = nuevo TreeSet<Libro>(); á[Link](b1);


á[Link](b2);
á[Link](b3);
[Link](árbol);

}
}

Libro de clase {
Título de cadena;
Libro público (Cadena t) { título = t;

}
}

usted está aquí 565


Machine Translated by Google

cómo se clasifican los TreeSets

Los elementos de TreeSet DEBEN ser comparables

Para utilizar un TreeSet, una de


estas cosas debe ser cierta:
Los elementos de la lista
deben ser de un tipo que implemente
Comparable

La clase Libro de la página clase Libro implementa Comparable {


anterior no implementó Comparable, por lo Título de cadena;
que no funcionaría en tiempo de ejecución. Libro público (Cadena t) {
Piénselo, el único propósito en la vida del título = t;
pobre TreeSet es mantener sus elementos }

ordenados y, una vez más, ¡no tenía idea de público int comparar con (Objeto b) {
Libro libro = (Libro) b;
cómo ordenar los objetos del Libro! No falla
return (tí[Link](libro.título));
en tiempo de compilación, porque el método
}
TreeSet add() no toma un tipo Comparable. }
El método TreeSet add() toma el tipo que usó
cuando creó el TreeSet. En otras palabras, si
dice new TreeSet<Book>() el método add() es
esencialmente add(Book). ¡Y no es necesario
que la clase Libro implemente Comparable!
Pero falla en tiempo de ejecución cuando agrega el segundo elemento al conjunto.
Esa es la primera vez que el conjunto intenta llamar a

uno de los métodos compareTo() del objeto y... no puede.

O clase pública BookCompare implementa Comparador<Libro> {


Utiliza el constructor sobrecargado public int compare(Libro uno, Libro dos) {
de TreeSet que toma un retorno (uno.tí[Link](dos.título));
Comparador }
}

TreeSet funciona de manera muy prueba de clase {

similar al método sort(): tiene la opción de vacío público ir () {


Libro b1 = nuevo libro ("Cómo funcionan los gatos");
usar el método compareTo() del elemento,
Libro b2 = nuevo Libro(“Remix your Body”);
asumiendo que el tipo de elemento
Libro b3 = nuevo libro ("Buscando a Emo");
implementó la interfaz Comparable, O puede
LibroCompare bCompare = nuevo LibroCompare();
usar un Comparador personalizado que TreeSet<Libro> árbol = nuevo TreeSet<Libro>(bCompare);
sepa cómo ordenar los elementos en el [Link](new Book(“Cómo funcionan los gatos”);
conjunto. . Para utilizar un Comparador [Link](nuevo Libro(“Buscando a Emo”);
[Link](new Book(“Remezcla tu cuerpo”); [Link](tree);
personalizado, llame al constructor TreeSet que toma un Comparador.

}
}

566 capítulo 16
Machine Translated by Google

colecciones con genéricos

Hemos visto Listas y Conjuntos, ahora usaremos un Mapa

valor
Cada elemento en un mapa es en realidad
DOS objetos: a y a llave .
Puedes tener duplicado valoresvalores
, pero
“Bola” “Pez” “Bola3”
“Bola1” “Bola2” “Coche”
“Bola4”
llave
NO duplicado llaves .
Mapa

Ejemplo de mapa
importar [Link].*;
HashMap necesita DOS parámetros de tipo:
uno
mapa de prueba de clase pública { para la clave y otro para el valor.

público estático vacío principal (String [] argumentos) {

HashMap<String, Integer> puntuaciones = new HashMap<String, Integer>();

[Link](“Kathy”, 42); Utilice put() en lugar de add() y ahora, por supuesto,


[Link](“Bert”, 343);
se necesitan dos argumentos (clave, valor).
[Link](“Skyler”, 420);

[Link](puntuaciones);
[Link]([Link](“Bert”));
} El método get() toma una clave y devuelve
} el valor (en este caso, un número entero).

Ayuda de la ventana de edición de archivos WhereAmI

% mapa de pruebas java


Cuando imprimes un mapa, te da la clave = valor, entre
llaves { } en lugar de los corchetes [ ] que ves
{Skyler=420, Bert=343, Kathy=42} al imprimir listas y conjuntos.
343

usted está aquí 567


Machine Translated by Google

tipos genéricos

Finalmente, volvamos a los genéricos.


Si el argumento de un método es de formación
Animales, también tomará una matriz de
cualquier subtipo de Animal.

En otras palabras, si un método se declara


como:

vacío foo(Animal[] a) { }

Suponiendo que Perro extienda Animal, puedes


llamar a ambos:

Así es como funciona con regular matrices:


foo(unAnimalArray); foo(aDogArray);
importar [Link].*;

clase pública TestGenerics1 {


público estático vacío principal (String [] argumentos) {
nuevo TestGenerics1().go();
}
Declare y cree una matriz Animal, que contenga
tanto perros como gatos.
vacío público ir () {
Animal[] animales = {nuevo Perro(), nuevo Gato(), nuevo Perro()};
Perro[] perros = {nuevo Perro(), nuevo Perro(), nuevo Perro()};
tomarAnimales(animales); Declare y cree una matriz Dog, que
tomarAnimales(perros); Llame a takeAnimals(), usando ambos contenga solo Dogs (el compilador
} tipos de matriz como argumentos... no le permitirá colocar un Cat).

public void takeAnimals(Animal[] animales) { El punto crucial es que el método takeAnimals() puede
para(Animal a: animales) {
tomar un Animal[] o un Perro[], ya que Perro ES­UN Animal.
[Link](); Polimorfismo en acción.
}
Recuerde, podemos llamar SÓLO a los métodos declarados en tipo animal, ya
}
} que el parámetro animales es de tipo Matriz animal y no hicimos ningún
casting. (¿A qué lo lanzaríamos?
Esa matriz podría contener tanto perros como gatos).

clase abstracta Animal { void comer() {

[Link](“comer animales”);
}
}
clase Perro extiende Animal {
corteza vacía() { }
La jerarquía de clases Animal simplificada.
}
clase Gato extiende Animal { void miau() { }

568 capítulo 16
Machine Translated by Google

colecciones con genéricos

Usar argumentos polimórficos y genéricos.

Pasando solo ArrayList<Animal>


Un simple cambio de Animal[] a
ArrayList<Animal>.
vacío público ir () {
ArrayList<Animal> animales = new ArrayList<Animal>();
[Link](nuevo Perro());
[Link](new Cat());
Tenemos que agregar uno a la vez ya que no hay una
[Link](nuevo Perro());
sintaxis de acceso directo como la que hay creación.

tomarAnimales(animales);
para matriz. Este es el mismo código, los animales"
}
excepto que ahora variable se refiere a ArrayList en lugar de matriz.

public void takeAnimals(ArrayList<Animal> animales) {


para(Animal a: animales) {
[Link](); El método ahora
} toma un ArrayList
} en lugar de una matriz, pero todo lo demás es
igual. Recuerde que la sintaxis del bucle for
funciona tanto para matrices como para colecciones.

Se compila y funciona bien

Ayuda de la ventana de edición de archivos CatFoodIsBetter

%java PruebaGenerics2

comer animales
comer animales
comer animales
comer animales
comer animales
comer animales

usted está aquí 569


Machine Translated by Google

polimorfismo y genéricos

¿Pero funcionará con ArrayList<Dog>?

Pasando solo ArrayList<Dog>

vacío público ir () {
ArrayList<Animal> animales = new ArrayList<Animal>(); [Link](nuevo Perro());
[Link](new Cat());
[Link](nuevo Perro());
tomarAnimales(animales);

Sabemos que esta línea funcionó bien.

ArrayList<Perro> perros = new ArrayList<Perro>(); [Link](nuevo


Perro()); [Link](nuevo
Perro()); tomarAnimales(perros); Haga una Dog ArrayList y coloque un par de perros.

}
¿Funcionará esto ahora que cambiamos de
una matriz a una ArrayList?

public void takeAnimals(ArrayList<Animal> animales) { for(Animal a: animales) { [Link](); }

Cuando lo compilamos:

Ayuda de la ventana de edición de archivos CatsAreSmarter

%java PruebaGenerics3

[Link]: tomarAnimales([Link].
Parecía tan bien,
ArrayList<Animal>) en TestGenerics3 no se puede aplicar a ([Link]<Dog>)
takeAnimals(dogs); pero salió tan mal...

^
1 error

570 capítulo 16
Machine Translated by Google

colecciones con genéricos

¿Y se supone que debo estar bien con esto? Eso arruina


totalmente mi simulación de animales donde el programa
veterinario toma una lista de cualquier tipo de animal, de
modo que una perrera para perros puede enviar una lista de perros
y una perrera para gatos puede enviar una lista de gatos...
ahora estás diciendo que yo ¿No puedo hacer eso si uso
colecciones en lugar de matrices?

¿Qué podría pasar si eran permitido...

public void takeAnimals(ArrayList<Animal> animales) {


para(Animal a: animales) {
[Link]();
}
}

public void takeAnimals(ArrayList<Animal> animales) {

[Link](new Cat());
¡¡Ay!! Simplemente colocamos un gato en lo que
}
podría ser una ArrayList exclusiva para perros.

usted está aquí 571


Machine Translated by Google

matrices frente a ArrayLists

Espera un minuto... si es por eso que no te permiten


pasar un Dog ArrayList a un método que
toma una Animal ArrayList, para evitar que puedas poner
un gato en lo que en realidad era una lista de perros, entonces
¿por qué funciona con ? ¿No tienesmatrices
el mismo problema con las
matrices? ¿Aún no puedes agregar?
¿Un objeto Cat para un perro []?

Los tipos de matriz se verifican nuevamente en


tiempo de ejecución, pero las verificaciones de tipo
de colección ocurren solo cuando se compila

vacío público ir () {
Perro[] perros = {nuevo Perro(), nuevo Perro(), nuevo Perro()};
tomarAnimales(perros);
}

public void takeAnimals(Animal[] animales) {


animales[0] = nuevo Gato();
} Ponemos un nuevo Gato en una matriz de
Perros. El compilador lo permitió, porque sabe
que es posible que haya pasado una matriz Cat o
una matriz Animal al método, por lo que para el
compilador era posible que esto estuviera bien.

Se compila, pero cuando lo ejecutamos:

Ayuda de la ventana de edición de archivos CatsAreSmarter

%java PruebaGenerics1
Excepción en el hilo "principal" [Link]: Cat
¡Uf! Al menos la
JVM lo detuvo. en [Link]([Link])
en [Link] ([Link])
en [Link]([Link])

572 capítulo 16
Machine Translated by Google

colecciones con genéricos

¿No sería fantástico si hubiera una manera


de seguir usando tipos de colecciones
polimórficas como argumentos de método, de
modo que mi programa veterinario pudiera
aceptar listas de perros y gatos? De esa manera
podría recorrer las listas y llamar a su método
immunize(), pero aún así tendría que ser seguro
para que no pudieras agregar un Gato a la lista
de Perros. Pero supongo que eso es sólo una fantasía...

usted está aquí 573


Machine Translated by Google

comodines genéricos

Comodines al rescate

public void takeAnimals(ArrayList<? extiende Animal> animales) {


para(Animal a: animales) {
[Link](); Recuerde, la palabra clave
} "extiende" aquí significa
}
extiende O implementa
según el tipo. Entonces, si
deseas tomar una ArrayList
de tipos que implementen la
interfaz Pet, deberás declararla como:

ListaMatriz<? extiende mascota>

Cuando utiliza un comodín en el argumento de su método, el


compilador le impedirá hacer cualquier cosa que pueda dañar la lista a la
que hace referencia el parámetro del método.

Aún puedes invocar métodos en los elementos en


la lista, pero no puede agregar elementos a la lista.

con de la lista,
En otras palabras, puedes hacer cosas con los elementos
pero no puedes poner cosas en la lista. nuevo
Así que estás seguro en tiempo de ejecución, porque el compilador no te
permitirá hacer nada que pueda ser horrible en tiempo de ejecución.

Entonces, esto está bien dentro de takeAnimals():

para(Animal a: animales) {
[Link]();
}

Pero ESTO no compilaría:

[Link](new Cat());

574 capítulo 16
Machine Translated by Google

colecciones con genéricos

Sintaxis alternativa para hacer lo mismo

Este:
público <T extiende Animal> void takeThing(ArrayList<T> lista)

Hace lo mismo que esto:


takeThing público vacío (ArrayList<? extiende la lista Animal>)

no existen
Preguntas tontas

público <T extiende Animal> void takeThing(ArrayList<T> uno, ArrayList<T> dos)

public void takeThing(ArrayList<? extiende Animal> uno,


ListaMatriz<? extiende Animal> dos)

usted está aquí 575


Machine Translated by Google

ser el ejercicio compilador

ArrayList<Perro> perros1 = new ArrayList<Animal>();

ArrayList<Animal> animales1 = new ArrayList<Perro>();

Lista<Animal> lista = nueva ArrayList<Animal>();

ArrayList<Perro> perros = new ArrayList<Perro>();

ArrayList<Animal> animales = perros;

Lista<Perro> listaperro = perros;

ArrayList<Objeto> objetos = nuevo ArrayList<Objeto>();

Lista<Objeto> objList = objetos;

ArrayList<Objeto> objs = nuevo ArrayList<Perro>();

576 capítulo 16
Machine Translated by Google

colecciones con genéricos

importar [Link].*;

clase pública OrdenarMontañas {

LinkedList<Montaña> mtn = new LinkedList<Montaña>();

clase NameCompare implementa Comparador <Montaña> { public int


comparar(Montaña uno, Montaña dos) {

devolver [Link]([Link]);
}
}

class HeightCompare implements Comparator <Montaña> { public int compare(Montaña


uno, Montaña dos) {

retorno ([Link] ­ [Link]);


}

} public static void main(String [] args) { new SortMountain().go(); ¿Notaste que la lista de alturas está
en secuencia DESCENDENTE? : )

} público vacío ir() {


[Link](nueva Montaña(“Largos”, 14255)); [Link](nueva
Montaña(“Elbert”, 14433)); [Link](nueva Montaña(“Granate”,
14156)); [Link](nueva Montaña(“Castillo”, 14265));

[Link](“como se ingresó:\n” + mtn); NombreCompare


nc = nuevo NombreCompare();

[Link](mtn, nc);
[Link](“por nombre:\n” + mtn); Comparación de
alturas hc = nueva Comparación de alturas();

[Link](mtn, hc);
[Link](“por altura:\n” + mtn);
}
}

clase montaña {

Nombre de cadena;

altura interna;
Ayuda de la ventana de edición de archivos ThisOne'sForBob

%java OrdenarMontañas
Montaña(Cadena n, int h) { como se ingresó:
nombre = n;
[Largos 14255, Elbert 14433, Granate 14156, Castillo 14265]
altura = h; por nombre:

[Castillo 14265, Elbert 14433, Longs 14255, Granate 14156]


} public String toString() { + altura; por altura:
““
devolver nombre +
[Elbert 14433, Castillo 14265, Longs 14255, Granate 14156]
}

usted está aquí 577


Machine Translated by Google

solución para llenar los espacios en blanco

Respuestas posibles:

comparador,
Comparable,
comparar con( ),

comparar( ),
Sí,
No

[Link](myArrayList);

miListaArray Comparable
miListaArray comparar con( )
miListaArray
Comparador Comparable Sí

[Link](myArrayList, myCompare);

miListaArray Comparable si

miListaArray Comparador si

miListaArray No comparable

miListaArray Comparador no

miComparar Comparador
miComparar comparar( )

578 capítulo 16
Machine Translated by Google

colecciones con genéricos

ArrayList<Perro> perros1 = new ArrayList<Animal>();

ArrayList<Animal> animales1 = new ArrayList<Perro>();

Lista<Animal> lista = nueva ArrayList<Animal>();

ArrayList<Perro> perros = new ArrayList<Perro>();

ArrayList<Animal> animales = perros;

Lista<Perro> listaperro = perros;

ArrayList<Objeto> objetos = nuevo ArrayList<Objeto>();

Lista<Objeto> objList = objetos;

ArrayList<Objeto> objs = nuevo ArrayList<Perro>();

usted está aquí 579


Machine Translated by Google
Machine Translated by Google

17 paquetes, frascos e implementación

Libera tu código

Es hora de dejarlo ir.

este es un nuevo capitulo 581


Machine Translated by Google

Implementación de Java

Implementando su aplicación

Un programa Java es un
conjunto de clases. Ese

es el resultado de su desarrollo.

La verdadera pregunta es qué


Opciones de implementación hacer con esas clases
HTTP
Vista de edición de archivos

Vista de edición de archivos

HTTP
Vista de edición de archivos
cuando hayas terminado.
RMI
servlets
Ejecutable
Frasco
Inicio web Aplicación RMI

100% locales Combinación 100% Remoto

1 locales
La aplicación completa se ejecuta en la
computadora del usuario final, como un programa
independiente, probablemente GUI,
implementado como un JAR ejecutable (veremos
el JAR en unas pocas páginas).
Barra cerebral
cerebro
con barra

2 Combinación de local y remoto


La aplicación se distribuye con una parte del
cliente que se ejecuta en el sistema local
del usuario, conectada a un servidor donde
se ejecutan otras partes de la aplicación.

3 Remoto
Toda la aplicación Java se ejecuta en un
sistema servidor, y el cliente accede al sistema a
través de algún medio que no sea Java,
probablemente un navegador web.

582 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

¡Finalmente está hecho!


Imagínate este escenario...

es

Que... ?

usted está aquí 583


Machine Translated by Google

organizando tus clases

Separe el código fuente y los archivos de clase

Pero pensé que no tenía


opción de colocar los archivos de
clase con los archivos fuente.
Cuando compilas, simplemente ir
están ahí, entonces, ¿qué hago?

­d

­d

Compilando con el indicador ­d (directorio)

%cd MiProyecto/fuente
%javac ­d ../clases MiAplicació[Link]
Mi proyecto
le dice al compilador que coloque el lo último sigue siendo el
código compilado (archivos de clase) El código compilar desde
nombre del archivo java compilado llega aquí. ESTE directorio
en el directorio “clases: que es un a compilar
directorio arriba y abajo nuevamente
desde el directorio de trabajo actual.

­d clases fuente

ejecuta tu principal()
desde aquí Lorper iure
101101
eugue
%javac ­d ../clases *.java 101101
10101000010 tatuaje vero
consenso
1010 10 0
01010 1 eugueroLore do

*.java compila TODOS 1010101


10101010
eliquis do del
dip

Ejecutando tu código los archivos fuente 1001010101

en el directorio actual MiAplicació[Link]


MiAplicació[Link]

%cd MiProyecto/clases
(nota de solución de problemas: todo en este capítulo supone que el
%javamini ejecuta tu programade directorio de trabajo actual (es decir, el “.”) está en su classpath. Si ha
configurado explícitamente una variable de entorno classpath,
el directorio 'clases'. asegúrese de que contenga el “.”)
584 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

Pon tu Java en un JAR

FRASCO

Hacer un JAR ejecutable Mi proyecto

1 Asegúrate de que todos los archivos de tu clase estén en 101101


101101
101101
10101000010

el directorio de clases 1010101101


01010
10 0
10101000010
1010101
1
1010 10 0
101101
Vamos a refinar esto en unas pocas páginas, pero 10101010
01010 1
101101
clases 1010101
1001010101
10101000010
por ahora, mantenga todos sus archivos de clase 1010 10101010
10 0
010101010101
1

en el directorio llamado 'clases'. 1010101


10101010
1001010101

MiAplicació[Link]

2 Cree un archivo [Link] que indique


qué clase tiene el método main()
Cree un archivo de texto llamado [Link] que tenga Clase principal: MyiApp Mi proyecto
una línea:
no pongas el .class al
Clase principal: MyApp final
101101
101101
101101
101101
101101

Presione la tecla Intro después de escribir la línea clases 101101

Main­Class o es posible que su manifiesto no


funcione correctamente. Coloque el archivo de manifiesto en [Link] Clase principal: MiniApp

el directorio "clases".

[Link]

3 Ejecute la herramienta jar para crear un archivo JAR que


clases
contenga todo el contenido del directorio de clases,
además del manifiesto. 101101
101101
101101
101101
101101

%cd MiniProject/clases %jar ­cvmf 101101


sin fuentes
[Link] [Link] *.clase Clase principal: MiniApp

O código (.java)
en el JAR
%jar ­cvmf [Link] [Link] MiAplicació[Link]
aplicació[Link]

usted está aquí 585


Machine Translated by Google

tarro ejecutable

Vista de edición de archivos


Vista de edición de archivos
Vista de edición de archivos

HTTP
Vista de edición de archivos

HTTP RMI La mayoría de las aplicaciones


Ejecutable
cliente GUI Inicio Web Aplicación RMI servlets
Frasco Java 100% locales se

100% locales Combinación 100% Remoto implementan como archivos JAR ejecutables.

Ejecutando (ejecutando) el JAR

La JVM tiene que "ver" el JAR, por lo


que debe estar en su classpath. La
forma más sencilla de hacer visible el
JAR es hacer que su directorio de
trabajo sea el lugar donde se encuentra el JAR.
clases
%cd MiProyecto/clases
101101
101101
101101
101101
101101
101101 %java ­jar aplicació[Link]

La JVM busca dentro de este JAR un manifiesto


Clase principal: MiniApp

El indicador ­jar le dice a la con una entrada para Main­Class. Si no


aplicació[Link] JVM que le estás dando encuentra uno, obtienes
un JAR en lugar de una clase. una excepción de tiempo de ejecución.

no existen
Preguntas tontas

586 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

¡Pon tus clases en paquetes!

Estructura de paquete de la API de Java para:

[Link]

[Link]

[Link]

[Link]
Los paquetes evitan conflictos de nombres de clases
[Link]

Java

neto
texto
101101 10
1001 101 10
10 10010
101 101
101 101 101 101101 10

awt 1001 101 10 10


10010
101 101

Formato numérico
útil
101 101 101

Enchufe
101101 10

evento
101101 10 1001 101 10
1001 101 10 10 10010
10 10010 101 101
101 101 101 101 101
101 101 101

Lista de arreglo
Diseño de flujo
101101 10
1001 101 10
10 10010
101 101
101 101 101

Evento de acción

¿Qué te parece esta imagen? ¿No se


parece mucho a una jerarquía de directorios?

usted está aquí 587


Machine Translated by Google

denominación de paquetes

...así que finalmente me


decidí por [Link] ¡Ese es el mismo nombre que
para mi clase de horneado cuántico estaba pensando para mi clase
de planchado subatómico!
Supongo que tendré que pensar en
algo más.

Los paquetes pueden evitar


conflictos de nombres, pero
solo si elige un nombre
de paquete que garantice
que sea único. La mejor
Prevención de conflictos de nombres de paquetes manera de hacerlo es
anteponer sus paquetes con
su nombre de dominio inverso.

[Link]
Nombre del paquete nombre de la clase

Nombres de paquetes de dominio inverso el nombre de la clase siempre

está en mayúscula
[Link]áfico

Inicie el paquete con su dominio [Link] puede ser un nombre

inverso, separado por un punto común, pero agregar [Link]


(.), luego agregue su propia significa que solo tenemos que preocuparnos
estructura organizativa después de eso. de nuestros propios desarrolladores internos.

588 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

Para poner tu clase en un paquete:


Debe colocar una clase en una
1 Elija un nombre de paquete estructura de directorios
Estamos usando [Link] rstjava como
ejemplo. El nombre de la clase es PackageExercise,
que coincida con la jerarquía de
por lo que el nombre completo de la clase ahora
es: [Link] [Link]. paquetes.

2 Pon una declaración de paquete en tu clase.


Debe ser la primera declaración en el archivo de código
fuente, encima de cualquier declaración de importación. Sólo
puede haber una declaración de paquete por archivo de
código fuente, por lo que todas las clases en un archivo Mi proyecto
fuente deben estar en el mismo paquete. Eso incluye las
clases internas, por supuesto.

paquete [Link];

importar [Link].*;
clases fuente
clase pública PaqueteExercise {
// código que cambia la vida aquí
}

com com
3 Configure una estructura de directorio coincidente
No basta con que su clase
decir
esté en un paquete, simplemente
colocando una declaración de paquete en el código. Su
clase no está en un paquete hastarealmente
que coloque la clase
estructura
paquete

en una estructura de directorio coincidente. Entonces, si el


nombre de la clase totalmente calificada es [Link] cabezaprimerajava
del

cabezaprimerajava
[Link], usted
debe coloque el código fuente de PackageExercise en un
debe
directorio llamado headfi rstjava, que estará en un directorio
llamado com.
Lorper iure
Se trata de compilar sin hacer eso, pero créanos: no vale la
posible
101101
101101
eugue
tatuaje vero
10101000010
pena los demás problemas que tendrás. Mantenga su 1010 10 0
consenso

eugueroLore do
01010 1
eliquis do del
código fuente en una estructura de directorios que coincida 1010101
10101010
dip

con la estructura del paquete y evitará un montón de dolores 1001010101

de cabeza en el futuro. [Link] [Link]

Configure una estructura de directorio coincidente


para los árboles de origen y de clases.

usted está aquí 589


Machine Translated by Google

compilar y ejecutar con paquetes

Compilando y ejecutando paquetes

Compilando con el indicador ­d (directorio)


¡Quédese en el directorio fuente! ¡NO baje al
%cd MiProyecto/fuente directorio donde está el archivo .java!

%javac ­d ../classes com/headfirstjava/[Link]

¡Le dice al compilador que coloque Ahora debe especificar


el código compilado (archivos la RUTA para llegar al
de clase) en el directorio de archivo fuente real.
clases, dentro de la estructura Mi proyecto
de paquete correcta! Sí, lo sabe. todavía compilarás
de aquí
todavía
huirás de aquí

%javac ­d ../classes com/headfirstjava/*.java clases fuente

compila todos los archivos fuente


(.java) en este directorio

Ejecutando tu código com com

ejecuta tu programa de
%cd MiProyecto/clases el directorio 'clases'.

%java [Link]
cabezaprimerajava cabezaprimerajava

¡DEBES dar el nombre de la clase completamente calificado! 101101 loper iure


10 110 1
La JVM verá eso e inmediatamente buscará dentro de su 0 11 0 euge

directorio actual (clases) y esperará encontrar un directorio


tatuaje vero
001 10
consenso
001 01
euguero­
llamado com, donde espera encontrar un directorio llamado
[Link] [Link]
headfirstjava, y allí espera encontrar la clase. Si la clase está en
el directorio “com”, o incluso en “clases”, ¡no funcionará!

590 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

La bandera ­d es incluso más genial de lo que dijimos. no existen


Preguntas tontas
­d

Mi proyecto

clases fuente

com %java [Link]


Si la estructura del directorio del paquete
no existe en el directorio 'clases', el
compilador creará los directorios si usa el
indicador ­d.
cabezaprimerajava
Por lo tanto, no es necesario crear
físicamente los directorios en el directorio raíz
'clases'. Y, de hecho, si dejas que el
compilador lo haga, no hay posibilidad loper iure

de que se produzca un error tipográfico. eugue tat


vero
consenso

euguero­

[Link]

La bandera ­d le dice al compilador: “Coloque


la clase en la estructura de directorios de su
paquete, usando la clase especificada
después de ­d como directorio raíz. Pero... si
los directorios no están allí, créelos primero y
coloque la clase en el lugar correcto”.
entonces

usted está aquí 591


Machine Translated by Google

JAR y paquetes

Hacer un JAR ejecutable con paquetes

FRASCO

clases
Hacer un JAR ejecutable

1 Asegúrese de que todos sus archivos de


clase estén dentro de la estructura de com

paquete correcta, en el directorio de clases.


101101
10 110 1 0
11 0
cabezaprimerajava 001 10
001 01

[Link]

2 Cree un archivo [Link] que indique qué


clase tiene el método main() y asegúrese Clase principal: MiniApp

clases
de utilizar el nombre de clase completo.

[Link]
Cree un archivo de texto llamado [Link] que tenga
com
una sola línea:
Clase principal: [Link]
101101
10 110 1 0

Coloque el archivo de manifiesto en el directorio de clases. cabezaprimerajava


11 0 001
10
001 01

[Link]

3 Ejecute la herramienta jar para crear un archivo


clases
JAR que contenga los directorios del paquete
más el manifiesto.
com
Lo único que necesita incluir es el
directorio 'com' y todo el paquete (y todas las ¡Todo lo que especifica
clases) irá al JAR. es el directorio com! ¡Y 101101
10 110 1 0
11 0 001
%cd MiProyecto/clases obtendrás todo lo que contiene!
[Link]
cabezaprimerajava 10 001
01

%jar ­cvmf [Link] [Link] com [Link]

592 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

Entonces, ¿a dónde fue el archivo de manifiesto?

Colocamos el archivo JAR en


un directorio llamado Skyler.

skyler

Comandos jar para listar y extraer

1 Enumerar el contenido de un JAR

% jar ­tf [Link]


[Link]
­tf significa 'Archivo de tabla' como
en "muéstrame una tabla del archivo JAR"
la herramienta jar crea automáticamente

Ayuda de la ventana de edición de archivos Pickle

un directorio META­INF y coloca el


% CD Skyler manifiesta en su interior.
% jar ­tf [Link]
META­INF/ META­INF com
META­INF/[Link]
com/
es/headfirstjava/
Clase principal: MiniApp

es/headfirstjava/
[Link] cabezaprimerajava

[Link]

101101
10 110 1
0 11 0
001 10
001 01

2 Extraer el contenido de un JAR (es decir, unjar)


% CD Skyler [Link]

% jar ­xf [Link]


skyler
META­INF significa
"metainformación". La herramienta
­xf significa 'Extraer archivo' y funciona jar crea el directorio META­INF
igual que descomprimir o descomprimir. META­INF com así como el archivo [Link].
Si extrae [Link], verá el directorio También toma el contenido del
META­INF y el directorio com en su
su archivo de manifiesto y lo
directorio actual Clase principal: MiniApp

coloca en el archivo [Link].


cabezaprimerajava
su Entonces, el manifiesto no va al
archivo
[Link]
contenido
JAR, pero sus componentes se
101101
10 110 1
0 11 0
colocan en el manifiesto "real"
([Link]).
001 10
001 01

[Link]

usted está aquí 593


Machine Translated by Google

organizando tus clases

Afila tu lápiz

Mi proyecto

Clase principal: MiniApp

clases fuente

[Link]

javarancho javarancho Compilar:


fuente %cd
% javac ________________________________
vacas vacas

Correr:
101101
loper
10 110 1 0
11 0 001
iure
euge
%cd ___________
10 tatuaje vero
001 01 consenso

euguero­
%Java _________________________________
clase foof
[Link]

Crear un frasco
%cd ___________

%______________________________________

Ejecutar un JAR
%cd ___________

% _____________________________________

594 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

no existen
Preguntas tontas
PUNTOS DE VIÑETA

Organice su proyecto para que su código fuente y archivos de clase no estén en el


mismo directorio.

Una estructura organizativa estándar consiste en crear un directorio de proyecto y luego


colocar un directorio de origen y un directorio de clases dentro del directorio del proyecto.

Organizar sus clases en paquetes evita colisiones de nombres con otras clases, si
antepone su nombre de dominio inverso al frente del nombre de una clase.

Para poner una clase en un paquete, coloque una declaración de paquete en la parte
superior del archivo de código fuente, antes de cualquier
declaración de importación: paquete [Link];

Para estar en un paquete, una clase debe estar en una estructura de directorios que
coincida exactamente con la estructura del paquete. Para una clase,
[Link], la clase Foo debe estar en un directorio llamado Wickedlysmart,
que está en un directorio llamado com.

Para que su clase compilada aterrice en la estructura de directorio de paquetes


correcta en el directorio de clases , use el indicador del compilador ­d : %
cd source

% javac ­d ../classes com/wickedlysmart/[Link]

Para ejecutar su código, vaya al directorio de clases y proporcione el nombre completo de su


clase: % cd clases

% java [Link]

Puede agrupar sus clases en archivos JAR (Java ARchive). JAR se basa en el formato
pkzip.

Puede crear un archivo JAR ejecutable colocando un manifiesto en el JAR que indique
qué clase tiene el método main(). Para crear un archivo de manifiesto, cree un archivo
de texto con una entrada como la siguiente (por ejemplo): Clase principal:
[Link]

Asegúrese de presionar la tecla Intro después de escribir la línea Main­Class, o es posible que

su archivo de manifiesto no funcione.

Para crear un archivo JAR,


escriba: jar ­cvfm [Link] [Link] com

Toda la estructura de directorios del paquete (y solo los directorios que coinciden con el
paquete) deben estar inmediatamente dentro del archivo JAR.

Para ejecutar un archivo JAR ejecutable,


escriba: java ­jar [Link]

usted está aquí 595


Machine Translated by Google

¿No sería un sueño...?

Los archivos JAR


ejecutables son buenos, pero ¿no sería
fantástico si hubiera una manera de crear una
GUI de cliente rica e independiente que pudiera
distribuirse a través de la Web? Para que no tengas
que imprimir y distribuir todos esos CD­ROM. ¿Y no
sería simplemente maravilloso si el programa
pudiera actualizarse automáticamente,
reemplazando sólo las piezas que cambiaron?
Los clientes siempre estarán actualizados y usted
nunca tendrá que preocuparse por entregar nuevos

596 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

Vista de edición de archivos


Vista de edición de archivos

Vista de edición de archivos

HTTP Vista de edición de archivos

HTTP RMI HTTP

Ejecutable
Inicio
InicioWeb
Web Aplicación RMI
servlets
Frasco

100% locales Combinación 100% Remoto


Los usuarios finales inician una

aplicación Java Web Start


Inicio web de Java
haciendo clic en un

enlace en una página web.


Pero una vez que la aplicación

se descarga, se ejecuta fuera del


navegador, como cualquier

otra aplicación Java

independiente. De hecho, una


aplicación Java Web Start es
simplemente un JAR ejecutable que se distribu

usted está aquí 597


Machine Translated by Google

Inicio web de Java

Cómo funciona Java Web Start


navegador web

Servidor web
1 El cliente hace clic en el enlace de una
página web a su aplicación JWS (un archivo .jnlp). “dame [Link]” Lorper iure
hacer clic eugue

tat vero

El enlace de la página web consenso

euguero­

<a href=”[Link]”>Haga clic</a> MiAplicació[Link] MiAplicació[Link]

2 El servidor web (HTTP) recibe la Servidor web


solicitud y devuelve un archivo .jnlp loper
loper

(este NO es el JAR).
hacer clic iure
iure
euge
tatuaje vero euge
tatuaje vero
consenso
consenso
euguero­
El archivo .jnlp es un documento XML que euguero­

MiAplicació[Link]
indica el nombre del archivo JAR MiAplicació[Link] MiAplicació[Link]

ejecutable de la aplicación.

Inicio web de Java

3 El navegador inicia Java Web Start (una


Servidor web
pequeña 'aplicación auxiliar' en el “dame [Link]”
JWS
cliente). La aplicación auxiliar JWS lee el loper
iure

archivo .jnlp y solicita al servidor el archivo


euge
tatuaje vero
consenso

[Link]. euguero­

MiAplicació[Link] MiAplicació[Link]

4 El servidor web 'sirve' el archivo .jar


Servidor web
solicitado. JWS
Lorper iure
eugue

tat vero

consenso

euguero­
MiAplicació[Link]
MiAplicació[Link] MiAplicació[Link]

HelloWebStart (la aplicación en el JAR)


5 Java Web Start obtiene el JAR e
inicia la aplicación llamando al Servidor web
método main() especificado (como un Hola
Lorper iure

JAR ejecutable). eugue

tat vero

consenso

La próxima vez que el usuario quiera ejecutar esta euguero­

aplicación, puede abrir la aplicación Java Web Start MiAplicació[Link] MiAplicació[Link]

y desde allí iniciar la aplicación, sin siquiera estar en línea.

598 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

El archivo .jnlp

La etiqueta 'codebase' es donde especificas la 'raíz' de


dónde se encuentran tus elementos de inicio web en el servidor.
<?xml versión=”1.0” codificación=”utf­8”?> Estamos probando esto en nuestro host local, por lo que
usamos la dirección de loopback local "[Link]". Para
aplicaciones de inicio web en nuestro servidor web de
Internet, esto diría: "[Link]
<especificación jnlp =”0.2 1.0”

base de código =”[Link]


Esta es la ubicación del archivo .jnlp en relación con el código
href=”MiAplicació[Link]”> base. Este ejemplo muestra que [Link] está disponible
en el directorio raíz del servidor web, no anidado en ningún otro
directorio.

<información>

<título>Aplicación kathy</título> ¡Asegúrese de incluir todas estas etiquetas o su aplicación podría


no funcionar correctamente! La aplicación auxiliar JWS utiliza las
<vendor>Perversamente inteligente</vendor> etiquetas de 'información', principalmente para mostrar cuando el
usuario desea reiniciar una aplicación descargada anteriormente.
<página de inicio href=”[Link]”/>

<description>Demostración de Head First WebStart</description>

<icon href=”[Link]”/>

<permitido sin conexión/> Esto significa que el usuario puede ejecutar su programa sin
estar conectado a Internet. Si el usuario no está conectado, significa
</información> que la función de actualización automática no funcionará.

<recursos>
Esto dice que tu aplicación necesita la versión 1.3.
<j2se versión=”1.3+”/> de Java, o superior.

<jar href=”MiAplicació[Link]”/> El nombre


</recursos> de tu JAR ejecutable! Es posible que también
tengas otros archivos JAR que contengan otras clases o
incluso sonidos e imágenes utilizados por tu aplicación.

<application­desc main­class=”HolaWebStart”/>

</jnlp> Esto es como la entrada principal de Mainfest...


dice qué clase en el JAR tiene el método main().

usted está aquí 599


Machine Translated by Google

implementando con JWS

Pasos para crear e implementar una


aplicación Java Web Start
1 Cree un JAR ejecutable para
su aplicación.

MiAplicació[Link]

loper iure

2 Escriba un archivo .jnlp. euge


tatuaje vero
consenso

euguero­

MiAplicació[Link]

3 Coloque sus archivos JAR Servidor web


y .jnlp en su servidor web. Lorper iure
eugue

tat vero
Lorper <iure
consenso

euge euguero­
tatuaje vero
consenso [Link]

MiAplicació[Link] MiAplicació[Link]

4 Agregue un nuevo tipo mime a su servidor web.


Servidor web
aplicación/archivo x­java­jnlp
configurar
Esto hace que el servidor envíe el archivo .jnlp con el el tipo mime
encabezado correcto, de modo que cuando el navegador
reciba el archivo .jnlp sepa qué es y sepa cómo iniciar
la aplicación auxiliar JWS.

Lorper iure
eugue

5 Cree una página web con un enlace a tat vero

su archivo .jnlp
consenso

euguero­

[Link]
<HTML>
<CUERPO>

<a href=”[Link]”>Iniciar mi aplicación</a> </BODY>

</HTML>

600 capitulo 17
Machine Translated by Google

paquete, frascos y despliegue

el servidor web envía un archivo


JAR a la aplicación auxiliar JWS
el navegador web inicia la
aplicación auxiliar JWS
la aplicación auxiliar JWS solicita
el archivo JAR
la aplicación auxiliar JWS invoca
el servidor web envía un
archivo .jnlp al navegador el método main() del JAR

El usuario hace clic en el enlace de una página web. El navegador solicita un


archivo .jnlp del servidor web.

no existen
Preguntas tontas
PUNTOS DE VIÑETA

La tecnología Java Web Start le permite implementar


una aplicación cliente independiente desde la Web.

Java Web Start incluye una 'aplicación auxiliar' que debe


instalarse en el cliente (junto con Java).

Una aplicación Java Web Start (JWS) consta de dos partes:


un JAR ejecutable y un archivo .jnlp.

Un archivo .jnlp es un documento XML simple


que describe su aplicación JWS. Incluye etiquetas
para especificar el nombre y la ubicación del JAR y el
nombre de la clase con el método main().

Cuando un navegador obtiene un archivo .jnlp del


servidor (porque el usuario hizo clic en un enlace al
archivo .jnlp), el navegador inicia la aplicación auxiliar JWS.

La aplicación auxiliar JWS lee el archivo .jnlp y


solicita el JAR ejecutable desde la Web
servidor.

Cuando el JWS obtiene el JAR, invoca el método


main() (especificado en el archivo .jnlp).

usted está aquí 601


Machine Translated by Google

ejercicio: Verdadero o Falso

602 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

Resumen­Cross 7.0

usted está aquí 603


Machine Translated by Google

soluciones de ejercicio

El usuario hace clic en el enlace de una página web.

El navegador solicita un
archivo .jnlp del servidor web.

el servidor web envía un


archivo .jnlp al navegador

el navegador web inicia la


aplicación auxiliar JWS

la aplicación auxiliar JWS solicita


el archivo JAR

el servidor web envía un archivo


JAR a la aplicación auxiliar JWS

la aplicación auxiliar JWS


invoca el método main() del JAR

Verdadero

FALSO

FALSO

Verdadero

FALSO

FALSO

Verdadero

FALSO

FALSO

FALSO

Verdadero

Verdadero

Verdadero

Verdadero

FALSO

FALSO

FALSO

604 capítulo 17
Machine Translated by Google

paquete, frascos y despliegue

Resumen­Cross 7.0

DOGTMTRANSIENTW
I BATÓMICR oh I
AJARKNSINCRONIZADO
l EBE t t GRAMO

OCHAINEDR S AHORRAR
GETG EJECUTABLECT
S mi Pensilvania AU CS
B FILTRO DE IMPLEMENTACIÓN
BRN oh I F SUDOESTE
DIRECTORIO USUARIO DE ENCHUFE
NAE t PR A
PAQUETE CLASE BUCLE PAG

R mi LTL R PAG

BYTERESTOREEXTREME
AI ES EMXR
MANIFESTACIONES CAPSULAS

usted está aquí 605


Machine Translated by Google
Machine Translated by Google

18 implementación remota con RMI

Repartido
Todo el mundo dice

Informática que las relaciones a distancia son


difíciles, pero con RMI es fácil.
No importa qué tan lejos en realidad

estemos, RMI hace que parezca


parecer
que estamos juntos.

Ser remoto no tiene por qué ser algo malo.

este es un nuevo capitulo 607


Machine Translated by Google

cuantos montones

Vista de edición de archivos

Vista de edición de archivos

Vista de ediciónVista de edición de archivos


de archivos

HTTP RMIRMI HTTP


Ejecutable

Frasco Inicio Web Aplicación


Aplicación RMI RMI servlets

100% locales Combinación 100% Remoto

Las llamadas a métodos siempre se realizan un montón, dos objetos

entre dos objetos en el mismo montón.

hacer cosas()

clase Foo { Bar bj miCt


oh

ir vacío() {
Barra b = nueva barra(); Fohoh bj miCt
oh

[Link]();

público estático vacío principal (String[] args) {


Foo f = nuevo Foo(); En la mayoría de las aplicaciones, cuando un
objeto llama a un método en otro, ambos objetos
[Link]();
están en el mismo montón. En otras palabras,
} ambos se ejecutan dentro de la misma JVM.

608 capítulo 18
Machine Translated by Google

implementación remota con RMI

¿Qué sucede si desea invocar un método en


un objeto que se ejecuta en otra máquina?

Potente, rápido, le encanta


atravesar grandes superficies.
cálculos

JVM

diminuto, débil,
JVM
dolorosamente lento en los cálculos

Pequeño Grande

doble doCalcUsingDatabase (números CalcNumbers)

usted está aquí 609


Machine Translated by Google

dos objetos, dos montones

El Objeto A, que se ejecuta en Little, quiere llamar a


un método en el Objeto B, que se ejecuta en Big.

doCalcUsingDatabase()

B
A

valor de retorno

Pero no puedes hacer eso.

610 capítulo 18
Machine Translated by Google

implementación remota con RMI

Un diseño para llamadas a métodos remotos.

Cree cuatro cosas: servidor, cliente,


ayudante del servidor, ayudante del cliente

1 Cree aplicaciones de cliente y servidor. La aplicación del


servidor es el servicio remoto que tiene un objeto con el
método que el cliente quiere invocar.

montón de servidor
montón de clientes

Smirv miC
t
iCmi ohbj
Cimi
yo Ct
t ohbj mi
norte

2 Cree 'ayudantes' de cliente y servidor. Ellos se encargarán de todo


los detalles de E/S y redes de bajo nivel para que su cliente y su servicio puedan fingir
que están en el mismo montón.

montón de servidor
montón de clientes

r
Cimi
yo r
mi Smir iCmihmiyopagmi S Ct
mir
viCmi ohbj mi
v
t
norte
yo
h mi
pag

Cimi
yo
miC
t
t ohbj
norte

usted está aquí 611


Machine Translated by Google

ayudantes de cliente y servidor

El papel de los 'ayudantes'

Su objeto cliente actúa como


si estuviera realizando llamadas
a métodos remotos. Pero

lo que realmente está haciendo


es llamar a métodos en un

objeto 'proxy' local del montón


que maneja todos los detalles
de bajo nivel de Sockets y flujos.

El asistente del cliente


pretende ser el servicio,
pero es solo un proxy para el
montón de servidor
montón de clientes Cosa real.

r
El objeto cliente cree
Cimi
yo mi r Smirv iCmihmiyopagmi S Ct
t mir
viCmi ohbj mi
yopag
que está hablando norte
h mi
con el Servicio Cimi
yo
miC
t
t ohbj
norte

Real. Cree que el


El objeto del Servicio
ayudante del cliente ES el Servicio Real. Es el
es lo que realmente El asistente del servicio
recibe la solicitud del objeto con el método el
puede hacer el trabajo real.
asistente del cliente, la que realmente hace
descomprime y llama al funcionar el método real.
método en el Servicio Real.

612 capítulo 18
Machine Translated by Google

implementación remota con RMI

Cómo ocurre la llamada al método


1 El objeto cliente llama a doBigThing() en el objeto auxiliar del cliente

montón de servidor
montón de clientes

hacerBigThing()

r
Cimi
yo r
mi Smirv iCmihmiyopagmi S Ct
t mir
viCmi ohbj mi
yo
norte
h mipag

Cimi
yo
miC
t
t ohbj
norte

2 El asistente del cliente empaqueta información sobre la


llamada (argumentos, nombre del método, etc.) y la envía a
través de la red al asistente del servicio.

montón de servidor
montón de clientes "El cliente quiere llamar a un método"

hacerBigThing()

r
Cimi
yo mi r Smirv iCmihmiyopagmi S Ct
t mir
viCmi ohbj mi
yopag
norte
h mi
Cimi
yo
miC
t
norte
t ohbj

3 El asistente de servicio descomprime la información del asistente


del cliente, descubre qué método llamar (y en qué objeto)
e invoca el método real en el objeto de servicio real.

montón de servidor
montón de clientes "El cliente quiere llamar a un método"

hacerBigThing()
hacerBigThing()
Recuerde, este es el objeto
con el REAL
lógica del método. El tipo
mi r
Cimi
yo
yo mi
r Smirv iCmihmi
yopag
Smirv miC
t ¡Eso hace el verdadero trabajo!

t
norte
t h mipag iCmi ohbj
Cimi
yo C
norte
t ohbj mi

usted está aquí 613


Machine Translated by Google

Objetos auxiliares RMI

¡Java RMI le proporciona los objetos


auxiliares de cliente y servicio!

En RMI, el asistente del cliente es un


"stub" y el asistente del servidor es un "esqueleto".

montón de servidor
montón de clientes

Talón RMI ESQUELETO RMI

r
Cimiyo mi r Smirv iCmihmiyopagmi S Ct
t mir
viCmi ohbj mi
yopag
norte
h mi
Cimi t
j miC
yo
t ohb
norte

614 capítulo 18
Machine Translated by Google

implementación remota con RMI

Realizar el servicio remoto Servidor

Paso uno: Esta interfaz define los


Crear una interfaz remota
interfaz pública
MyRemote se extiende
Remoto { } métodos remotos a los que
desea que llamen los clientes.

[Link]

Segundo paso: El verdadero servicio. La clase


interfaz pública
con los métodos que hacen
Realizar una implementación remota
MyRemote se extiende
Remoto { }

el trabajo real. Implementa la


interfaz remota.
[Link]

escupe dos nuevas


Ejecutando rmic contra la clase de clases para los
Paso tres: implementación de servicio real... objetos auxiliares
Genere los talones y esqueletos usando rmic 101101
Ventana de edición de archivos Ayuda a comer 10 110 1
0 11 0

%rmic MiRemoteImpl
001 10
001 01

MyRemoteImpl_Stub.clase

101101
10 110 1 0
11 0
001 10
001 01

MyRemoteImpl_Skel.clase
Paso cuatro: Ventana de edición de archivos Ayuda Bebida

Inicie el registro RMI (rmiregistry) %rmiregistro ejecutar esto en un

terminal separada

Paso cinco:
Iniciar el servicio remoto Ayuda de la ventana de edición de archivos BeMerry

%java MiRemoteImpl

usted está aquí 615


Machine Translated by Google

una interfaz remota

Paso uno: crear una interfaz remota interfaz pública


MyRemote se extiende
Remoto { }

[Link]
1 Ampliar [Link]

Su interfaz debe
anunciar que es para
llamadas a métodos
interfaz pública MyRemote extiende Remote {
remotos. Una interfaz no
puede implementar nada,
pero puede ampliar otras interfaces.
2 Declarar que todos los métodos arrojan una RemoteException

la interfaz remota está en [Link]


importar [Link].*;

interfaz pública MyRemote extiende Remote { Cada llamada a un método remoto se

public String sayHello() lanza RemoteException; considera "arriesgada". Declarar

} RemoteException en cada método


obliga al cliente a prestar atención
y reconocer que es posible

que las cosas no funcionen.

3 Asegúrese de que los argumentos y los valores de retorno sean primitivos o serializables

public String sayHello() lanza RemoteException;

Este valor de retorno se enviará por cable desde el


servidor al cliente, por lo que debe ser de regreso
serializable.

Así es como se empaquetan y envían los argumentos


y los valores de retorno.

616 capítulo 18
Machine Translated by Google

implementación remota con RMI

Paso dos: realizar una implementación remota interfaz pública


MyRemote se extiende
Remoto { }

1 Implementar la interfaz remota [Link]

la clase pública MyRemoteImpl extiende UnicastRemoteObject implementa MyRemote {


Cadena pública decir Hola() {
devolver “El servidor dice 'Hola'”; El compilador se asegurará de
} que haya implementado todos los
// más código en clase métodos de la interfaz que implemente.
} En este caso sólo hay uno.

2 Extender UnicastRemoteObject

la clase pública MyRemoteImpl extiende UnicastRemoteObject implementa MyRemote {

3 Escriba un constructor sin argumentos que declare una RemoteException

No tienes que poner nada en el


constructor. Sólo necesitas una forma
public MyRemoteImpl() lanza RemoteException { } de declarar que el constructor de tu
superclase genera una excepción.

4 Registrar el servicio en el registro RMI

Asigne un nombre a su servicio (que los clientes


intentar {
puedan usar para buscarlo en el registro) y
Servicio MyRemote = nuevo MyRemoteImpl(); regístrelo en el registro RMI. Cuando vincula el
[Link](“Hola remota”, servicio); objeto de servicio, RMI intercambia el servicio por
} captura (Excepción ex) {...} el código auxiliar y coloca el código auxiliar en el registro.

usted está aquí 617


Machine Translated by Google

talones y esqueletos

Paso tres: generar talones y esqueletos

1 Ejecute rmic en la clase de implementación


remota (no en la interfaz remota) escupe dos nuevas
clases para los
Observe que no dice ".class" al objetos auxiliares
final. Sólo el nombre de la clase.
101101
10 110 1 0
11 0 001
Ayuda de la ventana de edición de archivos Whuffi e
10 001
01

%rmic MiRemoteImpl
MyRemoteImpl_Stub.clase

101101
10 110 1
0 11 0
001 10
001 01

MyRemoteImpl_Skel.clase

Paso cuatro: ejecute rmiregistry

1 Abra una terminal e inicie rmiregistry. Ayuda de la ventana de edición de archivos, ¿eh?

%rmiregistro

Paso cinco: iniciar el servicio


1 Abra otra terminal e inicie su servicio. Ayuda de la ventana de edición de archivos, ¿eh?

%java MiRemoteImpl

618 capítulo 18
Machine Translated by Google

implementación remota con RMI

Código completo para el lado del servidor.


Servidor

La interfaz remota:

RemoteException y la interfaz
remota están en el paquete [Link]
importar [Link].*;
Su interfaz DEBE extender
interfaz pública MyRemote extiende Remote { [Link]
Todos sus métodos remotos deben
public String sayHello() lanza RemoteException;
declarar una RemoteException
}

El servicio remoto (la implementación):

UnicastRemoteObject está en

importar [Link].*; el paquete [Link] UnicastRemoteObject es la


importar [Link].*;
forma más fácil de crear un objeto remoto

la clase pública MyRemoteImpl extiende UnicastRemoteObject implementa MyRemote {

Cadena pública decir Hola() {


Tienes que implementar todos tú
los métodos de la interfaz, por ¡DEBE implementar
devolver “El servidor dice 'Hola'”; su interfaz remota!
supuesto. Pero tenga en cuenta que
}
NO es necesario declarar RemoteException.

public MyRemoteImpl() lanza RemoteException { } su constructor de superclase (para


UnicastRemoteObject) declara una excepción, por lo que
USTED debe escribir un constructor, porque significa que
público estático vacío principal (String[] args) { su constructor está llamando a código riesgoso (su
superconstructor)
intentar {
Servicio MyRemote = nuevo MyRemoteImpl();
[Link](“Hola remota”, servicio);
} captura (Excepción ex) {
Cree el objeto remoto, luego 'vincúlelo' al
[Link]();
} rmiregistry usando el nombre estático, rebind(). El
} nombre con el que lo registra es el nombre que los
} clientes necesitarán para buscarlo en el registro rmi.

usted está aquí 619


Machine Translated by Google

obteniendo el trozo

¿Cómo obtiene el cliente el objeto stub?

Este debe ser el


nombre con el que
lookup() es un método estático se registró el servicio.
de la clase Naming

Servicio MyRemote = (MyRemote) [Link](“rmi://[Link]/Remote Hello”);

Tienes que enviarlo a la su nombre de host o


El cliente siempre utiliza la
implementación remota como interfaz, ya que el método dirección IP va aquí
tipo de servicio. De hecho, el de búsqueda devuelve el tipo Objeto.
cliente nunca necesita saber el
nombre de clase real de su
servicio remoto.

Cliente Servidor

di hola( )
3
Skmi mit oh Smirv miC
t
St tub iCmi ohbj
yo norte

Cimi
yo Ct trozo devuelto
t ohbj mi
norte

2
1 Registro RMI (en el servidor)
buscar() Remoto
Hola

1 El cliente realiza una búsqueda en el registro RMI


[Link](“rmi://[Link]/Hola remota”);
Talón

2 El registro RMI devuelve el objeto stub

3 El cliente invoca un método en el stub,


como si el stub ES el servicio real
620 capítulo 18
Machine Translated by Google

implementación remota con RMI

¿Cómo obtiene el cliente la clase de código auxiliar?

Código de cliente completo

La clase Naming (para realizar la


importar [Link].*; búsqueda de remiregistry) está
en el paquete [Link]
clase pública MiClienteRemoto {
público estático vacío principal (String[] args) {
nuevo MiClienteRemoto().go();
}
Sale del registro como tipo
vacío público ir () {
Objeto, así que no olvides el elenco.

intentar {
Servicio MyRemote = (MyRemote) [Link](“rmi://[Link]/Remote Hello”);

Cadena s = [Link]();
necesitas la dirección IP o el y el nombre utilizado para
nombre de host
vincular/volver a vincular el servicio
[Link](s);
} captura (Excepción ex) {
¡Parece una llamada a un método antiguo
[Link]();
} normal! (Excepto que debe reconocer la
RemoteException)
}
}

usted está aquí 621


Machine Translated by Google

Archivos de clase RMI

Asegúrese de que cada máquina tenga los archivos

de clase que necesita.

Cliente Servidor

Skmi mit oh norte


t
Smirv
yo

miC
iCmi ohbj
St tub
Cimi t
j miC
yo
t ohb
norte

St tub
No olvide que el cliente 101101
101101
10 110 1 0
101101
10 110 1 0
usa la interfaz para llamar 10 110 1 0
101101
10 110 1
11 0 001 11 0 001
11 0 001 10 001 10 001
a métodos en el código 10
001 01
0 11 0
001 10
01 01

001 01
auxiliar. La JVM del cliente
Clase MyRemoteImpl MyRemoteImpl_Stub.clase
necesita la clase stub, pero [Link] MyRemoteImpl_Stub.clase
el cliente nunca hace 101101
10 110 1 101101
0 11 0 10 110 1 0
referencia a la clase stub 101101
10 110 1
001 10
001 01
11 0

en el código. El cliente 0 11 0
001 10
001 10
001 01
001 01
siempre utiliza la MyRemoteImpl_Skel.clase
interfaz remota, como Mi clase remota
Mi clase remota
si la interfaz remota FUERA el objeto remoto real.
El servidor necesita las clases Stub y
Skeleton, así como el servicio y la
La interfaz remota.
interfaz remota. Necesita la clase stub
porque recuerde, el stub se sustituye por el
servicio real, cuando el servicio real está
vinculado al registro RMI.

622 capítulo 18
Machine Translated by Google

implementación remota con RMI

Afila tu lápiz

El cliente obtiene el código


auxiliar del registro RMI.
El stub envía el método.
llamar al servidor
El cliente invoca un método
en el stub.
El cliente realiza una búsqueda El servicio remoto está
en el Registro RMI. registrado en el registro RMI.

Se inicia el registro RMI Se crea una instancia del


servicio remoto (implementación remota)

PUNTOS DE VIÑETA

Un objeto en un montón no puede obtener una referencia Su servicio remoto debería extender UnicastRemoteObject.
Java normal a un objeto en un montón diferente (lo que significa (Técnicamente, existen otras formas de crear un objeto remoto, pero
ejecutarse en una JVM diferente) extender UnicastRemoteObject es la más sencilla).

La invocación de método remoto de Java (RMI) hace que parezca que Su clase de servicio remoto debe tener un constructor, y el
estás llamando a un método en un objeto remoto (es decir, un objeto constructor debe declarar una RemoteException (porque el
en una JVM diferente), pero no es así. constructor de la superclase declara una).

Cuando un cliente llama a un método en un objeto remoto, el Se debe crear una instancia de su servicio remoto y registrar el objeto
cliente en realidad está llamando a un método en un proxy del objeto en el registro RMI.
remoto. El proxy se llama "stub".
Para registrar un servicio remoto, utilice el método
Un stub es un objeto auxiliar del cliente que se encarga de los detalles estático [Link](“Nombre del servicio”, serviceInstance);
de la red de bajo nivel (sockets, flujos, serialización, etc.)
El registro RMI debe ejecutarse en la misma máquina que el servicio
empaquetando y enviando llamadas a métodos al
remoto antes de intentar registrar un objeto remoto en el registro RMI.
servidor.

Para crear un servicio remoto (en otras palabras, un objeto al que un


El cliente busca su servicio remoto utilizando el método estático
cliente remoto puede finalmente llamar métodos), debe comenzar con
[Link](“rmi://MyHostName/ServiceName”);
una interfaz remota.
Casi todo lo relacionado con RMI puede generar una
Una interfaz remota debe ampliar la interfaz [Link] y
RemoteException (comprobada por el compilador). Esto
todos los métodos deben declarar
incluye registrar o buscar un servicio en el registro y todas las llamadas
RemoteException. a métodos remotos desde el cliente al código auxiliar.

Su servicio remoto implementa su interfaz remota.

usted está aquí 623


Machine Translated by Google

usos para RMI

Sí, pero ¿quién realmente usos RMI?

Lo usamos
para nuestro
Escuché que tu ex
nuevo y genial sistema de esposa todavía usa
apoyo a las decisiones. enchufes lisos.
Lo uso
para back­ends serios de
comercio electrónico B­to­

B, que se ejecutan en tecnología


J2EE.

Disponemos de un
sistema de reservas de

hoteles basado en EJB.


¡Y EJB usa RMI!

¡Yo también! ¿Cómo


Simplemente no puedo
imaginar la vida sin nuestra se las arregló alguien?
red doméstica y electrodomésticos Me encanta RMI por
brindarnos la tecnología
habilitados para Jini.
Jini.

624 capítulo 18
Machine Translated by Google

Vista de edición de archivos


implementación remota con RMI
Vista de edición de archivos

Vista de edición de archivos


HTTP
HTTP
HTTP RMI

Ejecutable servlets
servlets
Frasco
Inicio Web Aplicación RMI servlets

100% locales Combinación 100% Remoto

¿Qué pasa con los servlets?

1 El cliente completa un formulario de registro y hace clic en "enviar".


El servidor HTTP (es decir, el servidor web) recibe la solicitud, ve que es
para un servlet y envía la solicitud al servlet.

Servidor web
Navegador web
“El cliente solicita RegisterServlet”
(cliente)
101101
10 110 1
0 11 0
001 10
bob
001 01
Mascotas

kathy
Sierra

[Link]

2 Se ejecuta Servlet (código Java), agrega datos a la base de datos,


compone una página web (con información personalizada) y la envía de
vuelta al cliente donde se muestra en el navegador.

Servidor web
Navegador web
(cliente) “El cliente solicita RegisterServlet”
101101
10 110 1
0 11 0
001 10
Gracias
001 01
kathy
Sierra

[Link]
<HTML>

“aquí hay una página de confir rmación” <CUERPO>


Java
¡normas!
<CUERPO>
<HTML>

[Link]
usted está aquí 625
Machine Translated by Google

servlet muy simple

Paso para crear y ejecutar un servlet

Servidor web
1 Descubra dónde deben colocarse sus servlets.

servlets
101101
10 110 1
0 11 0
001 10
001 01

[Link]

2 Obtenga [Link] y agréguelo a su classpath

[Link]

3 Escriba una clase de servlet extendiendo HttpServlet 101101


10 110 1 0
11 0 001
10
001 01

[Link]

clase pública MyServletA extiende HttpServlet {...}

<HTML>

4 Escriba una página HTML que invoque su servlet <CUERPO>


Java
¡normas!
<CUERPO>
<HTML>

MiPá[Link]

<a href="servlets/MyServletA">Este es el servlet más sorprendente.</a>

Servidor web
5 Haga que su servlet y página HTML estén disponibles para su servidor
servlets
101101
10 110 1 0
11 0 001
<HTML>
10 001
<CUERPO>
Java
01
¡normas!
<CUERPO>
<HTML>
[Link]
MiPá[Link]

626 capítulo 18
Machine Translated by Google

implementación remota con RMI

Un servlet muy simple

Además de io, necesitamos importar dos de los paquetes de servlets.


importar [Link].*; Recuerde, estos dos paquetes NO forman parte de las bibliotecas
importar [Link].*; estándar de Java; debe descargarlos por separado.
importar [Link].*;

La mayoría de los servlets "normales"


clase pública MyServletA extiende HttpServlet { extenderán HttpServlet y luego anularán
uno o más métodos.

Anule doGet para mensajes El servidor web llama a este método y le entrega la solicitud
HTTP GET simples. del cliente (puede obtener datos de ella) y un objeto de
'respuesta' que utilizará para enviar una respuesta (una página).
public void doGet (solicitud HttpServletRequest, respuesta HttpServletResponse)
lanza ServletException, IOException {

Esto le dice al servidor (y al navegador) qué tipo


[Link](“texto/html”); de "cosa" regresa del servidor como resultado de la
ejecución de este servlet.

El objeto de respuesta nos proporciona un flujo de


PrintWriter fuera = [Link](); salida para "escribir" información en el servidor.

Mensaje de cadena = "Si estás leyendo esto, ¡funcionó!";

[Link](“<HTML><CUERPO>”); ¡Lo que 'escribimos' es una página HTML! La


[Link](“<H1>” + mensaje + “</H1>”); página se entrega a través del servidor al
[Link](“</BODY></HTML>”); [Link](); navegador, como cualquier otra página HTML,
aunque esta es una página que nunca existió
} hasta ahora. En otras palabras, no hay ningún
} archivo .html en alguna parte con este material.

Cómo se ve la página web:

Página HTML con un enlace a este servlet haga clic en el enlace Este es un servlet increíble.
para activar el
servlet
<HTML>
<CUERPO>

<a href="servlets/MyServletA">Este es un servlet increíble.</a>


</CUERPO>
</HTML>

usted está aquí 627


Machine Translated by Google

servlets y JSP

no existen
Preguntas tontas
PUNTOS DE VIÑETA

Los servlets son clases de Java que se ejecutan


completamente en (y/o dentro) de un servidor HTTP (web).

Los servlets son útiles para ejecutar código en el


servidor como resultado de la interacción del cliente

con una página web. Por ejemplo, si un cliente


envía información en un formulario de página web, el
servlet puede procesar la información, agregarla a una
base de datos y enviar una página de respuesta de
confirmación personalizada.

Para compilar un servlet, necesita los paquetes de


servlet que se encuentran en el archivo [Link]. Las
clases de servlets no forman parte de las bibliotecas
estándar de Java, por lo que es necesario descargar los servlets.
jar de [Link] u obtenerlos de un servidor web
compatible con servlets. (Nota: la biblioteca Servlet se
incluye con Java 2 Enterprise Edition (J2EE))

Para ejecutar un servlet, debe tener un servidor web


capaz de ejecutar servlets, como el servidor Tomcat de
[Link].

Su servlet debe ubicarse en una ubicación que sea


específica de su servidor web particular, por lo que
deberá averiguarlo antes de intentar ejecutar sus
servlets. Si tiene un sitio web alojado por un ISP que admite
servlets, el ISP le indicará en qué directorio colocar sus
servlets.

Un servlet típico extiende HttpServlet y anula uno


o más métodos de servlet, como doGet() o doPost().

El servidor web inicia el servlet y llama al método

apropiado (doGet(), etc.) según la solicitud del cliente.

El servlet puede devolver una respuesta obteniendo un


flujo de salida PrintWriter del parámetro de respuesta
del método doGet().

El servlet "escribe" una página HTML, completa con


etiquetas).

628 capítulo 18
Machine Translated by Google

implementación remota con RMI

Sólo por diversión, hagamos que Phrase­O­Matic


funcione como un servlet. Pruebe
mi nueva frase­o­
matic habilitada para la web
y será un conversador hábil
como el jefe o esos tipos de
marketing.

importar [Link].*;

importar [Link].*;
importar [Link].*;

clase pública KathyServlet extiende HttpServlet { public void doGet (solicitud


HttpServletRequest, respuesta HttpServletResponse)
lanza ServletException, IOException {

Título de cadena = “PhraseOMatic ha generado la siguiente frase.”;

[Link](“texto/html”);
PrintWriter fuera = [Link]();

¿Ver? Su servlet puede llamar a


[Link](“<HTML><CABEZA><TÍTULO>”);
métodos de otra clase. En este caso,
[Link](“FraseOmática”);
[Link](“</TITLE></HEAD><BODY>”);
llamamos al método estático makePhrase()
[Link](“<H1>” + título + “</H1>”);
de la clase PhraseOMatic (en la página siguiente)
[Link](“<P>” + [Link]());
[Link](“<P><a href=\”KathyServlet\”>crea otra frase</a></p>”);
[Link](“</BODY></HTML>”);

[Link]();
}
}

usted está aquí 629


Machine Translated by Google

Código Phrase­O­Matic

Código Phrase­O­Matic, compatible con servlets

clase pública PhraseOMatic {


cadena estática pública makePhrase() {

// crea tres conjuntos de palabras para elegir


String[] wordListOne = {“24/7”,”multi­Nivel”,”30,000 foot”,”B­to­B”,”win­win”,”front­
final”, “basado en la web”, “generalizado”, “inteligente”, “seis sigma”, “camino crítico”, “dinámico”};

String[] wordListTwo = {“empoderado”, “pegajoso”, “de valor agregado”, “orientado”, “céntrico”,


“distribuido”, “agrupado”, “de marca”, “fuera de lo común”, “posicionado”, “en red”, “enfocado”, “apalancado”, “alineado”, “dirigido”,
“compartido”, “cooperativa”, “acelerada”};

String[] wordListThree = {“proceso”, “punto de inflexión”, “solución”, “arquitectura”, “competencia central”, “estrategia”, “mente
compartida”, “portal”, “espacio”, “visión”, “paradigma ", "misión"};

// descubre cuántas palabras hay en cada lista


int oneLength = [Link];
int twoLength = [Link];
int tresLongitud = lista de [Link];

// genera tres números aleatorios para extraer palabras aleatorias de cada lista
int rand1 = (int) ([Link]() * oneLength);
int rand2 = (int) ([Link]() * twoLength);
int rand3 = (int) ([Link]() * tresLongitud);

// ahora construye una frase


Frase de cadena = listadepalabras[rand1] +
““
+ lista de palabras dos [rand2] +
““
+
lista de palabrasTres[rand3];

// ahora devuélvelo

retorno (“Lo que necesitamos es un + frase);
}
}

630 capítulo 18
Machine Translated by Google

implementación remota con RMI

Enterprise JavaBeans: RMI con esteroides

Un servidor EJB agrega una


serie de servicios que no se
obtienen con RMI directamente.
Cosas como transacciones,
seguridad, concurrencia,
gestión de bases de datos y redes.

Un servidor EJB interviene en


medio de una llamada RMI y

coloca capas en todos los servicios.

¡El objeto bean está protegido del


acceso directo del cliente! Sólo el
servidor puede realmente hablar con
el bean. Esto le permite al servidor
¡Aquí es donde entra en juego el hacer cosas como decir: “¡Vaya!
servidor EJB! El objeto EJB intercepta Este cliente no tiene la autorización
las llamadas al bean (el bean contiene de seguridad para llamar a este
Este cliente podría ser CUALQUIER COSA,
la lógica empresarial real) y capas en método...” ¡Casi todo lo que pagas en
pero normalmente un cliente EJB es un un servidor EJB sucede AQUÍ, donde interviene el servidor!
servlet que se ejecuta en el mismo servidor J2EE.
todos los servicios proporcionados por
el servidor EJB (seguridad, transacciones, etc.)

servidor EJB
Cliente
ESQUELETO RMI
Talón RMI

r
Smirv iCmihmiyopagmi
Cimi r anorte

mi mi
t mir r ismibmi
yo
t yopag
h mi mij t norte

B bj miC
norte

t
pag

Cimi
yo
j miC
oh

t ohb
norte

DB

¡Esto es sólo una pequeña parte de la imagen de EJB!

usted está aquí 631


Machine Translated by Google

un poco de jini

Para nuestro truco final... un poco de Jini

632 capítulo 18
Machine Translated by Google

implementación remota con RMI

Descubrimiento adaptativo en acción

1 Se lanza el servicio de búsqueda Jini en algún lugar de la red, y


se anuncia mediante multidifusión IP.

¡Hola a todos,
estoy aquí!

otra máquina en la red


Servicio de búsqueda de Jini

máquina en la red en algún


otra máquina en la red
lugar...

Regístreme
como algo que
implemente
2 Un servicio Jini ya en ejecución en ScientificCalculator. Aquí hay un
otra máquina solicita registrarse en este objeto serializado que representa mi
servicio de búsqueda recientemente servicio. Envíaselo a quien
anunciado. Se registra por capacidad, te lo pida...
en lugar de por nombre. En otras palabras,
se registra como la interfaz de servicio que
implementa. Envía un objeto serializado para
Servicio Jini
colocarlo en el servicio de búsqueda.

otra máquina en la red


Servicio de búsqueda de Jini

máquina en la red en algún


otra máquina en la red
lugar...

usted está aquí 633


Machine Translated by Google

descubrimiento adaptativo en Jini

Descubrimiento adaptativo en acción, continuación...

3 Un cliente en la red quiere algo que


implemente la interfaz
ScientificCalculator. No tiene idea de
dónde (o si) existe esa cosa, por lo que
pregunta al servicio de búsqueda. otra máquina en la
Servicio Jini red

¿Tiene
Servicio de búsqueda de Jini algo que
implemente
ScientificCalculator?
aplicación java

máquina en la red en algún


otra máquina en la red
lugar...

4 El servicio de búsqueda responde, ya que tiene algo registrado como


interfaz de ScientificCalculator.

Sí, tengo
algo.
Te envío el objeto
Servicio Jini
serializado.
ahora...

otra máquina en la red


Servicio de búsqueda de Jini

aplicación java

máquina en la red en algún


otra máquina en la red
lugar...

634 capítulo 18
Machine Translated by Google

implementación remota con RMI

Red de autorreparación en acción


1 Un servicio Jini ha solicitado registrarse en el servicio de búsqueda. El servicio de
búsqueda responde con un "arrendamiento". El servicio recién registrado debe
seguir renovando el contrato de arrendamiento o el servicio de búsqueda asumirá
que el servicio se ha desconectado. El servicio de búsqueda siempre quiere
presentar una imagen precisa al resto de la red sobre qué servicios están disponibles.

Te
registraré y
aquí tienes tu otra máquina en la
contrato de Servicio Jini
red
arrendamiento. Si no lo renuevas, te dejo.
alquiler

Servicio de búsqueda de Jini

máquina en la red en algún


otra máquina en la red
lugar...

2 El servicio se desconecta (alguien lo cierra), por lo que no


renovar su contrato de arrendamiento con el servicio de búsqueda. El servicio de búsqueda lo descarta.

Hmmmm...
No obtuve una
renovación del contrato de
arrendamiento de ese... debe estar
caído. Lo dejaré. Si vuelve,
automáticamente me redescubrirá.

otra máquina en la red


Servicio de búsqueda de Jini

máquina en la red en algún


otra máquina en la red
lugar...

usted está aquí 635


Machine Translated by Google

proyecto de servicio universal

Proyecto Final: el navegador de Servicio Universal

Elija un servicio de la lista.


El servicio remoto RMI tiene
un método
getServiceList() que devuelve
esta lista de servicios.
Cuando el usuario
selecciona uno, el
cliente solicita que se envíe
el servicio real (DiceRolling,
DayOfTheWeek, etc.) desde
el servicio remoto RMI.

Cuando selecciones un
servicio, ¡aparecerá aquí!

636 capítulo 18
Machine Translated by Google

implementación remota con RMI

Cómo funciona:
Servidor
1 El cliente se inicia y busca Navegador de servicios
en el registro RMI el (cliente)
servicio llamado r
“ServiceServer” y
rvmi
recupera el código Smi
"Por favor

Cmi
auxiliar. dame
la Smirvi
“Servidor de servicios”
cosa
llamada

Registro RMI (en el servidor)


Servicio
"Está Servidor

bien, aquí
está
el talón"
Talón

2 El cliente llama a getServiceList() en el código auxiliar. El ServiceServer


devuelve una serie de servicios.
Servidor
Navegador de servicios
“obtenerListaServicios()”
(cliente)

r
mi
rv
mi
mi S
Smirvi C
"Está bien, aquí hay una variedad de servicios"

3 El cliente muestra la lista de servicios en una GUI

Servidor
Navegador de servicios
(cliente)
r
mi
rv
mi
mi S
Smirvi C

usted está aquí 637


Machine Translated by Google

navegador de servicio universal

Cómo funciona, continuación...

4 El usuario selecciona de la lista, por lo que el cliente llama a getService()


método en el servicio remoto. El servicio remoto devuelve un objeto serializado que
es un servicio real que se ejecutará dentro del navegador del cliente.

Servidor
Navegador de servicios
“getService(svcseleccionado)”
(cliente)
r
mi
rv
mi
Cmi
S
Smirvi
“OK, aquí está el servicio”

5 El cliente llama a getGuiPanel() en el objeto de servicio serializado que


acaba de obtener del servicio remoto. La GUI para ese servicio se
muestra dentro del navegador y el usuario puede interactuar con ella
localmente. En este punto, no necesitamos el servicio remoto a menos que el
usuario decida seleccionar otro servicio.

Navegador de servicios
(cliente)

638 capítulo 18
Machine Translated by Google

implementación remota con RMI

Las clases e interfaces:

Servidor de servicio
1 interfaz ServiceServer implementa Remote
Una interfaz remota RMI antigua y normal para el servicio remoto (el obtenerListaServicios()
servicio remoto tiene el método para obtener la lista de servicios y obtenerServicio()
devolver un servicio seleccionado).

ServiceServerImpl de 2 clases implementa ServiceServer


El servicio remoto RMI real (extiende UnicastRemoteObject). ServicioServidorImpl

Su trabajo es crear instancias y almacenar todos los obtenerListaServicios()


servicios (las cosas que se enviarán al cliente) y registrar el obtenerServicio()
servidor en sí (ServiceServerImpl) con el registro RMI.

Navegador de servicios de 3 clases


Navegador de servicios
El cliente. Crea una GUI muy simple, realiza una búsqueda en el registro RMI
para obtener el código auxiliar de ServiceServer y luego llama a un método remoto principal()

para obtener la lista de servicios que se mostrarán en la lista de GUI.

Servicio de 4 interfaces
Ésta es la clave de todo. Esta interfaz muy sencilla tiene un solo método,
getGuiPanel(). Cada servicio que se envía al cliente debe implementar esta
interfaz. ¡Esto es lo que hace que todo sea UNIVERSAL! Al implementar esta interfaz,
un servicio puede llegar incluso aunque el cliente no tenga idea de cuál es la clase (o
clases) real que componen ese servicio. Todo lo que el cliente sabe es que, sea lo Servicio
que sea, implementa la interfaz de Servicio, por lo que DEBE tener un método
obtenerGuiPanel()
getGuiPanel().

El cliente obtiene un objeto serializado como resultado de llamar a


getService(selectedSvc) en el código auxiliar de ServiceServer, y todo lo que el
cliente le dice a ese objeto es: "No sé quién o qué es usted, pero SÍ sé que
implementa el Interfaz de servicio, así sé que puedo llamar a getGuiPanel(). Y
como getGuiPanel() devuelve un JPanel, ¡simplemente lo insertaré en la GUI del
navegador y comenzaré a interactuar con él!

Servicio de dados
5 clase DiceService implementa el servicio
obtenerGuiPanel()
¿Tienes dados? Si no es así, pero los necesita, utilice este servicio para lanzar entre 1 y 6 dados virtuales por usted.

MiniMusicService de 6 clases implementa el servicio


Servicio MiniMusica
¿Recuerdas ese pequeño y fabuloso programa de 'vídeos musicales' del primer
GUI Code Kitchen? Lo hemos convertido en un servicio y puedes reproducirlo una obtenerGuiPanel()
Servicio del día de la semana
y otra vez hasta que tus compañeros de cuarto finalmente se vayan.
obtenerGuiPanel()

7 clase DayOfTheWeekService implementa el servicio


¿Naciste un viernes? Escribe tu cumpleaños y descúbrelo.

usted está aquí 639


Machine Translated by Google

código de servicio universal

interfaz ServiceServer (la interfaz remota)

importar [Link].*;
Una interfaz remota RMI normal
La interfaz pública ServiceServer extiende Remote { define los dos métodos que
tendrá el servicio remoto.
Object[] getServiceList() lanza RemoteException;

El servicio getService (Object serviceKey) lanza RemoteException;


}

Servicio de interfaz (lo que implementan los servicios GUI)

importar [Link].*; Una interfaz simple y antigua (es decir, no remota)


importar [Link].*; que define el único método que debe tener
cualquier servicio universal: getGuiPanel().
El servicio de interfaz pública extiende Serializable { public JPanel La interfaz amplía Serializable, de modo que
getGuiPanel(); cualquier clase que implemente la interfaz de
Servicio será automáticamente Serializable.
}

Esto es imprescindible, porque los servicios


se envían por cable desde el servidor, como
resultado de que el cliente llama a getService()
en el ServiceServer remoto.

640 capítulo 18
Machine Translated by Google

implementación remota con RMI

clase ServiceServerImpl (la implementación remota)


importar [Link].*;
importar [Link].*;
importar [Link].*; Una implementación RMI normal

la clase pública ServiceServerImpl extiende UnicastRemoteObject implementa ServiceServer {

Lista de servicios HashMap;

Los servicios se almacenarán en una colección HashMap. En lugar de poner


UNobjeto
un objetode
envalor
la colección, pones DOS:
(lo que quieras). un objeto B
(ver apéndice clave
para(como una Cadena) y
más en HashMap)
public ServiceServerImpl() lanza RemoteException {
configurarServicios();
}
Cuando se llama al constructor, inicializa los servicios
setUpServices vacío privado() { universales reales (DiceService, MiniMusicService, etc.)
lista de servicios = nuevo HashMap();
[Link](“Servicio de lanzamiento de dados”, nuevo DiceService()); [Link](“Servicio
del día de la semana”, nuevo DayOfTheWeekService()); [Link](“Servicio de música visual”, nuevo
MiniMusicService());
}
Haga los servicios (los objetos de servicio
reales) y colóquelos en el
HashMap, con un nombre String (para
la clave').
Objeto público[] getServiceList() {
[Link](“en remoto”); El cliente llama a esto para obtener una lista de servicios
devolver [Link]().toArray(); para mostrar en el navegador (para que el usuario pueda
seleccionar uno). Enviamos un array de tipo Objeto (aunque
} tenga Strings dentro) haciendo un array solo de las LLAVES
que están en el HashMap. No enviaremos un objeto de
Servicio real a menos que el cliente lo solicite llamando a getService().

Servicio público getService (Objeto serviceKey) lanza RemoteException { Servicio theService = (Servicio)
[Link] (serviceKey); devolver el Servicio;

} El cliente llama a este método después de que el usuario


selecciona un servicio de la lista de servicios mostrada (que obtuvo
del método anterior). Este código utiliza la clave (la misma
clave enviada originalmente al cliente) para obtener el correspondiente
servicio fuera del HashMap.

público estático vacío principal (String[] args) {


intentar {
[Link](“ServiceServer”, nuevo ServiceServerImpl());
} captura (Excepción ex) {
[Link]();
}
[Link](“El servicio remoto se está ejecutando”);
}
}
usted está aquí 641
Machine Translated by Google

Código del navegador de servicio

clase ServiceBrowser (el cliente)

importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;

Navegador de servicios de clase pública {

Panel principal de JPanel;


Lista de servicios JComboBox;
Servidor de servicio;

buildGUI pública vacía() {


Marco JFrame = nuevo JFrame ("Navegador RMI");
panel principal = nuevo JPanel();
[Link]().add([Link], mainPanel);
este método realiza la búsqueda del registro RMI,
Objeto[] servicios = getServicesList(); obtiene el código auxiliar y llama a getServiceList().
(El método real se encuentra en la página siguiente).

Agregue los servicios (una matriz de Objetos) al


serviceList = nuevo JComboBox(servicios); JComboBox (la lista). JComboBox sabe cómo crear
cadenas visualizables a partir de cada elemento de la matriz.

[Link]().add([Link], serviceList);

[Link](new MyListListener());

[Link](500,500);
[Link] (verdadero);

void loadService (Objeto selección de servicio) {


intentar {
Servicio svc = [Link](serviceSelection);

panel [Link]();
Aquí
el es donde
usuario agregamos el servicio real a la GUI, después del
ha seleccionado
[Link]([Link]());
uno. oyente (Este método es llamado por el evento
panel [Link]();
panel [Link]();
JComboBox). Llamamos a getService() en
en servidor remoto el
} captura (Excepción ex) { (el código auxiliar de ServiceServer) y pasarle el
[Link](); Cadena que se mostró en la lista (que es la MISMA cadena que
} obtuvimos originalmente del servidor cuando llamamos a
getServiceList()). El servidor
} devuelve el servicio real
(serializado), que se deserializa automáticamente (gracias a RMI) y
simplemente llamamos a getGuiPanel() en
el servicio y agregamos
el resultado (un JPanel) al panel principal del navegador.

642 capítulo 18
Machine Translated by Google

implementación remota con RMI

Objeto[] getServicesList() {
Objeto obj = nulo;
Objeto[] servicios = nulo;
Realice la búsqueda de RMI y obtenga el talón

intentar {

obj = [Link](“rmi://[Link]/ServiceServer”);

}
captura (excepción ex) {
[Link]();
}
servidor = (Servidor de servicios) obj;
Transmita el código auxiliar al tipo de interfaz remota,
para que podamos llamar a getServiceList() en él.

intentar {

servicios = [Link]();

} captura (Excepción ex) {


[Link](); getServiceList() nos proporciona la matriz de
} Objetos que mostramos en JComboBox para que el
servicios de devolución; usuario los seleccione.

clase MyListListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) {

Selección de objetos = [Link]();


loadService(selección);
Si estamos aquí, significa que el usuario
} hizo una selección de la lista JComboBox.
}
Entonces, tome la selección que hicieron y
cargue el servicio apropiado. (ver el método
público estático vacío principal (String [] argumentos) { loadService en la página anterior, que solicita al
nuevo ServiceBrowser().buildGUI();
servidor el servicio que corresponde con esta selección)
}
}

usted está aquí 643


Machine Translated by Google

Código de servicio de dados

clase DiceService (un servicio universal, implementa el Servicio)

importar [Link].*; importar


[Link].*; importar [Link].*;

clase pública DiceService implementa Servicio {

Etiqueta JLabel;
JComboBox número de dados;

JPanel público getGuiPanel() {


Panel JPanel = nuevo JPanel(); Botón JButton
= new JButton(“¡Enróllalos!”); Cadena[] opciones = {“1”, “2”, “3”, “4”,
“5”}; numOfDice = nuevo JComboBox(opciones); etiqueta = new
JLabel(“valores de dados aquí”); botó[Link](new
RollEmListener()); [Link](numOfDice); panel.añadir(botón);
[Link](etiqueta); panel de retorno;

¡Aquí está el único método importante! El método de


la interfaz de Servicio: el que
El cliente va a llamar cuando
este servicio es seleccionado y cargado. Puedes hacer lo que quieras
} en el método getGuiPanel(), siempre y cuando devuelvas un
JPanel, para que construya la GUI real para tirar los dados.
public class RollEmListener implements ActionListener { public void
actionPerformed(ActionEvent ev) { // tira los dados String diceOutput = “”;
Selección de cadena =
(Cadena) [Link]();
int numOfDiceToRoll = [Link](selección); for (int i = 0; i < numOfDiceToRoll; i++) { int
r = (int) (([Link]() * 6) + 1); salida de dados += (“ “ + r);

}
[Link](diceOutput);

}
}

Afila tu lápiz

644 capítulo 18
Machine Translated by Google

implementación remota con RMI

clase MiniMusicService (un servicio universal, implementa el Servicio)

importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;

La clase pública MiniMusicService implementa el servicio {


¡El método de servicio! Todo lo
MiDrawPanel miPanel;
que hace es mostrar un botón y el
servicio de dibujo (donde
JPanel público getGuiPanel() {
eventualmente aparecerán los rectángulos).
JPanel panel principal = nuevo JPanel();
pintarse).
miPanel = nuevo MiPanelDraw();
JButton playItButton = new JButton(“Tócalo”);
[Link](nuevo PlayItListener());
[Link](miPanel);
[Link](playItButton);
devolver panel principal;
}

clase pública PlayItListener implementa ActionListener { Este es todo el material musical de Code
acción vacía pública realizada (ActionEvent ev) { Kitchen en el capítulo 12, por lo que
no lo volveremos a comentar aquí.
intentar {

Secuenciador secuenciador = [Link](); [Link]();

[Link](myPanel, new int[] {127});


Secuencia secuencia = nueva Secuencia ([Link], 4);
Seguimiento de seguimiento = [Link]();

para (int i = 0; i < 100; i+= 4) {

int rNum = (int) (([Link]() * 50) + 1);


if (rNum < 38) { // así que ahora solo hazlo si num <38 (75% del tiempo)
[Link](makeEvent(144,1,rNum,100,i));
[Link](makeEvent(176,1,127,0,i));
[Link](makeEvent(128,1,rNum,100,i + 2));
}
} // finalizar bucle

[Link](seq);
[Link]();
[Link](220);
} captura (Excepción ex) {[Link]();}

} // cerrar acción realizada


} // cerrar clase interna

usted está aquí 645


Machine Translated by Google

Código de servicio MiniMusic

clase MiniMusicService, continuación...


public MidiEvent makeEvent(int comd, int chan, int uno, int dos, int tick) {
Evento MidiEvent = nulo;
Pruebe
{Mensaje Corto a = nuevo Mensaje Corto(); [Link](comd,
chan, uno, dos); evento = nuevo MidiEvent(a, marca);

}catch(Excepción e) { } evento de
retorno; }

clase MyDrawPanel extiende JPanel implementa ControllerEventListener {

// sólo si tenemos un evento queremos pintar boolean msg = false;

cambio de control de vacío público (evento de mensaje corto) {


mensaje =
verdadero; repintar(); Nada nuevo en toda esta página. Lo has
} visto todo en los gráficos CodeKitchen.
Si desea realizar otro ejercicio,
Dimensión pública getPreferredSize() { return nueva intente anotar este código usted
Dimensión(300,300); mismo y luego compárelo con
} CodeKitchen en el capítulo “Una historia muy gráfica”.

componente de pintura público vacío (Gráficos g) { if (msg) {

Gráficos2D g2 = (Gráficos2D) g;

int r = (int) ([Link]() * 250); int gr = (int) ([Link]()


* 250); int b = (int) ([Link]() * 250);

[Link](nuevo Color(r,gr,b));

int ht = (int) (([Link]() * 120) + 10); int ancho = (int) (([Link]() *


120) + 10);

int x = (int) (([Link]() * 40) + 10); int y = (int) (([Link]() * 40)


+ 10);

[Link](x,y,ht, ancho); mensaje = falso;

} // cerrar si } // cerrar
método } // cerrar clase
interna } // cerrar clase

646 capítulo 18
Machine Translated by Google

implementación remota con RMI

clase DayOfTheWeekService (un servicio universal, implementa el Servicio)

importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;

la clase pública DayOfTheWeekService implementa el servicio {

JLabel etiqueta de salida;


mes de JComboBox;
El método de interfaz de servicio
Día JTextField;
que construye la GUI
JTextField año;

JPanel público getGuiPanel() {


Panel JPanel = nuevo JPanel();
Botón JButton = nuevo JButton(“¡Hazlo!”);
botó[Link](new DoItListener());
OutputLabel = new JLabel(“la fecha aparece aquí”); DateFormatSymbols
dateStuff = nuevo DateFormatSymbols(); mes = nuevo JComboBox([Link]());

día = nuevo JTextField(8);


año = nuevo JTextField(8);
JPanel inputPanel = nuevo JPanel(nuevo GridLayout(3,2));
[Link](new JLabel(“Mes”));
[Link](mes);
[Link](new JLabel(“Día”));
[Link](día);
[Link](new JLabel(“Año”)); [Link](año);

[Link](panel de entrada);
panel.añadir(botón);
[Link](etiquetadesalida);
panel de retorno;
}

la clase pública DoItListener implementa ActionListener {


acción vacía pública realizada (ActionEvent ev) { Consulte el capítulo 10 si necesita un recordatorio
int númeroMes = [Link](); int númeroDía = de cómo funciona el formato de números y fechas.
[Link](dí[Link]()); Sin embargo, este código es ligeramente
int númeroaño = [Link](añ[Link]()); diferente porque utiliza la clase Calendario.
Calendario c = [Link](); Además, SimpleDateFormat nos permite especificar
[Link]([Link], númeromes); un patrón sobre cómo debe imprimirse la fecha.
[Link](Calendario.DAY_OF_MONTH, dayNum);
[Link](Calendario.AÑO, númeroaño);
Fecha fecha = [Link]();
String dayOfWeek = (new SimpleDateFormat(“EEEE”)).format(fecha);
[Link](díade la semana);
}
}
} 647
usted está aquí
Machine Translated by Google

el final... algo así

¿No sería un
sueño si este fuera el final del libro?
¿Si no hubiera más viñetas, acertijos,
listas de códigos o cualquier otra
cosa?
Pero eso probablemente sea sólo
una fantasía...

Por supuesto, todavía quedan los dos apéndices.


Y el índice.
Y luego está el sitio web...
Realmente no hay escapatoria.

648 capítulo 18
Machine Translated by Google

Tu mensaje se envía a los

ritmo de baile demás jugadores, junto con


tu patrón de ritmo actual,

cuando presionas
"mándalo".

Andy: ritmo #2

Chris: groove2 revisado

Nigel: ritmo de baile Mensajes entrantes desde


jugadores. Haga clic
hasta cargar

en el patrón que lo acompaña


y luego haga clic en "Iniciar"
para reproducirlo.

este es un nuevo apéndice 649


Machine Translated by Google

código final de BeatBox

Programa cliente final de BeatBox


La mayor parte de este código es el mismo que el código de CodeKitchens en los capítulos anteriores,
por lo que no volvemos a anotarlo todo. Las nuevas piezas incluyen:

GUI: se agregan dos nuevos componentes para el área de texto que muestra los mensajes
entrantes (en realidad, una lista de desplazamiento) y el campo de texto.

REDES: al igual que SimpleChatClient en este capítulo, BeatBox ahora se conecta al servidor y
obtiene un flujo de entrada y salida.

HILOS: nuevamente, al igual que SimpleChatClient, iniciamos una clase de 'lector' que sigue
buscando mensajes entrantes del servidor. Pero en lugar de solo texto, los mensajes que llegan
incluyen DOS objetos: el mensaje String y el ArrayList serializado (lo que contiene el estado de todas
las casillas de verificación).

importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;
importar [Link].*;

clase pública BeatBoxFinal {

JFrame el Marco;
Panel principal de JPanel;
JList lista entrante;
Mensaje de usuario de JTextField;
ArrayList<JCheckBox> lista de casillas de verificación;
int númsiguiente;
Vector<String> listaVector = nuevo Vector<String>();
Nombre de usuario de cadena;
ObjectOutputStream hacia fuera;
ObjectInputStream en;
HashMap<String, boolean[]> otherSeqsMap = new HashMap<String, boolean[]>();

Secuenciador secuenciador;
Secuencia de secuencia;
Secuencia miSecuencia = nula;
Seguimiento de seguimiento;

String[] nombres de instrumentos = {“Bambo”, “Charles cerrado”, “Charles abierto”, “Acústico


Caja”, “Crash Cymbal”, “Hand Clap”, “High Tom”, “Hola Bongo”, “Maracas”, “Silbato”,
“Conga baja”, “Cowbell”, “Vibraslap”, “Tom medio bajo”, “Agogo alto”, “Open Hi Conga”};

int[] instrumentos = {35,42,46,38,49,39,50,60,70,72,64,56,58,47,67,63};

650 apéndice A
Machine Translated by Google

Apéndice A Código Final Cocina

public static void main (String[] args) { new BeatBoxFinal().startUp(args[0]); //


args[0] es su ID de usuario/nombre de pantalla
}
Agregue un argumento de línea de comando para su nombre de pantalla.

inicio público vacío (nombre de cadena) { nombre de usuario


Ejemplo: % java BeatBoxFinal theFlash
= nombre; // abrir conexión
al servidor try { Socket sock = new Socket(“[Link]”,
4242);
salida = nuevo ObjectOutputStream([Link]()); en = nuevo
Nada nuevo... configure la
ObjectInputStream([Link]()); Hilo remoto = nuevo hilo (nuevo RemoteReader()); red, la E/S y cree (e inicie) el hilo
inicio remoto(); } catch(Exception ex) { [Link](“no se pudo conectar; tendrás del lector.
que jugar solo.”);

} configurarMidi();
construirGUI(); } //
cerrar inicio

buildGUI pública vacía() { Código GUI, nada nuevo aquí

theFrame = nuevo JFrame(“Cyber BeatBox”); Diseño BorderLayout =


nuevo BorderLayout(); Fondo de JPanel = nuevo JPanel (diseño);
[Link]([Link](10,10,10,10));

checkboxList = nueva ArrayList<JCheckBox>();

Botón de cuadroBox = new Box(BoxLayout.Y_AXIS); Inicio de JButton =


nuevo JButton(“Inicio”); [Link](new
MyStartListener()); [Link](inicio);

Detener JButton = nuevo JButton(“Detener”);


[Link](new MyStopListener()); [Link](detener);

JButton upTempo = new JButton(“Tempo arriba”);


[Link](new MyUpTempoListener()); [Link](upTempo);

JButton downTempo = new JButton(“Tempo abajo”); [Link](new


MyDownTempoListener()); [Link](downTempo);

JButton enviarlo = nuevo JButton(“enviar”); [Link](new


MySendListener()); [Link](enviarlo);

mensaje de usuario = nuevo JTextField();

usted está aquí 651


Machine Translated by Google

código final de BeatBox

[Link](mensaje de usuario);

Listaentrante = nueva JList();


[Link](new MyListSelectionListener());
[Link](ListSelectionModel.SINGLE_SELECTION);
JScrollPane theList = nuevo JScrollPane(listaentrante);
[Link](laLista);
[Link](listVector); // no hay datos para empezar

Nombre del cuadroBox = new Box(BoxLayout.Y_AXIS); JList es un componente que no hemos


para (int i = 0; i < 16; i++) { usado antes. Aquí es donde se
[Link](new Label(nombresdeinstrumentos[i])); muestran los mensajes entrantes.
} Solo que en lugar de un chat normal
donde simplemente MIRA los
[Link]([Link], buttonBox); mensajes, en esta aplicación
[Link]([Link], nameBox); puedes SELECCIONAR un mensaje de
la lista para cargar y reproducir el
[Link]().add(fondo); Cuadrícula GridLayout = patrón de ritmo adjunto.
new GridLayout(16,16);
[Link](1);
[Link](2);
panel principal = nuevo JPanel(cuadrícula);
[Link]([Link], panel principal);

para (int i = 0; i < 256; i++) {


JCheckBox c = nuevo JCheckBox();
Nada más en esta página es nuevo.
[Link](falso);
casilla de verificació[Link](c);
panel [Link](c); } //
finalizar bucle

[Link](50,50,300,300);
[Link]();
[Link] (verdadero);
} // cerrar buildGUI

setUpMidi público vacío() {


intentar {
secuenciador = [Link]();
[Link]();
secuencia = nueva Secuencia([Link],4);
pista = [Link](); Consigue el secuenciador, haz un
[Link](120); Secuenciar y hacer una pista
} captura (Excepción e) {[Link]();}

} // cerrar setUpMidi

652 apéndice A
Machine Translated by Google

Apéndice A Código Final Cocina

public void buildTrackAndStart() {


ArrayList<Integer> trackList = nulo; // esto contendrá los instrumentos para cada [Link](track);

pista = [Link]();
Cree una pista recorriendo las casillas de verificación para
obtener su estado y mapeándola a un instrumento (y
para (int i = 0; i < 16; i++) {
creando el MidiEvent para ello).
Esto es bastante complejo, pero es EXACTAMENTE como
trackList = nueva ArrayList<Integer>();
en los capítulos anteriores, así que consulte CodeKitchens
anteriores para obtener la explicación completa nuevamente.
para (int j = 0; j < 16; j++) {
JCheckBox jc = (JCheckBox) [Link](j + (16*i));
if ([Link]()) { int clave =
instrumentos[i]; [Link](new
Integer(clave));
} demás {
[Link](nulo); // porque este espacio debería estar vacío en la pista
}
} // cerrar bucle interno
makeTracks(lista de pistas);
} // cerrar el bucle exterior
[Link](makeEvent(192,9,1,0,15)); // ­ así que siempre vamos a 16 tiempos completos intenta {

[Link](secuencia);
[Link](secuenciador.LOOP_CONTINUOUSLY);
[Link]();
[Link](120);
} captura (Excepción e) {[Link]();}
} // cerrar método

clase pública MyStartListener implementa ActionListener {


acción vacía pública realizada (ActionEvent a) {
buildTrackAndStart();
} // cerrar acción realizada Los oyentes de la GUI.
} // cerrar clase interna Exactamente igual que la
versión del capítulo anterior.
clase pública MyStopListener implementa ActionListener {
acción vacía pública realizada (ActionEvent a) {
[Link]();
} // cerrar acción realizada
} // cerrar clase interna

clase pública MyUpTempoListener implementa ActionListener {


acción vacía pública realizada (ActionEvent a) {
float tempoFactor = [Link]();
[Link]((float)(tempoFactor * 1.03));
} // cerrar acción realizada } // cerrar
clase interna

usted está aquí 653


Machine Translated by Google

código final de BeatBox

clase pública MyDownTempoListener implementa ActionListener {


acción vacía pública realizada (ActionEvent a) {
float tempoFactor = [Link]();
[Link]((float)(tempoFactor * .97));
}
}

la clase pública MySendListener implementa ActionListener {


acción vacía pública realizada (ActionEvent a) {
// crea una lista de matrices solo del ESTADO de las casillas de verificación
boolean[] checkboxState = nuevo booleano[256];
para (int i = 0; i < 256; i++) {
JCheckBox comprobar = (JCheckBox) [Link](i);
si ([Link]()) { Esto es nuevo... es muy parecido a SimpleChatClient,
estado de casilla de verificación [i] = verdadero; excepto que en lugar de enviar un mensaje String, serializamos
} dos objetos (el mensaje String y el patrón de ritmo) y escribimos
} // cerrar bucle esos dos objetos en el flujo de salida del socket (en el servidor).
Mensaje de cadena para enviar = nulo;
intente
{ [Link] (nombre de usuario + nextNum++ + “: + mensaje de [Link]());
“ [Link] (checkboxState);
} captura (Excepción ex) {
[Link](“Lo siento amigo. No se pudo enviarlo al servidor.”);
}
mensaje de [Link] ("");
} // cerrar acción realizada
} // cerrar clase interna

clase pública MyListSelectionListener implementa ListSelectionListener {


public void valueChanged(ListSelectionEvent archivo) {
si (![Link]()) {
Cadena seleccionada = (Cadena) [Link](); si (seleccionado! = nulo) {

// ahora vamos al mapa y cambiamos la secuencia


boolean[] selectedState = (boolean[]) [Link](seleccionado);
cambiarSequence(estado seleccionado);
[Link]();
buildTrackAndStart();
}
} Esto también es nuevo: cuando
} // cerrar valorCambiado
} // cerrar clase interna Cuando elhizo
el usuario usuario
una selección en ListSelectionListener que nos dice
la lista de
selecciona un mensaje,
carga el mensaje asociado nosotros
mensajes.
INMEDIATAMENTE

patrón de ritmo (está en el HashMap


llamado
Lista otherSeqsMap)
de eventos y comienza a reproducirlo. Hay algunas pruebas si debido
de selección.
a pequeñas cosas peculiares sobre cómo obtener

654 apéndice A
Machine Translated by Google

Apéndice A Código Final Cocina


La clase pública RemoteReader implementa Runnable {
booleano[] estado de casilla de verificación = nulo;
Cadena nombreToShow = nulo; Este es el trabajo del hilo: leer datos del
Objeto obj = nulo; servidor. En este código, los 'datos' siempre
ejecución pública vacía() { serán dos objetos serializados: el
intentar { mensaje String y el patrón de ritmo (una
while((obj=[Link]()) != nulo) { ArrayList de valores de estado de casilla de verificación)
[Link](“obtuve un objeto del servidor”);
[Link]([Link]()); Cadena
nombreToShow = (Cadena) obj;
cuando un mensaje
checkboxState = (boolean[]) [Link]();
entra, leemos
[Link](nameToShow, checkboxState); mensaje
(deserializar) los dos objetos (el y el
[Link](nombreParaMostrar);
[Link](listVector); } // cerrar mientras ArrayList de Boolean el componente
valores de estado de casilla de verificación) y agréguelo a

} catch(Exception ex) {[Link]();} } // cerrar ejecución } // JList. Agregar a un JList es una cosa de dos pasos:
cerrar clase interna mantienes un Vector de los datos de las listas
(Vector es un ArrayList anticuado), y luego
JList para usar
le dices al para saber qué mostrar en la lista.
clase pública MyPlayMineListener implementa ActionListener { ese Vector como su fuente
acción vacía pública realizada (ActionEvent a) {
if (miSecuencia! = nulo) {
secuencia = miSecuencia; // restaurar a mi original
}
} // cerrar acción realizada
} // cerrar clase interna Este método se llama cuando el usuario
selecciona algo de la lista. Cambiamos
Secuencia de cambio pública vacía (booleano [] estado de casilla de verificación) {
INMEDIATAMENTE el patrón al que seleccionaron.
para (int i = 0; i < 256; i++) {
JCheckBox comprobar = (JCheckBox) [Link](i);
si (checkboxState[i]) {
[Link](verdadero);
} demás {
[Link](falso);
}
} // cerrar bucle Todo el material MIDI es exactamente igual que antes.
} // cerrar secuencia de cambio estaba en la versión anterior.

makeTracks público vacío (lista ArrayList) {


Iterador it = [Link](); para (int i = 0; i < 16;
i++) {
Número entero = (Entero) [Link]();
si (núm! = nulo) {
int numKey = [Link]();
[Link](makeEvent(144,9,numKey, 100, i));
[Link](makeEvent(128,9,numKey,100, i + 1));
}
} // cerrar bucle
} // cerrar makeTracks()

usted está aquí 655


Machine Translated by Google

código final de BeatBox

public MidiEvent makeEvent(int comd, int chan, int uno, int dos, int tick) {
Evento MidiEvent = nulo; Pruebe
{Mensaje
Corto a = nuevo Mensaje Corto(); [Link](comd, chan,
uno, dos); evento = nuevo MidiEvent(a, marca); }
catch(Excepción e) { } evento de retorno; } // cerrar
makeEvent
Nada nuevo. Igual que la última versión.

} // cerrar clase

Afila tu lápiz

656 apéndice A
Machine Translated by Google

Apéndice A Código Final Cocina

Programa final del servidor BeatBox


La mayor parte de este código es idéntico al SimpleChatServer que creamos en el
capítulo Redes e hilos. De hecho, la única diferencia es que este servidor recibe y luego reenvía dos
objetos serializados en lugar de una cadena simple (aunque uno de los objetos serializados
resulta ser una cadena).

importar [Link].*; importar


[Link].*; importar [Link].*;

servidor de música de clase pública {

ArrayList<ObjectOutputStream> clientOutputStreams;

public static void main (String[] args) { nuevo MusicServer().go();

la clase pública ClientHandler implementa Runnable {

ObjectInputStream en;
Cliente de socketSocket;

public ClientHandler (zócalo) {


prueba
{ clientSocket = socket;
en = new ObjectInputStream([Link]());

} catch(Excepción ex) {[Link]();}


} // cerrar constructor

ejecución pública vacía() {


Objeto o2 = nulo;
Objeto o1 = nulo; intentar {

mientras ((o1 = [Link]()) != nulo) {

o2 = [Link]();

[Link](“leer dos objetos”); decirle a todos (o1, o2); } //


cerrar mientras

} catch(Excepción ex) {[Link]();}


} // cerrar ejecución } //
cerrar clase interna

usted está aquí 657


Machine Translated by Google

código final de BeatBox

vacío público ir () {
clientOutputStreams = new ArrayList<ObjectOutputStream>();

intentar {
ServerSocket serverSock = nuevo ServerSocket(4242);

while(true) { Socket
clientSocket = [Link](); ObjectOutputStream out = new
ObjectOutputStream([Link]()); [Link](fuera);

Hilo t = nuevo hilo (nuevo ClientHandler (clientSocket)); [Link]();

[Link](“obtuve una conexión”);


}
}catch(Excepción ex) {
[Link]();
}
} // cerrar ir

public void tellEveryone(Objeto uno, Objeto dos) { Iterador =


[Link](); while([Link]()) { intentar
{ ObjectOutputStream fuera =

(ObjectOutputStream) [Link](); [Link](uno); [Link](dos); }catch(Excepción


ex) {[Link]();}

} } // cerrar decirle a todos

} // cerrar clase

658 apéndice A
Machine Translated by Google

apéndice B
Los diez temas principales que casi llegan al Libro Real...

¿Quieres decir que todavía


hay MÁS? ¿Este libro
NUNCA termina?

este es un nuevo apéndice 659


Machine Translated by Google

manipulación de bits

#10 Manipulación de bits


¿Por qué te importa? Los operadores de turno

Operador NOT bit a bit: ~

Operador de desplazamiento a la derecha: >>

Operador AND bit a bit: &

Operador de desplazamiento a la derecha sin firmar: >>>

Operador OR bit a bit: |

Operador de desplazamiento a la izquierda: <<

Operador XOR (OR exclusivo) bit a bit: ^

660 apéndice B
Machine Translated by Google

Apéndice B Referencia de los diez principales

#9 Inmutabilidad

¿Por qué te importa que las cadenas sean inmutables? ¿Por qué te importa que los Wrappers sean
inmutables?

hazlo pegado

¡Oh mira! Un bono Haz que se mantenga.


¿Cómo ahorra esto memoria? Aquí mismo en el apéndice.

usted está aquí 661


Machine Translated by Google

afirmaciones

#8 Afirmaciones
Cómo hacer que las afirmaciones funcionen

afirmar (altura > 0);

// si es verdadero, el programa continúa normalmente


// si es falso, lanza un AssertionError

“ +
afirmar (altura > 0): “altura = altura + + peso;

“ peso =

Afirmaciones

Compilando y ejecutando con


Afirmaciones

javac [Link]

java ­ea TestDriveJuego

662 apéndice B
Machine Translated by Google

Apéndice B Referencia de los diez principales

# 7 Alcance del bloque

inicio del bloque de método

void hacer cosas() { variable local con alcance para todo el método
int x = 0;
comienzo de un bloque de bucle for, y y tiene
para(int y = 0; y < 5; y++) {
como alcance solo el bucle for.

x = x + y; No hay problema, x e y están dentro del alcance.


}
final del bloque de bucle for

x=x *

¡Aaaa! ¡No se compilará! ¡Está fuera de alcance aquí! (Esta no es la
} forma en que funciona en otros idiomas, ¡así que ten cuidado!)

final del bloque de método, ahora x también está fuera de alcance

usted está aquí 663


Machine Translated by Google

invocaciones vinculadas

#6 Invocaciones vinculadas

StringBuffer sb = nuevo StringBuffer(“primavera”);

sb = [Link](3,6).insert(2,”umme”).deleteCharAt(1);

[Link](“sb = + alguien);

// el resultado es sb = verano

[Link](3,6) eliminar()

borrar()

insertar()
insertar()

sb = [Link](3,6);
sb = [Link](2,”umme”);
sb = [Link](1);

clase Foo {
público estático vacío principal (String [] args) [
nuevo Foo().go(); queremos llamar a go(), pero no nos importa la
} instancia de Foo, por lo que no nos molestamos en
asignar el nuevo objeto Foo a una referencia.
ir vacío() {
// esto es lo que REALMENTE queremos...
}

664 apéndice B
Machine Translated by Google

Apéndice B Referencia de los diez principales

#5 clases anidadas estáticas y anónimas

Las clases anidadas vienen en muchos estilos

clases anidadas estáticas

estático

Una clase anidada estática es simplemente


clase pública FooOuter { eso: una clase encerrada dentro de otra
y marcada con el modificador estático.
clase estática BarInner {
void decirlo() {
[Link](“método de una clase interna estática”);
}
}
} Debido a que una clase anidada estática es... estática,
nombre
el
no se utiliza una instancia de la clase externa. solo usas
de la clase, de la misma manera que invocas estática
prueba de clase { métodos o acceder a variables estáticas.

público estático vacío principal (String[] args) {

[Link] foo = nuevo [Link]();


[Link]();

usted está aquí 665


Machine Translated by Google

cuando las matrices no son suficientes

N.º 5 clases anidadas estáticas y anónimas, continuación

La diferencia entre anidado y interno

Clases internas anónimas

importar [Link].*;
importar [Link].*; Creamos un marco y agregamos un botón, y ahora
prueba de clase públicaAnon { necesitamos registrar un oyente de acción con el botón.
público estático vacío principal (String[] args) { Excepto que nunca creamos una clase que implemente
la interfaz ActionListener...
Marco JFrame = nuevo JFrame();
Botón JButton = nuevo JButton(“hacer clic”); Normalmente haríamos algo como esto: pasar una
[Link]().add(botón); referencia a una instancia de una clase interna... una
// botó[Link](quitListener); clase interna que implementa ActionListener (y el
método actionPerformed()).
Esta declaración:
Pero ahora, en lugar de pasar una referencia
botó[Link](nuevo ActionListener() { de objeto, pasamos... ¡¡toda la nueva
acción vacía pública realizada (ActionEvent ev) {
medicina
definición de clase!! En otras palabras,
[Link](0); escribimos la clase que implementa
} Ac­tionListener JUSTO AQUÍ DONDE LA
}); NECESITAMOS. La sintaxis también crea
Tenga en cuenta que decimos “nuevo ActionListener()” una instancia de la clase automáticamente.
aunque ActionListener es una interfaz y, por lo tanto,
no puede HACER una instancia de ella. Pero esta
¡Termina aquí abajo!
sintaxis realmente significa “crear una nueva clase
(sin nombre) que implemente la interfaz
ActionListener y, por cierto, aquí está la implementación
} de los métodos de la interfaz .actionPerformed().
}

666 apéndice B
Machine Translated by Google

niveles de acceso Apéndice B Referencia de los diez principales

#4 Niveles de acceso y modificadores de acceso (quién ve qué)

Niveles de acceso

público significa que cualquier código en cualquier lugar puede acceder al objeto
público (por "objeto" nos referimos a clase, variable, método, constructor, etc.).

protected funciona igual que el predeterminado (el código en el mismo paquete tiene acceso), EXCEPTO que
también permite que las subclases fuera del paquete hereden lo protegido.

acceso predeterminado significa que solo el código dentro del mismo paquete que la
clase con el elemento predeterminado puede acceder al elemento predeterminado.

privado significa que solo el código dentro de la misma clase puede acceder al objeto privado.
Tenga en cuenta que significa privado para la clase, no privado para el objeto. Un Perro puede ver las
cosas privadas de otro objeto Perro, pero un Gato no puede ver las partes privadas de un Perro.

Modificadores de acceso

público
protegido
privado

público

privado

usted está aquí 667


Machine Translated by Google

cuando las matrices no son suficientes

#4 Niveles de acceso y modificadores de acceso, cont.

predeterminado y protegido

por defecto

protegido

668 apéndice B
Machine Translated by Google

Cadena y StringBuffer Apéndice B Referencia de los diez principales

#3 Métodos String y StringBuffer/StringBuilder

usted está aquí 669


Machine Translated by Google

cuando las matrices no son suficientes

# 2 matrices multidimensionales

int[][] a2d = nuevo int [4][2];

a2d[1] los enteros regulares van dentro de


cada uno de los ocho elementos
a2d[0][0] a2d[2][1]
a2d[0][1]
a2d[3][0]

En t En t En t En t

En t
En t
matriz entera (int[]) matriz entera (int[])
matriz entera (int[])
En t
En t

matriz
entera (int[])

4 variables de referencia int[]

En t[] En t[] En t[] En t[]


a2d

objeto de matriz int (int[][]) Recuerde que la matriz en sí es un objeto (una


En t[][] matriz que contiene referencias a matrices int)

Trabajar con matrices multidimensionales

int x = a2d[2][1]; // recuerda, ¡basado en 0!


int[] copiar = a2d[1];
entero[][] x = { { 2,3,4 }, { 7,8,9 } };

int[][] y = nuevo int [2][]; y[0] = nuevo // crea solo la primera matriz, con una longitud de 2
int [3]; y[1] = nuevo int [5]; // hace que la primera submatriz tenga 3 elementos de longitud
// hace que la segunda submatriz tenga 5 elementos de longitud

670 apéndice B
Machine Translated by Google

enumeraciones Apéndice B Referencia de los diez principales

Y el tema número uno que no llegó a aparecer...

#1 Enumeraciones (también llamadas tipos enumerados o enumeraciones)

JFrameEXIT_ON_CLOSE
final estático

público estático final int JERRY = 1;


público estático final int BOBBY = 2;
público estático final int PHIL = 3;

// más adelante en el código


¡Esperamos que cuando lleguemos aquí,
“selectedBandMember” tenga un valor válido!
if (miembro de banda seleccionado == JERRY) {
// hacer cosas relacionadas con JERRY
}

ALEMÁN 1
miembro de la banda seleccionado

12 3
miembro de la banda seleccionado 812

usted está aquí 671


Machine Translated by Google

cuando las matrices no son suficientes

#1 Enumeraciones, cont.

Esto parece una definición de clase simple, ¿no?


Resulta que las enumeraciones SON un tipo
Miembros de enumeración pública {JERRY, BOBBY, PHIL}; especial de clase. Aquí hemos creado un nuevo
Miembros públicos seleccionadosBandMember; tipo enumerado llamado "Miembros".

// más adelante en el código


La variable “selectedBandMember” es de tipo “Miembros” y SÓLO
if (miembro de banda seleccionada == [Link]) { puede tener un valor de “JERRY”, “BOBBY” o “PHIL”.
// hacer cosas relacionadas con JERRY
}

¡No hay necesidad de preocuparse por el valor de esta variable! La sintaxis para referirse a una "instancia" de enumeración.

Su enumeración extiende [Link]

[Link]

Usando "si" y "cambiar" con enumeraciones

si cambia
== ==
.igual()

Asignar un valor de enumeración a una variable.

Miembros n = [Link];
if ([Link]([Link])) [Link](“¡Jerrrry!”);
if (n == [Link]) [Link](“Perro Rata”); ¡Ambos funcionan bien!

"Perro Rata" está impreso.


Miembros ifName = [Link];
cambiar (siNombre) {
caso JERRY: [Link](“hazlo cantar”);
caso PHIL: [Link](“profundizar”); ¡Examen sorpresa! ¿Cuál es el resultado?
caso BOBBY: [Link](“¡Cassidy! ”);
}
¡profundiza Cassidy

Respuesta:

672 apéndice B
Machine Translated by Google

enumeraciones Apéndice B Referencia de los diez principales

#1 Enumeraciones, completadas
Una versión realmente mejorada de una enumeración similar

clase pública HfjEnum { Este es un argumento pasado al


constructor declarado a continuación.
nombres de enumeración {
Se trata de los llamados
JERRY(“guitarra solista”) { public String canta() {
“organismos de clases constantes y específicos”.
regresar “quejumbroso”; }
Piense en ellos como anulando el método
},
BOBBY(“guitarra rítmica”) { public String canta() { de enumeración básico (en este caso, el

regresar “con voz ronca”; } método “sing()”), si se llama a sing() en


}, una variable con un valor de enumeración
PHIL(“bajo”); de JERRY o BOBBY.

instrumento de cuerda privado;

Nombres (instrumento de cuerda) { Este es el constructor de la enumeración. Se


[Link] = instrumento; ejecuta una vez por cada valor de enumeración
} declarado (en este caso se ejecuta tres veces).
cadena pública getInstrumento() {
devolver este instrumento;
}
cadena pública canta() { Verás que estos métodos se llaman desde "main()".
regresar “ocasionalmente”;
}
}

público estático vacío principal (String [] argumentos) { Cada enumeración viene con
para (Nombres n: [Link]()) { un método "values()" incorporado
[Link](n);
que normalmente se usa en un
[Link](“, instrumento: “+ [Link]());
bucle "for", como se muestra.
[Link](“, canta: “ + [Link]());
}
}
} Ventana de edición de archivos Ayuda pirata

% java HfjEnum
Tenga en cuenta que el método básico
JERRY, instrumento: guitarra solista, canta: lastimeramente
BOBBY, instrumento: guitarra rítmica, canta: con voz ronca "sing()" solo se llama cuando el valor de
PHIL, instrumento: bajo, canta: ocasionalmente enumeración no tiene un cuerpo de
%
clase específico de constante.

usted está aquí 673


Machine Translated by Google

cuando las matrices no son suficientes

Cinco minutos Un largo viaje a casa

Misterio El Capitán Byte de la nave espacial Flatland “Traverser” había recibido una transmisión urgente y ultrasecreta desde el
cuartel general. El mensaje contenía 30 códigos de navegación fuertemente cifrados que el Traverser necesitaría
para trazar con éxito un rumbo de regreso a través de sectores enemigos. Los hackarianos enemigos, de una
galaxia vecina, habían ideado un rayo diabólico de codificación de códigos que era capaz de crear objetos falsos en el
montón de la única computadora de navegación del Traverser. En
Además, el rayo alienígena podría alterar variables de referencia válidas para que se refirieran a estos
objetos falsos. La única defensa que tenía la tripulación del Traverser contra este malvado rayo hackariano era
para ejecutar un comprobador de virus en línea que podría integrarse en el estado del arte del Traverser
Código Java 1.4.

El Capitán Byte le dio al Alférez Smith las siguientes instrucciones de programación para procesar los críticos
códigos de navegación:

“Coloque los primeros cinco códigos en una matriz de tipo ParsecKey. Coloque los últimos 25 códigos en una matriz
bidimensional de cinco por cinco de tipo QuadrantKey. Pase estas dos matrices al método plotCourse() de la clase
pública final ShipNavigation. Una vez que se devuelve el objeto del curso, ejecute el comprobador de virus en línea
contra todas las variables de referencia del programa y luego ejecute el programa NavSim y tráigame los resultados”.

Unos minutos más tarde, el alférez Smith regresó con la salida de NavSim. “Salida de NavSim lista para revisión,
señor”, declaró el alférez Smith. “Bien”, respondió el Capitán, “por favor revise su trabajo”. “¡Sí señor!”, respondió el
Alférez, “Primero declaré y construí un array de tipo ParsecKey con el siguiente código; ParsecKey [] p = nueva
ParsecKey[5]; , a continuación declaré y construí una matriz de tipo QuadrantKey con el siguiente código: QuadrantKey
[] [] q = new QuadrantKey [5] [5]; .
A continuación, cargué los primeros 5 códigos en la matriz ParsecKey usando un bucle 'for' y luego cargué los últimos 25
códigos en la matriz QuadrantKey usando bucles 'for' anidados. A continuación, ejecuté el comprobador de virus con las
32 variables de referencia, 1 para la matriz ParsecKey y 5 para sus elementos, 1 para la matriz QuadrantKey y 25 para
sus elementos. Una vez que la verificación de virus regresó sin detectar virus, ejecuté el programa NavSim y volví a
ejecutar el comprobador de virus, solo para estar seguro... ¡Señor! “

El Capitán Byte le dio al Alférez una larga y fría mirada y dijo con calma: "Alférez, está confinado en una celda por
poner en peligro la seguridad de este barco. No quiero volver a ver su cara en este puente hasta que haya aprendido
correctamente su Java". ! ¡Teniente Boolean, reemplace al Alférez y haga este trabajo correctamente!

¿Por qué el capitán confinó al alférez en sus habitaciones?

674 apéndice B
Machine Translated by Google

respuestas del rompecabezas Apéndice B Referencia de los diez principales

Solución misteriosa de cinco minutos

usted está aquí 675


Machine Translated by Google
Machine Translated by Google

El índice

Índice

Símbolos

A
Ver

Ver

Ver también

usted está aquí 677


Machine Translated by Google

El índice

Ver

Ver también

Ver

Ver

índice 678
Machine Translated by Google

El índice

Ver también

mi

métodos 305

usted está aquí 679


Machine Translated by Google

El índice

Ver

argumento 300

GRAMO

F
Ver también

Ver también

índice 680
Machine Translated by Google

El índice

Ver también

Ver también

usted está aquí 681


Machine Translated by Google

El índice

Ver

Ver

Ver

k
Ver

l
Ver

índice 682
Machine Translated by Google

El índice

Ver
Ver
Ver

norte

Ver también

Ver

METRO

oh

usted está aquí 683


Machine Translated by Google

El índice

Ver

PAG

Ver

Ver

Ver

Ver

índice 684
Machine Translated by Google

El índice

Ver también

Ver también

Ver

q
R
S
Ver

Ver

Ver

Ver
Ver también

usted está aquí 685


Machine Translated by Google

El índice

Ver también

Ver también

Ver

Ver

Ver

Ver también

especificador de argumentos 300

índice 686
Machine Translated by Google

El índice

Ud.

Ver también
V

Ver

W.
Ver

Ver

usted está aquí 687


Machine Translated by Google

El índice

¿No conoces el sitio web? esto no es un adios


¡Tenemos respuestas a algunos de
los Sharpens, ejemplos, Code Kitchens, Lleva tu cerebro a
Ready­bake Code y actualizaciones [Link]
diarias de los blogs de los autores de Head First!

índice 688
Machine Translated by Google

Machine Translated by Google
Cabeza
Lo  que  están  diciendo  sobre
Primero
Machine Translated by Google
Cabeza
Java
Primero
Elogios  para
Machine Translated by Google
Cabeza
libros  en  coautoría  de  Kathy  y  Bert
Primero
alabanza  para  otros
Machine Translated by Google
Cabeza  primero  EJB™
Hormiga:  La  Guía  Definitiva™
Primero  los  servlets
Primero  los  patrones  de  diseño
Mejor,  más  
Segunda  edicion
Beijing  •  Cambridge  •  Colonia  •  París  •  Sebastopol  •  Taipei  •  Tokio
¿No  sería  fantástico  si  
Segunda  edicion
Dirígete  primero  a  Java™
Diseñadores  de  interiores:
Diseñador  de  la  portada:
Editor:
Historial  de  
Machine Translated by Google
Bert  Bates
Aunque  Kathy  y  Bert  intentan  responder  tantos  correos  electrónicos  como  pueden,  el  volumen  de  corre
yo  introducción
ix
A  Apéndice  A:  Código  final  cocina
xxx
27
659
12  Una  historia  muy  gráfica:  introducción  a  la  

También podría gustarte