Análisis de código fuente stl java
Como programador de C++, dominamos los conceptos básicos de la programación orientada a objetos y, sin duda, la sintaxis de Java es 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 comprendamos estas diferencias, entenderemos por qué Java es una excelente herramienta de programación. Este apéndice le 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 y nada puede impedirlo. Compilación del lenguaje Java En el momento de escribir este artículo, acaban de surgir algunos compiladores casi en tiempo real que pueden acelerar significativamente las cosas. Por supuesto, hay muchas razones para pensar que habrá compiladores nativos puros para plataformas más populares, pero si. esos no están disponibles. Debe haber algunos problemas que Java no puede resolver 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. No hay funciones globales ni datos globales. Si desea el equivalente de funciones globales, considere colocar métodos estáticos y datos estáticos en una clase. ¡Solo hay "clases" como conjuntos!
(4) Todos los métodos están definidos en el cuerpo de la clase, por lo que desde una perspectiva de C++, parece que todas las funciones están en línea, pero esta no es la forma. caso (el tema de la incrustación se discutirá más adelante).
(5) En Java, la forma de definición de clase es casi la misma que la de C++, pero no hay punto y coma para marcar el final. class. Declaración, solo definición de clase.
Clase de tipo ()
Método vacío (){/*cuerpo del método*/}
}
(No existe un operador de alcance "::" en Java. Java usa notación de puntos para todo, pero no tienes que pensar en ello porque solo puedes definir elementos en una clase. Incluso esas definiciones de métodos deben ser en una clase, por lo que no es necesario especificar el alcance en absoluto. Una diferencia que notamos es el uso de ClassName.methodName() Además, el nombre del paquete se establece con puntos, que algunas funciones de "#include" en C++. puede hacer. Implementado usando la palabra clave import. Por ejemplo, la siguiente declaración:
Importar Java
(#include no se asigna directamente a importar, pero tiene. una sensación similar cuando se usa. )
(7) Al igual que C++, Java contiene una serie de "tipos primitivos" para lograr un acceso más eficiente. En Java, estos tipos incluyen booleano, char, byte, short, int, long, float y double. Los tamaños de todos los tipos principales son intrínsecos e independientes de la máquina específica (considere los problemas de portabilidad). Esto definitivamente afectará el rendimiento según la máquina. En Java, la verificación de tipos y los requisitos se vuelven más estrictos. . Por ejemplo:
■Las expresiones condicionales sólo pueden ser de tipo booleano, no se permiten números enteros.
■Debes usar el resultado de una expresión como X+Y; no puedes simplemente usar "X+Y" para lograr "efectos secundarios".
(8) El tipo char (carácter) utiliza el conjunto de caracteres Unicode de 16 bits aceptado internacionalmente, por lo que puede representar automáticamente caracteres en la mayoría de los países.
(9)Las cadenas con referencias estáticas se convertirán automáticamente en objetos de cadena. A diferencia de C y C++, no hay disponibles cadenas de matrices de caracteres estáticas independientes.
(10) Java agrega tres operadores de desplazamiento a la derecha ">:>;> son similares en función al operador lógico de desplazamiento a la derecha y pueden insertar valores cero al final & gt>En el desplazamiento". mientras se inserta un bit de signo (es decir, un desplazamiento "aritmético").
(11) Aunque aparentemente similares, los arreglos de Java adoptan una estructura completamente diferente y tienen un comportamiento único en comparación con C++. 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 descartará automáticamente la 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) Todos los objetos que no pertenecen al tipo principal sólo pueden crearse con el comando "Nuevo". A diferencia de C++, Java no tiene un comando correspondiente para crear objetos "en la pila" que no sean del tipo principal. Todos los tipos principales solo se pueden crear en la pila, sin utilizar el nuevo comando. Todas las clases principales tienen sus propias clases "contenedores", por lo que se pueden crear objetos equivalentes basados en el "montón" de memoria a través de new (la excepción son las matrices de tipos principales: se pueden asignar mediante la inicialización de la colección como en C++, o usando new) .
(13) No se requiere declaración previa en Java. Si desea utilizar una clase o método antes de definirlo, simplemente úselo; el compilador se asegurará de que se utilice la definición correcta. Entonces, a diferencia de C++, no enfrentamos 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 hay macros tipo preprocesador.
(15) Java reemplaza los espacios de nombres con paquetes. Debido a que todo se coloca en una clase y a que se utiliza un mecanismo llamado "encapsulación", que puede hacer algo similar a la descomposición del espacio de nombres de los nombres de clases, la cuestión de los nombres ya no entra en nuestro ámbito de consideración. Este paquete también recopila los componentes de la biblioteca bajo un único nombre de biblioteca. Sólo necesitamos "importar" un paquete y el compilador hará el resto del trabajo automáticamente.
(16) Los identificadores de objetos definidos como miembros de la clase se inicializan automáticamente para quedar vacíos. En Java, la inicialización de los miembros de datos de la clase básica está garantizada de forma fiable. Si no se inicializan explícitamente, adquirirán un valor predeterminado (cero o equivalente). Se pueden inicializar explícitamente: se pueden definir en una clase o en un generador. La sintaxis utilizada es más fácil de entender que la de C++ y es fija tanto para miembros estáticos como no estáticos. No tenemos que definir cómo se almacenan externamente los miembros estáticos, a diferencia de C++.
(17) En Java, no existen punteros como C y C++. Cuando creas un objeto con new, obtienes una referencia (a la que a lo largo de este libro nos referimos como "identificador"). 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. Pero las referencias de Java no se limitan necesariamente a la ubicación cuando se crean. Se pueden definir arbitrariamente según la situación, eliminando parte de la necesidad de punteros. Otra razón para el uso generalizado de punteros en C y C++ es apuntar a cualquier ubicación de memoria (lo que también los hace inseguros, razón por la cual Java no proporciona este soporte). Generalmente se considera que los punteros son un medio eficaz para moverse dentro de matrices de variables primitivas. 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). Cuando se pasa un puntero a un método, generalmente no causa demasiado problema porque no hay funciones globales, solo clases. Podemos pasar una referencia a un objeto. El lenguaje Java originalmente afirmó que "no usa punteros en absoluto". Pero, como preguntaron muchos programadores, ¿cómo podría funcionar sin punteros? Más tarde se afirmó que "se utilizaron punteros restringidos". Es un indicador y usted mismo puede juzgar si es "verdadero" o no. Pero de todos modos, no existe una "aritmética" de punteros.
(18) Java proporciona un constructor similar a C++. Si no define uno usted mismo, obtendrá un constructor predeterminado. Si se define un constructor no predeterminado, no se definirá automáticamente un constructor predeterminado para nosotros. Esto es lo mismo que C++. Tenga en cuenta que no hay generadores de copias ya que todos los parámetros se pasan por referencia.
(19) No existe ningún "destructor" en Java. No hay ningún problema de "alcance" con las variables. La "vida útil" de un objeto está determinada por la vida útil del objeto, no por el recolector de basura. Hay un método finalize() que es miembro de cada clase, algo similar al "destructor" de C++.
Pero el recolector de basura llama a finalize() y solo es responsable de liberar "recursos" (como archivos abiertos, sockets, puertos, URL, etc.). Si desea hacer algo en un lugar específico, debe crear un lugar. método especial y llámalo. No puedo confiar en finalizar(). Por otro lado, todos los objetos en C++ son (o deberían ser) destruidos, pero no todos los objetos en Java se recolectan como "basura". Dado que Java no admite el concepto de destructores, debe crear cuidadosamente un método de limpieza cuando sea necesario. Además, todos los métodos de limpieza deben llamarse explícitamente para las clases base y los objetos miembro dentro de la clase.
(20) Java tiene un mecanismo de sobrecarga de métodos, que funciona casi exactamente igual que la sobrecarga de funciones de C++.
(21) Java no admite parámetros predeterminados.
(22) No hay ir a en Java. Su mecanismo de salto incondicional es "interrumpir" o "continuar", que se utiliza 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 del objeto de clase raíz. En C++, podemos iniciar un nuevo árbol de herencia en cualquier lugar, por lo que a menudo terminamos con un "bosque" que contiene una gran cantidad de árboles. En Java tenemos una sola jerarquía. Si bien esto puede parecer una limitación en la superficie, a menudo obtenemos mayor poder porque sabemos que cada objeto debe tener al menos una interfaz de objeto. Actualmente, C++ parece ser el único lenguaje OO que no impone una única estructura raíz.
(24) Java no tiene plantillas ni otras formas de tipos parametrizados. Proporciona una serie de colecciones: Vector (vector), Stack (pila) y Hashtable (tabla hash) para contener referencias de objetos. Con estas colecciones se pueden satisfacer una serie de necesidades. Sin embargo, estas colecciones no están diseñadas para una invocación rápida como la biblioteca de plantillas estándar (STL) de C++. Las nuevas colecciones de Java 1.2 son más completas, pero todavía no hace un uso eficiente de las plantillas auténticas.
(25) "Recolección de basura" significa que las pérdidas de memoria en Java serán mucho menores, pero no completamente imposibles (si se llama a un método inherente para asignar espacio de almacenamiento, el recolector de basura no puede rastrearlo ni monitorearlo) . Las lagunas de memoria y de recursos se deben principalmente a una finalización incorrecta () o a la liberación de un recurso al final de un bloque asignado (los "saboteadores" son particularmente convenientes en este momento). El recolector de basura es un avance importante basado en C++, que hace que muchos problemas de programación desaparezcan virtualmente. Pero para los pocos que recogen basura, no es adecuado. Sin embargo, las ventajas del recolector de basura hacen que esta desventaja parezca trivial.
(26) Java tiene soporte integrado para subprocesos múltiples. Con una clase Thread especial, podemos crear un nuevo hilo heredando (abandonando el método run()). Si la palabra clave sincronizada se utiliza como calificador de tipo para un método, se producirá una exclusión mutua a nivel de objeto. En un momento dado, sólo un hilo puede utilizar los métodos sincronizados de un objeto. Por otro lado, después de que ingresa un método sincronizado, primero "bloqueará" el objeto para evitar que cualquier otro método sincronizado vuelva a utilizar el objeto. Sólo saliendo de este método se "desbloqueará" el objeto. Entre subprocesos todavía somos responsables de implementar mecanismos de sincronización más complejos mediante la creación de nuestras propias clases de "monitoreo". Los métodos de sincronización recursivos funcionan bien. Si los subprocesos tienen la misma prioridad, no se garantiza la "fragmentación" temporal.
(27) No controlamos el bloque de código de declaración como C++, pero colocamos el calificador de acceso (público, privado, protegido) en la definición de cada miembro de la clase. Si no se especifica ningún calificador "explícito", el valor predeterminado es "amigable". Esto significa que otros elementos en el mismo paquete también pueden acceder a él (lo que equivale a convertirse en "amigos" de C++), pero ningún elemento fuera del paquete puede acceder a él. Una clase (y cada método que contiene) tiene un calificador de acceso que determina si es "visible" fuera del archivo. La palabra clave privada 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 muy importante utilizar privado correctamente. 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 protegida de C ++, que significa "accesible solo para herederos" (este propósito se logró anteriormente a través de "privado protegido", pero la combinación de este par de palabras clave se canceló).
(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 ocultar nombres sea redundante). El concepto de "encapsulación" o "empaquetado" en Java es equivalente al espacio de nombres de C++, por lo que ya no es un problema. Java 1.1 introdujo el concepto de "clases internas", que implícitamente retiene un identificador de la clase externa, necesario al crear objetos de clase interna. Esto significa que el objeto de clase interno puede acceder incondicionalmente a los miembros del objeto de clase externo, como si esos miembros estuvieran directamente subordinados al objeto de clase interno. Esto proporciona una mejor solución al problema de la devolución de llamada, que C++ resuelve con punteros a los miembros.
(29) Debido a las clases internas descritas anteriormente, no hay punteros a miembros en Java.
(30)No existe ningún método en línea en Java. El compilador de Java puede decidir incrustar un método por sí mismo, pero ya no tenemos control sobre él. En Java, la incrustación se puede "sugerir" utilizando la palabra clave final en un método. Sin embargo, las funciones en línea son sólo una sugerencia para los compiladores de C++.
(31) La herencia en Java tiene el mismo efecto que en C++, pero la sintaxis es diferente. Java usa la palabra clave extends para marcar la herencia de una clase base, y la palabra clave super para señalar el método que se llamará en la clase base. La palabra clave super tiene el mismo nombre que el método en el que nos encontramos actualmente (pero la palabra clave super en. Java solo nos permite acceder a los métodos de la clase principal (es decir, el nivel superior de la jerarquía). Al establecer el alcance de una clase base en C++, podemos acceder a métodos más profundos en la jerarquía. También se puede llamar al generador de clases base usando la palabra clave super. Como se señaló anteriormente, todas las clases eventualmente heredarán automáticamente de Object. A diferencia de C++, no existe una lista de inicialización de constructores explícita. Pero el compilador nos obligará a inicializar todas las clases básicas al comienzo del cuerpo del constructor y no nos permitirá hacerlo más adelante en el cuerpo. Al combinar la inicialización automática con excepciones de identificadores de objetos no inicializados, se puede garantizar de manera efectiva la inicialización de miembros.
(32)La herencia en Java no cambia el nivel de protección de los miembros de la clase base. No podemos especificar herencia pública, privada o protegida en Java, al igual que en C++. Además, los métodos de prioridad en clases derivadas no pueden reducir el acceso a los métodos de la 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 usado para el reemplazo también debe ser público (el compilador lo verificará automáticamente).
(33) Java proporciona una palabra clave de interfaz para crear equivalentes de clases básicas abstractas. Está lleno de métodos abstractos y sin miembros de datos. Por lo tanto, existe una clara distinción entre algo diseñado simplemente como una interfaz y una extensión de una función existente que utiliza la palabra clave extends. No vale la pena usar la palabra clave abstract para producir un efecto similar, ya que no podemos crear un objeto que pertenezca a esa clase. Una clase abstracta puede contener métodos abstractos (aunque no es necesario que contenga nada), pero también puede contener código para implementaciones concretas. Por tanto, se limita a una única herencia. Combinado con interfaces, este enfoque evita la necesidad de mecanismos como las clases base virtuales de C++.
Para crear una versión de una interfaz de la que se pueda "crear una instancia" (es decir, crear una instancia), es necesario utilizar la palabra clave implements. Su sintaxis es similar a la herencia.
(34) No hay palabras clave virtuales 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 porque cuando ajustamos el rendimiento, podemos omitirlo y obtener una pequeña mejora en la eficiencia de ejecución (o en otras palabras, "Si no lo usamos, no necesitamos pagar por ello") . La virtualización a menudo crea un nivel de confusión con resultados desagradables. La palabra clave final especifica cierto alcance para el ajuste del rendimiento: indica al compilador que este método no es reemplazable, por lo que su alcance puede estar vinculado estáticamente (mientras se incrusta, por lo que utiliza el método equivalente de llamadas no virtuales de C++). Estas optimizaciones las realiza el compilador.
(35) Java no proporciona un mecanismo de herencia múltiple (MI), al menos no como C++. Al igual que protegido, MI parece una muy buena idea, pero no sabrá que lo necesita hasta que realmente enfrente un problema de diseño específico. Debido a que Java utiliza una jerarquía de "raíz única", MI sólo es necesaria en casos excepcionales. La palabra clave interfaz nos ayudará a fusionar automáticamente varias interfaces.
(36) La función de identificación de tipo en tiempo de ejecución es muy similar a C++. Por ejemplo, para obtener información sobre el identificador x, puede utilizar el siguiente código:
X.getClass(). getName();
Para formas compactas "con seguridad de tipos", puede usar:
Derived d = (derived) base
Esto es lo mismo; Como en el estilo antiguo, la forma de C es la misma. El compilador invocará automáticamente el mecanismo de modelado dinámico, no se requiere sintaxis adicional. Si bien no tiene la ventaja de localizar fácilmente formas como "Newcastle" de C++, Java verifica el uso y descarta esas "excepciones", por lo que no permite formas incorrectas como lo hace C++.
(37) Java utiliza un mecanismo de control de excepciones diferente porque no hay ningún constructor en este momento. Puede agregar una cláusula finalmente para forzar que una declaración específica realice la limpieza necesaria. Todas las excepciones en Java heredan de la clase base Throwable, por lo que seguramente obtendremos una interfaz común.
(38)La especificación de excepción de Java es mucho mejor que la de C++. Después de descartar excepciones erróneas, las especificaciones de excepción de Java se verifican y ejecutan en tiempo de compilación en lugar de llamar a funciones en tiempo de ejecución como C++. Además, los métodos reemplazados deben ajustarse a la especificación de excepción de la versión de la clase base del método: pueden descartar excepciones especificadas u otras excepciones derivadas de esas excepciones. De esta manera, terminamos con un código de control de excepciones más "robusto".
(39) Java tiene la capacidad de sobrecargar métodos, pero no permite la sobrecarga de operadores. La clase de cadena no puede concatenar diferentes cadenas con los operadores + y +=, las expresiones de cadena usan conversión de tipo automática, pero ese es un caso especial integrado.
(40) Mediante acuerdo previo, el problema constante que ocurre a menudo en C++ se ha controlado en Java. Solo podemos pasar identificadores a objetos, nunca se genera automáticamente una copia local. Si desea utilizar técnicas de paso por valor de C++, puede llamar a clone() para generar una copia local de la variable independiente (aunque el diseño de clone() aún es relativamente aproximado; consulte el Capítulo 12). No existe un generador de réplicas llamado automáticamente. Para crear un valor constante en tiempo de compilación, puede codificarlo de la siguiente manera:
static final int TAMAÑO = 255
static final int BSIZE = 8 * TAMAÑO
(41) Por razones de seguridad, la programación de "aplicaciones" se diferencia significativamente de la programación de "bloques de programa". Uno de los problemas más evidentes es que el programa no nos permite escribir en el disco, porque al hacerlo provocará que un programa desconocido descargado desde el sitio remoto sobrescriba nuestro disco a su antojo. Con la introducción de la tecnología de firma digital en Java 1.1, esta situación cambió. A partir de firmas digitales podemos conocer con precisión a todos los autores de un programa y verificar que están autorizados. Java 1.2 mejorará aún más la funcionalidad del programa.
(42) Debido a que Java puede parecer demasiado restrictivo en algunas situaciones, a veces hay renuencia a usarlo para realizar tareas importantes como el acceso directo al hardware. La forma en que Java resuelve este problema es el "método intrínseco", que nos permite llamar a funciones escritas en otros lenguajes (actualmente solo se admiten C y C++).
Esto definitivamente resolverá los problemas relacionados con la plataforma (en un formato no portátil, pero ese código se aislará más adelante). Los programas no pueden llamar a métodos internos, solo las aplicaciones pueden hacerlo.
(43) Java proporciona soporte integrado para documentación anotada, por lo que los archivos fuente también pueden contener su propia documentación. A través de un programa separado, la información de este documento se puede extraer y reformatear en HTML. Este es sin duda un gran avance en la gestión y aplicación de documentos.
(44) Java contiene algunas bibliotecas estándar para completar tareas específicas. C++ se basa en algunas bibliotecas no estándar proporcionadas por otros proveedores. Estas tareas incluyen (o incluirán pronto):
■Redes
■Conexiones de bases de datos (a través de JDBC)
■Multiproceso
■ Objetos distribuidos (a través de RMI y CORBA)
■Compresión
■Negocios y comercio
Debido a que estas bibliotecas son fáciles de usar y muy estándar, pueden ser significativamente más rápido velocidad de desarrollo de aplicaciones.
(45) Java 1.1 incluye el estándar Java Beans, que permite la creación de componentes utilizados en 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 confiamos en la solución de un solo fabricante para diseñar componentes visuales, se ampliará la selección de componentes y se mejorará la eficiencia de los mismos. Además, el diseño de Java Beans es muy simple y fácil de entender para los programadores; sin embargo, los marcos de componentes especializados desarrollados por diferentes proveedores requieren más investigación;
(46) Si falla el acceso al identificador de Java, se descartará una excepción. No es necesario realizar esta prueba de descarte antes de utilizar el mango. Según las especificaciones de diseño de Java, esto simplemente significa que las excepciones deben descartarse de alguna forma. Muchos sistemas de ejecución de C++ también pueden descartar excepciones causadas por errores de puntero.
(47) Java es generalmente más robusto y las medidas tomadas para esto son las siguientes:
■Los identificadores de objetos se inicializan en vacío (palabra clave)
■Cuando se produzca un error, definitivamente se comprobará el identificador y se descartará la excepción.
■Todos los accesos a la matriz se verificarán y las violaciones de límites se descubrirán rápidamente.
■Recolección automática de basura para evitar pérdidas de memoria.
■Mecanismo de control de excepciones claro y "tonto"
■Proporciona soporte de lenguaje simple para subprocesos múltiples.
■Compruebe el código de bytes del chip del programa de red.