martes, 8 de septiembre de 2020

Nociones Básicas de lenguaje de programación JAVA

Estructura Básica de JAVA

Java es un lenguaje muy funcional, fue diseñado para ser parecido a C++, concretamente para facilitar un rápido y fácil aprendizaje para un gran número de programadores.

Java elimina muchas de las características de C++, para mantener la simplicidad del lenguaje añade caracteristicas muy útiles como el "garbage collector"(reciclador de memoria dinámica o recolector automático de basura).

No es necesario preocuparse de liberar memoria, el recolector de basura se encarga de ello. Como es una aplicación que se ejecuta "en segundo plano" (programa que se ejecuta en memoria de forma concurrente a otras a otroas aplicaciones) y es de baja prioridad, cuando entra en acción, permite liberar bloques de memoria muy grande, lo que mejora la gestion de la memoria.

Java reduce en un 50% los errores más comunes de programación con lenguajes como C y C++ al eliminar michas de las características de éstos, entre las que destacan:

    1.- Aritmética de punteros
    2.- registros (struct)
    3.- definición de tipos(typedef)
    4.- macros(#define)
    5.- necesidad de liberar memoria(free)


Lenguaje Orientado a Objetos.

Java implementa la tecnología básica de C++ con algunas mejoras y elimina algunas cosas para mantener el objetivo de la simplicidad del lenguaje.

    * Java trabaja con sus datos como objetos y con interfaces a esos objetos.
    * Soporta las tres características propias de la orientación a objetos:
        1. encapsulación
        2. herencia
        3. polimorfismo

    * Las plantillas de objetos son llamadas, clases y sus copias, instancias.
    * Las instancias necesitan ser construidas y destruidas en espacios de memoria.
    * Java incorpora funcionalidad llamada resolución dinámica de métodos(no existe en C++).
    * C++ trabaja con librerías dinámicas(DLLs) que obligan a recopilar la aplicación cuando se retocan las funciones que se encuentran en su interior. Este inconveniente es el resulto por Java, mediante una interfaz específica llamad RTTI(RunTime Type Indentification, Identificación de Tipo en Tiempo de Ejecución). Las clases en Java tiene una representación que permite a los programadores interrogar en tiempo de ejecución por el tipo de clases y asociar dinamicamente la clase con el resultado de la búsqueda.

Distribuido

Java se ha construido con grandes capacidades de interconexión TCP/IP. Existen librerías de rutinas para acceder e interactuar con protocolos como el protocolo HTTP y el protocolo FTP. Esto permite a los programadores acceder a la información a través de la red con tanta facilidad como a los ficheros locales.

Lo que realmente hace Java es proporcionar las librerías y herramientas para que los programas puedan seer distribuidos, es decir, que se corran en varias maquinas  interactuando entre ellas.

Verificaciones


Java realiza verificaciones en busca de problemas en tiempo de compilación y en tiempo de ejecución.

- La comprobación de tipos en java ayuda a detectar errores, lo antes posible, en la fase de implementación. En Java la declaración de un método se hace justo antes de su definición indicando en ella los tipos de datos pasados como argumentos y el tipo de dato envuelto, reduciendo así las posibilidades de error.
- Maneja la memoria para eliminar las preocupaciones por parte del programador de la liberación de memoria o de la corrupción de memoria.
- Implementa los arrays como bloques de memoria contiguos con comprobación de límites, para evitar la posibilidad de sobrescribir o corromper memoria a causa de punteros que señalan a zonas equivocadas. Estas características reducen drásticamente el tiempo de desarrollo de aplicaciones Java.
- Para asegurar el funcionamiento de la aplicación, realiza una verificación de los bytecodes. No es el código máquina directamente entendible por el hardware, pero ha pasado la fase del compilador, como el análisis de instrucciones, orden de operaciones, etc., y ya tiene generada la pila de ejecución de órdenes.

Arquitectura neutral

Para establecer Java como parte integral de la red, el compilador Java compila su código a un fichero objeto de formato independiente de la arquitectura de la máquina en que se ejecutará. Cualquier máquina que tenga el sistema de ejecución(run-tine o maquina virtual Java) puede ejecutar ese código objeto, sin importar en modo alguno la máquina en que ha sido generado. Actualmente existen sistemas run-time para Solaris, SunOs, Windows, Linux, Irix, Aix, Mac, Apple.

El código fuente de Java se "compila" a un código de bytes de bajo nivel independiente de la máquina. Este código(bytecodes) está diseñado para ejecutarse en máquina hipotética que es implementada por un sistema run-time, que sí es dependiente de la máquina. Lo que es realmente dependiente de la máquina es la Máquina Virtual Java (JVM) y las librerías fundamentales, que también nos permitirían acceder directamente al hardware de la máquina.

Seguro

En el lenguaje Java, las características como los punteros o el casting(cambio de tipo de un objeto) implícito que hacen los compiladores de C y C++ se eliminan para prevenir el acceso ilegal a la memoria. El lenguaje C, por ejemplo, tiene lagunas de seguridad importantes. Por ejemplo, al desarrollar en C se utilizan punteros junto a operaciones aritméticas. Esto le permite al programador que un puntero haga referencia a un lugar conocido de la memoria y puede sumar o restar algún valor, para referirse a otro lugar de la memoria. Si otros programadores conocen nuestras estructuras de datos pueden extraer información confidencial de nuestro sistema.

El código Java pasa unas pruebas antes de ejecutarse en un máquina. El código se pasa a través de un verificador de bytecodes que comprueba el formato de los fragmentos de código y aplica un probador de teoremas para detectar fragmentos de código ilegal(código que falsea punteros, viola derechos de acceso sobre objetos o intenta cambiar el tipo o clase de un objeto.

Portable

Más allá de la portabilidad básica por ser de arquitectura independiente, Java implementa otros estandares de portabilidad para facilitar el desarrollo. Los enteros son siempre enteros además de ser enteros de 32 bits en complemento de 2, también Java construye sus interfaces de usuario a través de un sistema abstracto de ventanas de forma que las ventanas puedan ser implantadas en entornos unix, Pc o Mac.


Interpretado

El intérprete Java(sistema run-time o máquina virtual Java) puede ejecutar directamente los bytecodes. No obstante, Java es más lento que otros lenguajes de programación, más que C++, ya que debe ser interpretado antes de ser ejecutado en vez de ser ejecutado directamente como sucede en cualquier programa compilado de forma tradicional.



En definitiva Java para conseguir ser un lenguaje independiente del sistema operativo y del procesador que incorpore la máquina utilizada, es tanto interpretado como compilado. El código fuente escrito en cualquier editor se compila generando los bytecodes. Este código intermedio es de muy bajo nivel, pero sin alcanzar las instrucciones en código máquina propias de cada plataforma. Ese mismo código es el que se puede ejecutar sobre cualquier plataforma. Para ello hace falta la JVM, que sí es completamente dependiente de la máquina y del sistema operativo, que interpreta dinámicamente los bytecodes. Con este sistema es fácil crear aplicaciones multiplataforma, pero para ejecutarlas es necesario que exista la JVM correspondiente al sistema operativo utilizado.

Multihebrado

Al sr multihreaded(multihebrado), Java permite muchas actividades simultáneas en un programa. Los hilos(a veces llamados, procesos ligeros), que son piezasa independientes(líneas de ejecución) de un proceso. No ha de confundirse un hilo con un proceso. Hilo es la unidad mínima ejecutable, mientras que proceso es la unidad mínima planificable. Un proceso está formado por hilos. Al estar los hilos construidos en el lenguaje, son más fáciles de usar y más robustos que sis homólogos en C o C++.

Por ejemplo, es posible que el interfaz gráfico de una aplicación(las ventanas, botones, controles, etc) se ejecutan en un hilo(thread) encargado de dibujarlos en la pantalla, mientras que las acciones que llevan asociadas se ejecutan en otro, consiguiendo una respuesta más rápida de la aplicación.
 


Dinámico

Java se beneficia todo lo posible de la tecnología orientada a objetos. Java no intenta conectar todos los módulos que comprenden una aplicación hasta el tiempo de ejecución. Las librerías nuevas o actualizadas no paralizan las aplicaciones actuales(siempre que mantengan el API anterior).

Java también simplifica el uso de protocolos nuevos o actualizados. Sí un sistema dado ejecuta una aplicación Java sobre la red y encuentra una pieza de la aplicación que no sabe manejar, Java es capaz de traer automaticamente cualquiera de esas piezas que el sistema necesita para funcionar.

JDK

La herramienta básica para empezar a desarrollar aplicaciones o applets en Java es el JDK(Java Development Kit o kit de desarrollo Java), que consiste basicamente en un compliador y un intérprete(JVM) para la línea de comandos. No dispone de un entorno de desarrollo integrado (IDE), pero es suficiente para aprender el lenguaje y desarrollar pequeñas aplicaciones. Es todo lo que necesitamos para poder compilar y ejecutar nuestros programas Java.

La API de Java está formada por varios paquetes que se distribuyen con el JDK como biblioteca de clases. Estos paquetes proporcionan una interfaz común para desarrollar aplicaciones Java en todas las plataformas Java.

La API de Java está formada por varios paquetes de desarrollo principales y de un paquete de soporte de depuración. Estos paquetes son colecciones de objetos relacionados. Por ejemplo, vienen separados según se trate de programas de ventas, mini-aplicaciones, software de conexión, etc.
 

Nivel léxico, gramatical y semántico de los lenguajes de programación

Uno de los objetivos de los lenguajes de programación de alto nivel es que son fáciles de entender, por eso todos los lenguajes de programación de alto nivel como Java, C, C++, python y otros tienen una estructura similar al lenguaje natural(ingles), Aunque existen construcciones concretras que las pueden diferenciar entre diferentes lenguajes.

Una de las diferencias y que no esta a simple vista se concretra en la forma de compilar e interpretar que se traducen en el texto escrito en el lenguaje de alto nivel a código máquina y ejecutable por el ordenador.

Como ya hemos visto, Java no es muy distinto de cualquier otro lenguaje, incluido el castellano. Casi todos hemos empezado aprendiendo las letras que forman parte del alfabeto de nuestra lengua, y en todo caso, usemos el método que usemos para aprender a leer, seguro que tenemos que usarlas de una en una al escribir un texto. Igual ocurre en Java. El lenguaje se construye sobre un alfabeto, un conjunto de símbolos que son los que podemos emplear para escribir nuestros programas.

Tradicionalmente, el alfabeto que venía usándose para todos los lenguajes de programación era el código ASCII de 8 bits, lo que permitía un conjunto de 256 símbolos distintos, que más o menos coincidían con los caracteres usados en la mayoría de los países occidentales. Pero eso imposibilitaba el uso de caracteres propios de los idiomas de muchos paises.

Para evitar ese problema, Java ha incorporado como alfabeto el código Unicode, que es un nuevo código estándar de E/S que isa 16 bits para representar cada carácter, lo que da un número suficientemente amplio(2^16 = 65.536 posibles caracteres distintos).

El código Unicode es totalmente compatible con ASCII, ya que respeta el código ASCII, lo que realmente hace es colocar 8 bits a cero delante para convertirlos en Unicode.

Nivel léxico: Tokenización

Inicialmente el compilador percibe nuestro fichero de texto con el código fuente en Java como una secuencia de caracteres, que le van siendo suministrados uno a uno, tal como se escribre y de los cuales  tiene que ir extrayendo las palabras con significado propio(tokens, en la jerga informatica que se refiere a la compilación). Este proceso e el análisis léxico de nuestro programa, y se denomina tokenización. Para ello, algunos caracteres tendrán que interpretarse de forma especial por el compilador, indicándole que ahí termina un token y comienza otro. Son los separadores, y así tenemos la primera noción léxica que introduciremos, la de separador.

En Java se consideran separadores los siguientes caracteres/grupos de caracteres:

- Espacio en blanco: es el típico separador. Es un carácter más del alfabeto(Unicode), pero cuya misión es introducir un corte entre dos palabras.
- Return: es el símbolo de return, intro o nueva línea. Es un separador con exactamente las mismas propiedades que un espacio en blanco.
- Tabulador: denominado también otro separador.
- comentario: un comentario cumple asimismo las funciones de separador. Los comentarios poseen la función de documentación sobre el código fuente, pero desde el punto léxico del lenguaje, son más que separadores.
- Operador: actúan como separadores que permiten defierenciar tokens distintos, pero con la peculiaridad de que se mantienen a sí mismos como tokens significativos, por lo que no podrán ser sustituidos por ningún otro separador. Son las excepción a la regla que mecionamosen los párrafos siguientes.

Ejemplo: la expresión a=3+4 incluye dos operadores (= y +) que permiten separar el nombre de la variable "a" del primer operadory éste del segundo operando 4, generando la secuencia de tokens a, =, 3, +, 4.

Durante la primera fase de análisis del código fuente, el análisis léxico, el compilador de Java aplica la siguiente regla:

Toda secuencia de uno o más separadores se sustituye por un único espacio en blanco que establece una división entre tokens.

Tipos de tokens


no todos los tokens son iguales ni todos deben ser interpretados de  la misma forma.  Los tipos de tokens en Java son:

- Palabras reservadas
- Operadores
- Literales
- Identificadores

Ejemplo:

int numero = 8;

* int, se usa para indicar lo que ponemos a continuación va a ser una variable de tipo entero. El lenguaje Java le da un significado concreto, y no podemos usarla con ningún otro sentido que no sea el reservado para ella por el lenguaje. Por eso es una palabra reservada.
* numero, es el nombre que he decidido darle a la variable. Cualquier elemento que yo use en el lenguaje debe tener un nombre (variables, constantes, clases, métodos, etc.) y ese nombre lo elige el programador que lo crea, de esta forma nos permite identificarlo y distinguirlo de otros elementos. Es un identificador.
* =, es un operador de asignación que indica ina operación o acción a realizar, en este caso se le asigna a la variable con nombre "numero" el valor que lleva detras de "=", en este caso 8.
* 8, representa el valor concreto que forman la categoría de los enteros en Java. Es un valor literalm un literal de tipo entero.


Tipos básicos o primitivos

Cada uno de los tipos básicos tiene una palabra reservada asociada que permite declarar variables como pertenecientes a ese tipo. En la unidad 2, donde hablábamos de los tipos de datos y sus características, ya hicimos una introducción a los tipos básicos de Java.

La declaración de una variable consiste en indicar el tipo de los valores que va a almacenar seguido del nombre de esa variable, que nos va a permitir referirnos de forma cómoda al valor que contiene.

Java es un lenguaje fuertemente tipado, que quiere decir que no podremos usar ninguna variable si previamente no le hemos asignado un tipo. Además el lenguaje se preocupa de comprobar exhaustivamente que cualquier valor que se intenta guardar en una variable sea exactamente del mismo tipo que la variable. Además, cada tipo nos proporciona una serie de operaciones disponibles para usar con los datos de ese tipo.

Los tipos primitivos en Java son: boolean, char, byte, short, int, long, float, double.

Literales de los tipos primitivos.

Cada tipo tiene por tanto su conjunto finito de valores válidos. Por ejemplo, de tipo Boolean, sólo permite dos valores posibles, que son true(verdadero) y false(falso). Estos valores, aunque son literales, funcionan en la práctica como palabras reservadas, ya que no pueden usarse con ningún otro significado en Java. Por ejemplo, no se puede crear una variable llamada true, o llamada false.

Por otro lado, los literales de tipo Char se representan mediante comillas simples. Cualquier símbolo Unicode situado entre comillas simples es un literal de tipo carácter. Ejemplo: 'A', 'a', '7', '?', '+'.

Los símbolos de Unicode correspondientes al ASCII (primer bloque de 8bits que forman Unicode, concretamente los 8bits menos significativos de unicode), se pueden representar asimismo en notación octal. Para ello, conociendo el valor octal de un carácter(N), el literal correspondiente se representa como'\N'. Por ejemplo si sabemos que tanto en ASCII como unicode, la letra A(mayúscula) es el símbolo número 65, y que 65 en octal es 101, podemos representar esta letra como '\101'.

Cualquier símbolo Unicode se puede especificar utilizando su valor hexadecimal, precedido por la secuencia de escape \u. Por ejemplo, si sabemos que el símbolo Pi mayúscula del griego se representa en unicode con el valor hexadecimal 0370, dicho carácter se especificará en Java como el literal '\u0370'.

Literales de tipo entero.

Un número entero se define como una secuenncia de dígitos(0-9) que puede llevar delante signo o no. La única precaución que hay que tener es que para cada tipo primitivo de enteros(byte, short, int y long) se deben utilizar valores comprendidos en su rango de valores permitidos.

Los números enteros se pueden especificar en tres notaciones: decimal, octal y hexadecimal.

Todos los números por defecto están escritos en base decimal, a excepcion de los números que comienzan por 0, que se consideran que están en base octal, y los que comienzan por Ox o 0x(es decir, de un cero seguido de una x, mayúscula o minúscula), que se tratan como números en hexadecimal, pudiendo contener en dicho caso, además de dígitos(los números del 0 al 9), las letras A, B, C, D, E, o F(en mayúsculas o minúsculas). Ejemplo:

- 90
- 0132
- 0X5A
- 0x5A
- 0X5a
- 0x5a

Literales de tipo real.

En Java hay dos tipos de números reales, que son float y double. La diferencia básica es la precisión de la representación y el rango de valores representables, debido al mayor tamaño de double, que usa 64 bits en vez de 32 de float para representar cada valor.

La diferencia entre float y double es que la utilización de un mayor número de bits en el caso de double permite aumentar tanto la precisión de mantisa(número de dígitos significativos) como los valores extremos del exponente.

En cualquier caso, lo que aquí nos interesa es la especificaciónv de literales de este tipo.

Un número se considera real si posee decimales(lo que supone que se utilice el punto de separación entre la parte entera y la decimal, aunque cualquiera de las dos puede estar vacía), o poseé un exponente(el exponente se introduce mediante la letra e ò E), o va precedido por una letra identificativa de tipo(que es f ò F para float y d ò D para double).

Según el criterio de utilización del punto(en ingles se utiliza el punto para la separación de los decimales, por lo que a estos números se los denomina de punto  flotante), los siguientes números son reales y no enteros:

- 137.36
- 137.
- .56

Si la parte entera o decimal es nula(valor igual a 0) se puede omitir. Mientras que 137 es número entero, 137. es un número real.

Un número real se puede representar como NeM(equivalente NEM), donde N es un número real y M es un entero. Ejemplo de números son todos reales y poseen en mismo valor:

- 1584.0
- 1584E1 = 1584e1 = 1584e+1
- 15.84E2
- 1.584E3
- .1584E4

Tipo float:

- 16f
- 16F
- 115.94f

Tipo double:

- 56823d
- 56823D
- 98.234d

es importante tener en cuenta que en caso de no especificar la letra postfija correspondiente al tipo float, todos los números reales se consideran de tipo double por defecto.

No hay comentarios:

Publicar un comentario