0% encontró este documento útil (0 votos)
40 vistas20 páginas

Estructuras de Datos en Java: Vectores y Listas

El documento describe diferentes estructuras de datos para almacenar objetos en Java, incluyendo vectores, matrices y listas. Explica cómo crear y manipular estas estructuras, agregando, eliminando y accediendo a elementos.

Cargado por

est.cajhon
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 DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
40 vistas20 páginas

Estructuras de Datos en Java: Vectores y Listas

El documento describe diferentes estructuras de datos para almacenar objetos en Java, incluyendo vectores, matrices y listas. Explica cómo crear y manipular estas estructuras, agregando, eliminando y accediendo a elementos.

Cargado por

est.cajhon
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 DOCX, PDF, TXT o lee en línea desde Scribd

6.

ESTRUCTURAS DE DATOS CON OBJETOS

6.1 La clase String, y sus métodos

(ProgramacionJava, 2020)
Manejo de vectores con Objetos

Los arrays en Java son suficientes para guardar tipos básicos de datos, y objetos de una

determinada clase cuyo número conocemos de antemano. Algunas veces deseamos guardar

objetos en un array, pero no sabemos cuántos objetos vamos a guardar. Una solución es la

de crear un array cuya dimensión sea más grande que el número de elementos que

necesitamos guardar. La clase Vector nos proporciona una solución alternativa a este

problema. Un vector es similar a un array, la diferencia estriba en que un vector crece

automáticamente cuando alcanza la dimensión inicial máxima. Además, proporciona

métodos adicionales para añadir, eliminar elementos, e insertar elementos entre otros dos

existentes.

Crear un vector

Para usar la clase Vector hemos de poner al principo del archivo del código fuente la

siguiente sentencia import

import java.util.*;

Cuando creamos un vector u objeto de la clase Vector, podemos especificar su

dimensión inicial, y cuanto crecerá si rebasamos dicha dimensión.

Vector vector=new Vector(20, 5);

Tenemos un vector con una dimensión inicial de 20 elementos. Si rebasamos dicha

dimensión y guardamos 21 elementos la dimensión del vector crece a 25.

Al segundo constructor, solamente se le pasa la dimensión inicial.

Vector vector=new Vector(20); Si se rebasa la dimensión inicial guardando 21

elementos, la dimensión del vector se duplica. El programador ha de tener cuidado con este

constructor, ya que si se pretende guardar un número grande de elementos se tiene que


especificar el incremento de la capacidad del vector, si no se quiere desperdiciar

inútilmente la memoria el ordenador.

Con el tercer constructor, se crea un vector cuya dimensión inicial es 10.

Vector vector=new Vector();

La dimensión del vector se duplica si se rebasa la dimensión inicial, por ejemplo,

cuando se pretende guardar once elementos.

Añadir elementos al vector:

Hay dos formas de añadir elementos a un vector. Podemos añadir un elemento a

continuación del último elemento del vector, mediante la función miembro addElement.

v.addElement("uno");

Podemos también insertar un elemento en una determinada posición, mediante

insertElementAt. El segundo parámetro o índice, indica el lugar que ocupará el nuevo

objeto. Si tratamos de insertar un elemento en una posición que no existe todavía

obtenemos una excepción del tipo ArrayIndexOutOfBounds. Por ejemplo, si tratamos de

insertar un elemento en la posición 9 cuando el vector solamente tiene cinco elementos.

Para insertar el string "tres" en la tercera posición del vector v, escribimos

v.insertElementAt("tres", 2);

Para saber cuántos elementos guarda un vector, se llama a la función miembro size. Para

saber la dimensión actual de un vector se llama a la función miembro capacity. Por

ejemplo, en la porción de código hemos guardado 12 elementos en el vector v. La


dimensión de v es 20, ya que se ha superado la dimensión inicial de 10 establecida en la

llamada al tercer constructor cuando se ha creado el vector v.

System.out.println("nº de elementos "+v.size());

System.out.println("dimensión "+v.capacity());

Podemos eliminar todos los elementos de un vector, llamando a la función miembro

removeAllElements. O bien, podemos eliminar un elemento concreto, por ejemplo, el que

guarda el string "tres".

v.removeElement("tres");

Podemos eliminar dicho elemento, si especificamos su índice.

v.removeElementAt(2) . (sc.ehu, 2011)

Manejo de matrices con Objetos

Un array en Java puede tener más de una dimensión. El caso más general son los arrays

bidimensionales también llamados matrices o tablas.


La dimensión de un array la determina el número de índices necesarios para acceder a sus

elementos. Los vectores que hemos visto en otra entrada anterior son arrays

unidimensionales porque solo utilizan un índice para acceder a cada elemento.

Una matriz necesita dos índices para acceder a sus elementos. Gráficamente podemos

representar una matriz como una tabla de n filas y m columnas cuyos elementos son todos

del mismo tipo.

La siguiente figura representa un array M de 3 filas y 5 columnas:

A los elementos del array se accede mediante la fila y columna donde están

situados. A efectos prácticos, cuando trabajamos con arrays bidimensionales podemos

pensar en una tabla como la que se muestra en la imagen anterior donde los elementos están

distribuidos en filas y columnas. Pero en realidad una matriz en Java es un array de arrays.

La disposición real en memoria del array anterior la podemos representar gráficamente de

esta forma:
M es el nombre del array.

M contiene la dirección de memoria (referencia) de un array unidimensional de 3

elementos.

Cada elemento de este array unidimensional contiene la dirección de memoria de otro array

unidimensional.

Cada uno de estos últimos arrays unidimensionales contiene los valores de cada fila de la

matriz.

M.length indica el número de filas de la matriz. En este ejemplo el número de filas

(M.length) es 3.

M[i].length indica el nímero de columnas de la fila i. En este ejemplo la longitud de cada

fila del array (M[i].length) es 5.

Para acceder a cada elemento de la matriz se utilizan dos índices. El primero indica la fila y

el segundo la columna.

M[0][2] = 9; //asigna el valor 9 al elemento situado en la primera fila (fila 0) y tercera

columna (fila 2).

No dedemos olvidar que la primera fila de una matriz es la fila 0 y la primera columna de

una matriz es la columna 0.


CREAR MATRICES EN JAVA

Se crean de forma similar a los arrays unidimensionales, añadiendo un

índice.

Por ejemplo:

matriz de datos de tipo int llamado ventas de 4 filas y 6 columnas:

int [][] ventas = new int[4][6];

matriz de datos double llamado temperaturas de 3 filas y 4 columnas:

double [][] temperaturas = new double[3][4];

En Java se pueden crear arrays irregulares en los que el número de elementos de

cada fila es variable. Solo es obligatorio indicar el número de filas.

Por ejemplo:

int [][] m = new int[3][];

crea una matriz m de 3 filas.

A cada fila se le puede asignar un número distinto de columnas:

m[0] = new int[3];

m[1] = new int[5];

m[2] = new int[2];

Gráficamente podemos representar la disposición real en memoria del array anterior así:
INICIALIZAR MATRICES

Un array es un objeto, por lo tanto, cuando se crea, a sus elementos se les asigna

automáticamente un valor inicial:

0 para arrays numéricos

'\u0000' (carácter nulo) para arrays de caracteres

false para arrays booleanos

null para arrays de String y de referencias a objetos

También podemos dar otros valores iniciales al array cuando se crea.

Los valores iniciales se escriben entre llaves separados por comas.

Los valores que se le asignen a cada fila aparecerán a su vez entre llaves separados por

comas.

El número de valores determina el tamaño de la matriz.

Por ejemplo:

int [][] numeros = {{6,7,5},{3, 8, 4}, {1,0,2}, {9,5,2}};

se crea la matriz numeros de tipo int, de 4 filas y 3 columnas, y se le asignan esos valores

iniciales.

Asignando valores iniciales se pueden crear también matrices irregulares.

Por ejemplo la instrucción:

int [][] a = {{6,7,5,0,4}, {3, 8, 4}, {1,0,2,7}, {9,5}};

crea una matriz irregular de 4 filas. La primera de 5 columnas, la segunda de 3, la tercera de

4 y la cuarta de 2.

Tomado de. (puntocomnoesunlenguaje, 2021)

Manejo de listas con objetos


Java ArrayList for y size()

La forma más sencilla de recorrer una lista es a través de un bucle for y accediendo a la

propiedad size.

java arraylist for clasico

Veámoslo en código:

package com.arquitecturajava;
import java.util.ArrayList;
public class JavaFor {
public static void main(String[] args) {

ArrayList<String> lista = new ArrayList<String>();

lista.add("hola");
lista.add("que");
lista.add("tal");
lista.add("estas");
lista.add("hoy");

for (int i=0;i<lista.size();i++) {

System.out.println(lista.get(i));
}
}
}

Cuando uno empieza esta forma parece la más clara y no parece tener mucha

problemática . Sin embargo algunas veces sucede que los desarrolladores al recorrer la

lista no asignan correctamente el lista.size() o ponen otro valor sobre todo cuando se es
muy novato. Por lo tanto puede generarse un NullPointerException. No solo eso sino

que es una forma de recorrer elementos que solo nos vale para los ArrayList.

Java for e Iteradores

Una alternativa a esta situación es usar un Iterador .Un Iterador es un interface que

dispone de los métodos hasNext() y next() y nos permite recorrer una colección de

elementos.

java arraylist for

Da lo mismo que sea un ArrayList que otra estructura. Por lo tanto aporta

homogeneidad en las APIs.

package com.arquitecturajava;

import java.util.ArrayList;

import java.util.Iterator;

public class JavaFor2 {

public static void main(String[] args) {

ArrayList<String> lista = new ArrayList<String>();

lista.add("hola");

lista.add("que");

lista.add("tal");

lista.add("estas");
lista.add("hoy");

Iterator<String> it= lista.iterator();

while(it.hasNext()) {

System.out.println(it.next());

Java 5 ArrayList for

A partir de Java 5 aparece el concepto de bucle forEach y permite simplificar la forma

en la que trabajamos con los Iteradores.

package com.arquitecturajava;

import java.util.ArrayList;

public class JavaFor3 {

public static void main(String[] args) {

ArrayList<String> lista = new ArrayList<String>();

lista.add("hola");

lista.add("que");

lista.add("tal");

lista.add("estas");

lista.add("hoy");
for (String cadena: lista) {

System.out.println(cadena);

Como se puede observar la forma de recorrer una lista se simplifica sobremanera

comparado con el Iterador que aunque genera homogeneidad siempre era complicado

de usar. Esta es una de las opciones más recomendadas hasta la llegada de Java 8.

Java 8 y Streams.

En Java 8 tenemos un salto importante a niveles de programación ya que entran todas

las capacidades funcionales y con ello se pueden simplificar el manejo de listas a través

de streams.

package com.arquitecturajava;
import java.util.ArrayList;
public class JavaFor3 {
public static void main(String[] args) {
ArrayList<String> lista = new ArrayList<String>();
lista.add("hola");
lista.add("que");
lista.add("tal");
lista.add("estas");
lista.add("hoy");

lista.forEach(System.out::println);
}
}

La simplificación es clara aun así nos quedan situaciones clásicas en las que un bucle de

forEach de Java 5 nos aporta más ya que por ejemplo deseamos cambiar el contenido de

los elementos del Array y luego imprimirlo.

package com.arquitecturajava;
import java.util.ArrayList;
public class JavaFor6 {
public static void main(String[] args) {
ArrayList<String> lista = new ArrayList<String>();
lista.add("hola");
lista.add("que");
lista.add("tal");
lista.add("estas");
lista.add("hoy");
for (int i = 0; i < lista.size(); i++) {
lista.set(i, lista.get(i).toUpperCase());
}
for (String cadena : lista) {
System.out.println(cadena);
}
}
}

Este bloque nos recorrerá el array y volverá a recorrerlo de una forma clásica para

mostrar la información en pantalla actualizada. (java, 2019)

7. INTERFAZ GRÁFICA
8. SEGURIDAD ALGORITMOS DE CIFRADO

8.1 SHA-256

Las siglas SHA-256 hacen mención a la función hash que ha sido elegida para el

funcionamiento de muchas criptomonedas pues ofrece un alto nivel de seguridad, lo que la

hace perfecta para la tarea de proteger y codificar de forma segura la información de las

mismas.

Existen muchos sistemas para codificar la información y uno de ellos es el algoritmo

SHA-256. Este es un algoritmo de hash que es usado por Bitcoin para garantizar la

integridad de la información almacenada en un bloque, entre otras cosas.

Como casi todos los avances en materia de criptografía, los gobiernos del mundo han

tenido un papel fundamental debido a las guerras. El algoritmo SHA o Secure Hash

Algorithm (Algoritmo de Hash Seguro), es uno de estos avances. Este algoritmo

criptográfico fue desarrollado por la Agencia de Seguridad Nacional de los Estados Unidos

(NSA) y el National Institute of Standards and Technology (NIST). Su objetivo es generar

hashes o códigos únicos en base a un estándar con el que se pudieran asegurar documentos

o datos informáticos frente a cualquier agente externo que desee modificarlos. Este

algoritmo fue y es un gran avance en el camino a garantizar la privacidad del contenido en

el procesamiento de información.

En 1993 salió a la luz el primer protocolo SHA, también llamado coloquialmente SHA-

0. Dos años más tarde, se publicó una variante mejorada más resistente, el SHA-1. Algunos
años más tarde se lanzó SHA-2, que tiene cuatro variantes según el número de bits, como

son SHA-224, SHA-256, SHA-384 y SHA-512.

Características del algoritmo SHA-256

Un algoritmo hash funciona en una sola dirección: esto quiere decir que de cualquier

contenido podemos generar su hash (su “huella dáctilar digital”) pero de un hash no hay

forma de generar el contenido asociado a él, salvo probando al azar hasta dar con el

contenido.

Entre las diferentes formas de crear hashes, el algoritmo usado por SHA-256 es uno de

los más usados por su equilibrio entre seguridad y coste computacional de generación, pues

es un algoritmo muy eficiente para la alta resistencia de colisión que tiene.

Otra de las particularidades del algoritmo de hash SHA-256 es que la longitud del hash

resultante es siempre igual, no importa lo extenso que sea el contenido que uses para

generar el hash: ya sea de una letra o todas las palabras del libro de Harry Potter entero, el

resultado siempre es una cadena de 64 de letras y números (con una codificación de 256

bits, 32 bytes).

El objetivo del hash SHA-256 (y de toda función hash) es la de generar un resumen.

Para entender de forma simple y más detallada todo esto, no te pierdas el capítulo dedicado

a explicar las funciones hash.

En Bitcoin, el SHA-256 se utiliza para el proceso de minería (creación de bitcoins), pero

también en el proceso de generar direcciones bitcoin. Esto es así por el gran nivel de

seguridad que ofrece.


Dentro de la red blockchain todos los nodos tendrían una copia del hash de 64 caracteres

que representa la información que representa, por ejemplo, a todo un bloque. Una vez esa

información está validada por la red (o lo que es lo mismo, ya ha quedado registrada en la

cadena) cualquier manipulación de esa información intentando modificar algún carácter del

hash validado, sería detectada de forma inmediata y se descartaría.

Para aumentar la información técnica sobre esta función hash criptográfica, te

recomendamos descargar y leer el paper en español “Criptografía: Función SHA-256” de

Javier Domínguez Gómez, ingeniero de software español y hacktivista en Free Software

Foundation y Electronic Frontier Foundation.

Tomado de (academy.bit2me, 2021)

8.2 AES: Cifrado AES-256

Advanced Encryption Standard (AES) es uno de los algoritmos de cifrado más utilizados

y seguros actualmente disponibles. Es de acceso público, y es el cifrado que la NSA utiliza

para asegurar documentos con la clasificación "top secret". Su historia de éxito se inició en

1997, cuando el NIST (Instituto Nacional de Estándares y Tecnología) comenzó

oficialmente a buscar un sucesor al envejecimiento cifrado estándar DES. Un algoritmo

llamado "Rijndael", desarrollado por los criptografistas belgas Daemen y Rijmen,

sobresalía tanto en seguridad como en rendimiento y flexibilidad.

Apareció en la cima de varios competidores y se anunció oficialmente el nuevo estándar

de cifrado AES en 2001. El algoritmo se basa en varias sustituciones, permutaciones y

transformaciones lineales, cada una ejecutada en bloques de datos de 16 bytes - por lo tanto
el término blockcipher. Esas operaciones se repiten varias veces, llamadas "rondas".

Durante cada ronda, una clave circular única se calcula a partir de la clave de cifrado y se

incorpora en los cálculos. Basado en la estructura de bloques de AES, el cambio de un solo

bit, ya sea en la clave, o en el bloque de texto sin cifrado, da como resultado un bloque de

texto cifrado completamente diferente - una ventaja clara sobre los cifrados de flujo

tradicionales. La diferencia entre AES-128, AES-192 y AES-256 finalmente es la longitud

de la clave: 128, 192 o 256 bits - todas las mejoras drásticas en comparación con la clave de

56 bits de DES. A modo de ilustración: El agrietamiento de una clave AES de 128 bits con

un superordenador de última generación tomaría más tiempo que la presunta edad del

universo. Y Boxcryptor incluso utiliza claves de 256 bits. Hasta el día de hoy, no existe un

ataque factible contra AES. Por lo tanto, AES sigue siendo el estándar de cifrado preferido

para los gobiernos, bancos y sistemas de alta seguridad en todo el mundo.

9. PERSISTENCIA CON ARCHIVOS

10. MODELO VISTA CONTROLADOR

Modelo Vista Controlador (MVC) es un estilo de arquitectura de software que separa los

datos de una aplicación, la interfaz de usuario, y la lógica de control en tres componentes

distintos.

Se trata de un modelo muy maduro y que ha demostrado su validez a lo largo de los años

en todo tipo de aplicaciones, y sobre multitud de lenguajes y plataformas de desarrollo.

El Modelo que contiene una representación de los datos que maneja el sistema, su lógica

de negocio, y sus mecanismos de persistencia.


La Vista, o interfaz de usuario, que compone la información que se envía al cliente y los

mecanismos interacción con éste.

El Controlador, que actúa como intermediario entre el Modelo y la Vista, gestionando el

flujo de información entre ellos y las transformaciones para adaptar los datos a las

necesidades de cada uno.

El modelo es el responsable de:

Acceder a la capa de almacenamiento de datos. Lo ideal es que el modelo sea

independiente del sistema de almacenamiento.

Define las reglas de negocio (la funcionalidad del sistema). Un ejemplo de regla puede

ser: "Si la mercancía pedida no está en el almacén, consultar el tiempo de entrega estándar

del proveedor".

Lleva un registro de las vistas y controladores del sistema.

Si estamos ante un modelo activo, notificará a las vistas los cambios que en los datos

pueda producir un agente externo (por ejemplo, un fichero por lotes que actualiza los

datos, un temporizador que desencadena una inserción, etc.).

El controlador es responsable de:

Recibe los eventos de entrada (un clic, un cambio en un campo de texto, etc.).

Contiene reglas de gestión de eventos, del tipo "SI Evento Z, entonces Acción W". Estas

acciones pueden suponer peticiones al modelo o a las vistas. Una de estas peticiones a las
vistas puede ser una llamada al método "Actualizar()". Una petición al modelo puede ser

"Obtener_tiempo_de_entrega ( nueva_orden_de_venta )".

Las vistas son responsables de:

Recibir datos del modelo y los muestra al usuario.

Tienen un registro de su controlador asociado (normalmente porque además lo

instancia).

Pueden dar el servicio de "Actualización ()", para que sea invocado por el controlador o

por el modelo (cuando es un modelo activo que informa de los cambios en los datos

producidos por otros agentes).

Flujo MVC

El usuario interactúa con la interfaz de usuario de alguna forma (por ejemplo, el usuario

pulsa un botón, enlace, etc.)

El controlador recibe (por parte de los objetos de la interfaz-vista) la notificación de la

acción solicitada por el usuario. El controlador gestiona el evento que llega, frecuentemente

a través de un gestor de eventos (handler) o callback.

El controlador accede al modelo, actualizándolo, posiblemente modificándolo de forma

adecuada a la acción solicitada por el usuario (por ejemplo, el controlador actualiza el carro

de la compra del usuario). Los controladores complejos están a menudo estructurados

usando un patrón de comando que encapsula las acciones y simplifica su extensión.

El controlador delega a los objetos de la vista la tarea de desplegar la interfaz de usuario.

La vista obtiene sus datos del modelo para generar la interfaz apropiada para el usuario

donde se refleja los cambios en el modelo (por ejemplo, produce un listado del contenido
del carro de la compra). El modelo no debe tener conocimiento directo sobre la vista. Sin

embargo, se podría utilizar el patrón Observador para proveer cierta indirección entre el

modelo y la vista, permitiendo al modelo notificar a los interesados de cualquier cambio.

Un objeto vista puede registrarse con el modelo y esperar a los cambios, pero aun así el

modelo en sí mismo sigue sin saber nada de la vista. El controlador no pasa objetos de

dominio (el modelo) a la vista aunque puede dar la orden a la vista para que se actualice.

Nota: En algunas implementaciones la vista no tiene acceso directo al modelo, dejando que

el controlador envíe los datos del modelo a la vista.

La interfaz de usuario espera nuevas interacciones del usuario, comenzando el ciclo

nuevamente.

También podría gustarte