Red de conocimiento informático - Material del sitio web - ¿Cómo se organizan y gestionan las clases en Java?

¿Cómo se organizan y gestionan las clases en Java?

Comparando JAVA y C

Como programador de C, ya dominamos los conceptos básicos de la programación orientada a objetos y, sin duda, la sintaxis de Java nos resulta muy familiar. De hecho, Java se derivó originalmente de C ".

Sin embargo, todavía existen algunas diferencias significativas entre C y Java. Se puede decir que estas diferencias representan un gran avance en la tecnología. Una vez que aclaremos estas diferencias , entenderemos por qué Java se considera un excelente lenguaje de programación. Este apéndice lo guiará a través de algunas de las características importantes que distinguen a Java de C.

(1) El mayor obstáculo es la velocidad: Java interpretado es. aproximadamente 20 veces más lento que C. No hay nada que impida que el lenguaje Java se compile. En el momento de escribir este artículo, existen algunos compiladores casi en tiempo real que pueden acelerar mucho las cosas, por supuesto. Hay razones para creer que son nativos puros. Los compiladores aparecerán en plataformas más populares, pero sin estos compiladores, Java definitivamente no podrá resolver algunos problemas debido a limitaciones de velocidad.

(2) Al igual que C., Java también proporciona dos tipos de anotaciones

(3) Todo debe colocarse en una clase sin funciones globales o datos globales. Si desea obtener la funcionalidad equivalente a las funciones globales, considere colocar métodos estáticos y datos estáticos en una clase. estructuras, enumeraciones o uniones; ¡todo es una clase!

(4) Todos los métodos están definidos en el cuerpo de la clase. Por lo tanto, desde una perspectiva C, todas las funciones parecen estar integradas, pero esto. no es el caso (los problemas de incrustación se presentarán más adelante)

(5) En Java, la forma de definición de clase es casi la misma que en C. Pero no hay punto y coma para marcar el final de la declaración de clase. , solo la definición de clase

void aMethod()

}

(6)

(6) No hay operador de alcance. ":::" en Java. Java usa notación de puntos para todas las operaciones, pero el punto no es necesario porque los elementos dentro de un elemento solo se pueden definir dentro de una clase. Incluso esas definiciones de métodos deben estar dentro de la clase, por lo que no hay ninguna. No es necesario especificar el alcance. Una diferencia que notamos es que para llamadas a métodos estáticos: use ClassName.methodName(). Además, el nombre del paquete se crea con puntos y la palabra clave import se puede usar para implementar algunos de los. Funciones "#include" de C. Por ejemplo, la siguiente declaración

import java.awt.*;

(#include no se asigna directamente a import, pero tiene una función similar sensación cuando se usa)

(7) Similar a C, Java contiene un grupo de "tipos primitivos" para un acceso eficiente. En Java, estos tipos incluyen boolean, char, byte, short, int, long, float. y doble. Los tamaños de todos los tipos primitivos son intrínsecos e independientes de la máquina (para tener en cuenta cuestiones de portabilidad). Esto definitivamente tendrá algún impacto en el rendimiento, dependiendo de la máquina. En Java, la verificación de tipos y los requisitos se han vuelto más estrictos. Por ejemplo:

■ Las expresiones condicionales sólo pueden ser de tipo booleano (booleano), no de tipo entero.

■ Debes usar el resultado de una expresión como X Y; no puedes usar simplemente "X Y" para lograr un "efecto secundario".

(8) El tipo de carácter utiliza el conjunto de caracteres Unicode de 16 bits aceptado internacionalmente, por lo que puede expresar automáticamente caracteres de la mayoría de los países.

(9) Las cadenas de referencia estáticas se convertirán automáticamente en objetos de cadena. A diferencia de C y C, no hay disponible una cadena de matriz de caracteres estática separada.

(10)Java ha agregado tres operadores de desplazamiento a la derecha "gt; gt; gt;", cuya función es similar al operador de desplazamiento a la derecha "lógico", es decir, insertar un valor cero al final. "gt;gt;" inserta un bit de signo mientras se desplaza (es decir, un desplazamiento "aritmético").

(11) Aunque superficialmente similares, los arreglos de Java utilizan estructuras que son bastante diferentes de las de C y tienen un comportamiento único. Hay un miembro de longitud de solo lectura que le permite saber qué tan grande es la matriz. Una vez que se exceden los límites de la matriz, la verificación en tiempo de ejecución genera automáticamente una excepción. Todas las matrices se crean en el "montón" de memoria y podemos asignar una matriz a otra (simplemente copie el identificador de la matriz). Los identificadores de matriz pertenecen a objetos de primer nivel y todos sus métodos generalmente están disponibles para todos los demás objetos.

(12) Para todos los objetos de tipos no primarios, solo se pueden crear mediante el nuevo comando. A diferencia de C, Java no tiene ningún comando para crear objetos de tipo no primario en la "pila". Todos los tipos principales solo se pueden crear en la pila, sin utilizar el nuevo comando. Todos los tipos principales tienen sus propias clases "contenedores", por lo que pueden crear objetos equivalentes basados ​​en "montón" de memoria a través de new (excepto matrices de los tipos principales: se pueden inicializar a través de colecciones como C o asignar usando new).

(13) No se requiere declaración previa en Java. Si desea utilizar una clase o método antes de definirlo, úselo directamente y el compilador se asegurará de que se utilice la definición correcta. Por lo tanto, a diferencia de C, no encontramos ningún problema relacionado con las referencias tempranas.

(14) Java no tiene preprocesador. Si desea utilizar una clase de otra biblioteca, simplemente use el comando de importación y especifique el nombre de la biblioteca. No existen macros similares a los preprocesadores.

(15) Java reemplaza los espacios de nombres con paquetes. Dado que todo se coloca en una clase y se utiliza un mecanismo llamado "encapsulación" para hacer algo similar a la descomposición del espacio de nombres* del nombre de la clase, la denominación ya no es un problema. Los paquetes también pueden recopilar componentes de biblioteca bajo un único nombre de biblioteca. Simplemente "importamos" un paquete y el compilador hace el resto.

(16) Los identificadores de objetos definidos como miembros de la clase se inicializarán automáticamente a nulo. Si no se inicializan explícitamente, obtendrán un valor predeterminado (0 o equivalente). Se pueden inicializar explícitamente (inicialización explícita): se pueden definir en la clase o en el constructor. La sintaxis utilizada es más fácil de entender que la de C, y la sintaxis tanto para los miembros estáticos como para los no estáticos es fija. No tenemos que definir el almacenamiento de miembros estáticos externamente, a diferencia de C.

(17) No hay punteros en C y C en Java. Cuando usas new para crear un objeto, obtienes una referencia (siempre llamada "identificador" en este libro). Por ejemplo:

String s = new String("howdy");

Sin embargo, las referencias de C deben inicializarse cuando se crean y no se pueden redefinir en una ubicación diferente. Sin embargo, las referencias de Java no se limitan necesariamente a la ubicación donde se crean. Se pueden definir arbitrariamente según la situación real, lo que elimina hasta cierto punto la necesidad de punteros. Otra razón para el uso intensivo de punteros en C y C es que los punteros pueden apuntar a ubicaciones de memoria arbitrarias (lo que también hace que los punteros sean inseguros, razón por la cual Java no proporciona este soporte). Los punteros a menudo se consideran un medio eficaz para moverse por matrices de variables primitivas, y Java nos permite lograr el mismo objetivo de una forma más segura. La solución definitiva al problema del puntero es el "método inherente" (que se analiza en el Apéndice A). Pasar un puntero a un método no suele ser un problema porque no hay funciones globales, sólo una clase.

También podemos pasar referencias a objetos; originalmente se afirmó que el lenguaje Java era "sin punteros". Pero debido a que muchos programadores preguntaron cómo trabajar sin punteros, el lenguaje Java fue declarado un lenguaje "sin punteros". Luego, indica "usar punteros restringidos". En cuanto a si es "realmente" un puntero, depende de su propio juicio. Pero de todos modos, no existe el puntero "matemáticas".

(18) Java proporciona un constructor similar a C. Si no define un constructor usted mismo, obtendrá un constructor predeterminado. Si define un constructor no predeterminado, el constructor predeterminado no se definirá automáticamente para nosotros. Esto es lo mismo que C. Tenga en cuenta que, dado que todos los argumentos se pasan por referencia, no existe un generador de copias.

(19) No existe ningún destructor en Java. Las variables no tienen "alcance". La "edad" de un objeto está determinada por cuánto tiempo existe el objeto, no por el recolector de basura. Cada miembro de la clase tiene un método finalize(), que es algo similar al "destructor" de C. Pero el recolector de basura llama al método finalize() y solo es responsable de liberar "recursos" (archivos abiertos, sockets, puertos, URL, etc.). Para hacer algo en una ubicación específica, debe crear un método especial y llamarlo, en lugar de depender de finalize(). Por otro lado, todos los objetos en C se destruyen (o "deberían" destruirse), pero no todos los objetos en Java se recolectan como "basura". Dado que Java no admite el concepto de destructores, debe tener cuidado al crear métodos de limpieza cuando sea necesario. También debe llamar explícitamente a todos los métodos de limpieza de la clase base y a los objetos miembro de la clase.

(20) Java tiene un mecanismo de "sobrecarga" de métodos que funciona casi igual que la sobrecarga de funciones de C.

(21) Java no admite variables predeterminadas.

(22)Java no tiene goto; utiliza el mecanismo de salto incondicional "marca de interrupción" o "criterio de continuación" para saltar de los múltiples bucles anidados actuales.

(23) Java utiliza una única jerarquía raíz, por lo que todos los objetos heredan uniformemente de la clase raíz Objeto. En C puedes iniciar un nuevo árbol de herencia en cualquier lugar, por lo que terminarás con un "bosque". En Java tenemos una sola jerarquía. Si bien esto puede parecer una limitación en la superficie, a menudo es más poderoso porque sabemos que cada objeto debe tener al menos una interfaz de objeto, y C parece ser el único lenguaje OO actualmente que no tiene una estructura de raíz única obligatoria.

(24) Java no tiene plantillas ni otras formas de tipos parametrizados. Proporciona una serie de colecciones: Vector, Stack y Hashtable que se pueden utilizar para contener referencias de objetos. Muchos de nuestros requisitos se pueden cumplir utilizando estas colecciones. Sin embargo, estas colecciones no están diseñadas para ser llamadas tan rápidamente como la "Biblioteca de plantillas estándar" (STL) de C. Aunque las nuevas colecciones en Java 1.2 son más completas, todavía no se pueden usar tan eficientemente como las plantillas reales.

(25) "Recolección de basura" significa que las pérdidas de memoria en Java son mucho menos probables, pero no completamente imposibles (el recolector de basura no puede realizar un seguimiento del método inherente de asignación de espacio de almacenamiento. llamada). Sin embargo, los agujeros de memoria y de recursos son causados ​​principalmente por finalize() mal escrito o por la liberación de recursos al final del bloque de asignación (aquí es donde los "destructores" resultan útiles). El recolector de basura fue una gran mejora con respecto a C e hizo desaparecer muchos problemas de programación. Sin embargo, existen algunos problemas para los que el recolector de basura no es adecuado. Sin embargo, las muchas ventajas del recolector de basura hacen que esta desventaja parezca insignificante.

(26) Java tiene soporte integrado para subprocesos múltiples.

A través de una clase Thread especial, podemos crear un nuevo hilo mediante herencia (abandonando el método run()). Si utiliza la palabra clave sincronizada como restricción de tipo para un método, la exclusión mutua se produce a nivel de objeto. En cualquier momento, sólo un hilo puede utilizar los métodos sincronizados de un objeto. Por otro lado, cuando llega un método sincronizado, primero "bloquea" el objeto, impidiendo que cualquier otro método sincronizado lo utilice. Sólo cuando el método sale "desbloquea" el objeto. Entre subprocesos, sigue siendo nuestra responsabilidad implementar mecanismos de sincronización más complejos mediante la creación de nuestras propias clases de "monitoreo". El método de sincronización recursiva funciona bien. Si los subprocesos tienen la misma prioridad, no se garantiza el "corte" del tiempo.

(27) En lugar de controlar el bloque de declaración como en C, agregamos calificadores de acceso (público, privado y protegido) a la definición de cada miembro de la clase. Si no se especifica ningún calificador "explícito" (inequívoco), el valor predeterminado es "amigable". Esto significa que pueden acceder a él otros elementos en la misma bolsa (equivalente a "amigos" en C), pero no ningún elemento fuera de la bolsa. Las clases y cada método dentro de una clase tienen un calificador de acceso que determina si la clase es "visible" fuera del archivo. La palabra clave privada generalmente rara vez se usa en Java porque el acceso "amigable" suele ser más útil que excluir el acceso de otras clases en el mismo paquete. Sin embargo, en un entorno de subprocesos múltiples, es importante utilizar privado de forma adecuada; la palabra clave protegida de Java significa "accesible para los herederos y otros elementos del paquete". Tenga en cuenta que Java no tiene equivalente a la palabra clave protected de C, que significa "accesible sólo para herederos" (antes era posible lograr esto usando "protegido privado", pero la combinación de los dos ha quedado obsoleta).

(28) Clases anidadas. En C, las clases anidadas ayudan a ocultar nombres y organizar el código (pero los "espacios de nombres" de C hacen que la ocultación de nombres sea redundante). El concepto de Java de "encapsulación" o "empaquetado" es equivalente a los espacios de nombres de C, por lo que esto ya no es un problema. Java 1.1 introdujo el concepto de "clases internas", que secretamente mantienen un identificador de la clase externa, necesario al crear objetos de clase interna. Esto significa que los objetos de la clase interna pueden acceder a la clase externa. Esto significa que el objeto de clase interna puede acceder incondicionalmente a los miembros del objeto de clase externa como si estos miembros estuvieran directamente adjuntos al objeto de clase interna. Esto proporciona una mejor solución al problema de la devolución de llamada: C resuelve este problema con punteros a los miembros.

(29) Los punteros a miembros no existen en Java porque existen clases internas del tipo descrito anteriormente.

(30) Java no tiene métodos en línea; el compilador de Java puede incrustar un método a su discreción, pero ya no tenemos control sobre esto. En Java, puede "sugerir" la incrustación* utilizando la palabra clave final de un método. Sin embargo, incorporar funciones es sólo una sugerencia para el compilador de C.

(31) La herencia en Java tiene el mismo efecto que la herencia en C, pero la sintaxis es diferente: Java usa la palabra clave extends para marcar la herencia de la clase base y usa la palabra clave super para señalar la clase base. clase base destinada a llamar al método, que tiene el mismo nombre que el método en el que nos encontramos actualmente (sin embargo, la palabra clave super en Java solo nos permite acceder a los métodos de la clase principal sin tener la intención de llamar a los métodos de la clase principal). alcance de la clase base en C. Podemos acceder a métodos más profundos en la jerarquía. Los generadores de clases base también se pueden llamar usando la palabra clave super. Como se mencionó anteriormente, todas las clases finalmente heredan automáticamente de Object. A diferencia de C, no existe una lista de inicialización de constructores explícita.

Sin embargo, el compilador nos obliga a realizar toda la inicialización de la clase base al comienzo del cuerpo del constructor y no nos permite hacerlo más adelante en el cuerpo. La inicialización de miembros se puede garantizar de manera efectiva mediante el uso de una combinación de inicialización automática y excepciones de identificadores de objetos no inicializados.

(32) La herencia en Java no cambia el nivel de protección de los miembros de la clase base. En Java no podemos especificar herencia pública, privada o protegida, al igual que en C. Además, un método preferido en una clase derivada no puede reducir el acceso a un método de clase base. Por ejemplo, si un miembro es público en la clase base y lo reemplazamos con otro método, entonces el método utilizado para el reemplazo también debe ser público (el compilador verificará esto automáticamente).

(33) Java proporciona una palabra clave de interfaz para crear equivalentes de clases base abstractas. Contiene métodos abstractos pero no miembros de datos. Esto crea una clara distinción entre el diseño como una interfaz y el diseño como una extensión de la funcionalidad existente utilizando la palabra clave extends. Usar la palabra clave abstracta no tiene un efecto similar porque no podemos crear un objeto que pertenezca a esa clase. Una clase abstracta puede contener métodos abstractos (aunque no es necesario contener nada dentro de ellos), pero también puede contener código para implementaciones concretas. Por tanto, las clases abstractas se limitan a la herencia única. Utilizado junto con interfaces, este enfoque evita la necesidad de mecanismos como las clases base virtuales de C.

Para crear una versión de una interfaz que pueda ser "ejemplada" (es decir, crear una instancia), debe utilizar la palabra clave implementación. La sintaxis es similar a la herencia.

(34) No existe una palabra clave virtual en Java porque todos los métodos no estáticos deben utilizar enlace dinámico. En Java, el programador no tiene que decidir si utilizará el enlace dinámico. La razón por la que C usa virtual es que cuando ajustamos el rendimiento, omitir virtual hace que la ejecución sea un poco más eficiente (o para decirlo de otra manera: "si no lo usas, no pagas por ello"). Lo virtual suele causar cierta confusión, con resultados desagradables. La última palabra clave especifica el alcance de algunos ajustes de rendimiento: indica al compilador que el método no se puede reemplazar, por lo que su alcance puede estar vinculado estáticamente (y estará incrustado en el estado, por lo que debe usar una llamada no virtual equivalente). Estas optimizaciones las realiza el compilador.

(35) Java no proporciona herencia múltiple (MI), al menos no en la forma en que lo hace C. Al igual que los mecanismos protegidos, MI es una buena idea en la superficie, pero realmente no te darás cuenta de que la necesitas hasta que te enfrentes a un problema de diseño específico. Dado que Java utiliza una jerarquía de "raíz única", MI solo es necesaria en casos excepcionales y la palabra clave interfaz ayuda a fusionar automáticamente varias interfaces.

(36) El identificador de tipo de tiempo de ejecución es muy similar a C. Por ejemplo, para obtener información sobre el identificador X, utilice el siguiente código:

/p>

derived d = (derived )base

Esto es lo mismo que el anterior; Modelado estilo C. El compilador invoca automáticamente el mecanismo de modelado dinámico sin necesidad de sintaxis adicional. Si bien no tiene la ventaja de un modelado fácilmente dirigido como las "nuevas versiones" de C, Java verifica el uso y genera "excepciones" para no permitir un modelado incorrecto como lo hace C.

(37) Java adopta un enfoque diferente para el control de excepciones porque no tiene un constructor. Se puede agregar una cláusula finalmente para forzar la limpieza necesaria para una declaración específica, y todas las excepciones en Java heredan de la clase base Throwable, lo que garantiza que obtengamos una interfaz común.

(38) La especificación de excepción de Java es mucho mejor que la especificación de excepción de C. Después de que se genera una excepción de error, Java no llama a una función en tiempo de ejecución como C, sino que verifica y aplica la especificación de excepción en tiempo de compilación. Además, los métodos reemplazados deben cumplir con la especificación de excepción de la versión de la clase base del método: pueden generar las excepciones especificadas u otras excepciones derivadas de estas excepciones. De esta manera, terminamos con un código de control de excepciones más "robusto".

(39) Java puede sobrecargar métodos, pero no operadores; la clase String no puede usar el operador = para conectar diferentes cadenas, y las expresiones String usan conversión automática de tipos, pero este es un caso especial incorporado.

(40) El problema constante que ocurre a menudo en C se controla en Java mediante un acuerdo previo. Sólo podemos pasar identificadores a objetos; las copias locales nunca se generan automáticamente. Si desea utilizar una técnica similar al paso por valor de C, puede llamar a clone(), que generará una copia local de la herramienta (aunque el diseño de clone() aún es tosco; consulte el Capítulo 12). Actualmente no existe ningún generador de copias que se invoque automáticamente. Para crear un valor constante en tiempo de compilación, codifique como este:

static final int TAMAÑO = 255

static final int BSIZE = 8 * TAMAÑO

(41 ) Por razones de seguridad, existen diferencias de seguridad significativas entre la programación de "aplicaciones" y la programación de "piezas". Uno de los problemas más evidentes es que el programa no nos permite escribir en el disco*, porque al hacerlo puede provocar que un programa desconocido descargado desde un sitio remoto sobrescriba nuestro disco. Esto cambió con la introducción de firmas digitales en Java 1.1. A partir de la firma digital podemos conocer exactamente todos los autores del fragmento de programa y verificar que están autorizados. Java 1.2 mejorará aún más la funcionalidad de los fragmentos de programa.

(42) Debido a que Java parece ser demasiado restrictivo en algunos casos, a veces es reacio a usarlo para realizar tareas importantes, como acceder directamente al hardware. La solución de Java a este problema son los "métodos propios", que nos permiten llamar a funciones escritas en otros lenguajes (actualmente solo se admiten C y C++). De esta manera ciertamente podemos resolver problemas relacionados con la plataforma (de forma no portátil, pero el código estará aislado). Los fragmentos de programa no pueden llamar a métodos inherentes, sólo las aplicaciones pueden hacerlo.

(43) Java proporciona soporte integrado para documentación de anotaciones, por lo que los archivos fuente también pueden contener su propia documentación. Con un solo programa, la información de este documento se puede extraer y reformatear en HTML, lo que supone una gran mejora para la gestión de documentos y las aplicaciones.

(44) Java contiene una gran cantidad de bibliotecas estándar para tareas específicas, mientras que c se basa en una gran cantidad de bibliotecas no estándar proporcionadas por otros proveedores. Estas tareas incluyen (o pronto incluirán):

■Conexiones de red

■Conexiones de bases de datos (a través de JDBC)

■Multiproceso

■Objetos distribuidos (vía RMI y CORBA)

■Comercio electrónico

■Compresión

■Comercio electrónico

■ Comercio electrónico

Debido a que estas bibliotecas son muy simples y estándar, pueden acelerar enormemente el desarrollo de aplicaciones.

(45) Java 1.1 incluye el estándar Java Beans, que crea componentes para entornos de programación visual. Al cumplir con los mismos estándares, los componentes de visualización se pueden utilizar en entornos de desarrollo de todos los proveedores. Debido a que no dependemos de la solución de un solo proveedor al diseñar componentes de visualización, la selectividad de los componentes aumenta y el rendimiento mejora.

Además, Java Beans está diseñado para ser simple y fácil de entender para los programadores, mientras que los marcos de componentes especializados desarrollados por diferentes proveedores requieren un aprendizaje más profundo.

(46) Si falla el acceso al identificador de Java, se generará una excepción. No es necesario realizar esta prueba de descarte exactamente antes de utilizar el mango. Según las especificaciones de diseño de Java, esto simplemente significa que se debe lanzar una excepción de alguna forma. Muchos sistemas de ejecución de C también pueden descartar excepciones causadas por errores de puntero.

(47) En general, Java parece ser más robusto y su implementación es la siguiente:

■ El identificador del objeto se inicializa en nulo (una palabra clave)

■ Los identificadores siempre se verifican y se lanzan excepciones en caso de errores

■ Todos los accesos a la matriz se verifican y las violaciones de límites se descubren rápidamente

■ Recolección automática de basura para evitar vulnerabilidades en la memoria

■ Control de excepciones explícito y "tonto"

■ Soporte de lenguaje simple para subprocesos múltiples

■ Verificación de código de bytes de fragmentos de programas de red y