Java y C++ son dos lenguajes de programación orientados a objetos muy destacados . Según muchos indicadores de popularidad, ambos lenguajes han dominado el desarrollo de software orientado a objetos y de alto rendimiento durante gran parte del siglo XXI, y a menudo se comparan y contrastan directamente. La sintaxis de Java se basó en C/C++ .
El diseño tiene como objetivo
Las diferencias entre los lenguajes de programación C++ y Java se deben a su origen , ya que tienen objetivos de diseño diferentes.
C++ fue diseñado para la programación de sistemas y aplicaciones (es decir, programación de infraestructura), extendiendo el lenguaje de programación procedimental C , que fue diseñado para una ejecución eficiente. A C, C++ le añadió soporte para programación orientada a objetos , manejo de excepciones , administración de recursos basada en el ciclo de vida ( Adquisición de Recursos es Inicialización (RAII)), programación genérica , metaprogramación con plantillas y la Biblioteca Estándar de C++ , que incluye contenedores y algoritmos genéricos (la Biblioteca de Plantillas Estándar o STL), y muchas otras funcionalidades de propósito general.
Java es un lenguaje de programación de propósito general, concurrente, basado en clases y orientado a objetos [ 1 ] diseñado para minimizar las dependencias de implementación. Se basa en una máquina virtual Java para ser seguro y altamente portable . Viene con una extensa biblioteca diseñada para proporcionar abstracción de la plataforma subyacente. Java es un lenguaje orientado a objetos con tipado estático que utiliza una sintaxis similar a la de C++ (pero incompatible con ella). Incluye un sistema de documentación llamado Javadoc .
Los diferentes objetivos en el desarrollo de C++ y Java dieron como resultado principios y compromisos de diseño distintos entre ambos lenguajes. Las diferencias son las siguientes:
Características del idioma
Sintaxis
- La sintaxis de Java tiene una gramática libre de contexto que puede ser analizada por un analizador LALR simple . Analizar C++ es más complicado. Por ejemplo,
Foo<1>(3);es una secuencia de comparaciones siFooes una variable, pero crea un objeto siFooes el nombre de una plantilla de clase. - C++ permite constantes, variables y funciones a nivel de espacio de nombres. En Java, dichas entidades deben pertenecer a un tipo determinado y, por lo tanto, deben definirse dentro de una definición de tipo, ya sea una clase o una interfaz .
- En Java, todos los tipos pertenecen a un espacio de nombres ( paquete Java ), y no existe un "espacio de nombres global" (incluso en archivos fuente compactos donde el código aparentemente no reside en ninguna clase, dicho código pertenece a una clase final de nivel superior en el paquete sin nombre), a diferencia de C++, donde cualquier código que no forme parte de un espacio de nombres forma parte del espacio de nombres global. En Java, el "paquete sin nombre" no es un espacio de nombres global, y las clases que contiene no pueden ser importadas por código en paquetes con nombre.
- Java tiene un árbol de herencia global estricto , de modo que todas las clases extienden (implícitamente) el tipo superior .
java.lang.ObjectC++ no tiene ningún árbol de herencia global. Tiene un tipo superiorstd::any, pero es un objeto de tiempo de ejecución sin tipo definido en lugar de un tipo heredado. - En C++, los objetos son valores, mientras que en Java no lo son. C++ utiliza la semántica de valor por defecto, mientras que Java siempre utiliza la semántica de referencia . Para optar por la semántica de referencia en C++, se puede usar un puntero o una referencia.
- C++ admite
gotosentencias que pueden dar lugar a código espagueti . Con la excepción de la sentencia goto (que rara vez se ve en código real y se desaconseja encarecidamente), tanto Java como C++ tienen básicamente las mismas estructuras de flujo de control , diseñadas para imponer un flujo de control estructurado, y se basan en las sentencias break y continue para proporcionar algunasgotofunciones similares. Algunos comentaristas señalan que estas sentencias de control de flujo etiquetadas rompen la propiedad de punto único de salida de la programación estructurada. [ 11 ] - C++ ofrece funcionalidades de bajo nivel de las que Java carece en su mayoría (una excepción notable es la
sun.misc.UnsafeAPI interna para el acceso y la manipulación directa de memoria). En C++, se pueden usar punteros para manipular ubicaciones de memoria específicas, una tarea necesaria para escribir componentes de bajo nivel del sistema operativo . Del mismo modo, muchos compiladores de C++ admiten un ensamblador en línea , y las funciones de ensamblador se pueden enlazar en programas C/C++. En Java, dicho código debe residir en bibliotecas externas y solo se puede acceder a él a través de la Interfaz Nativa de Java , con una sobrecarga significativa por cada llamada.
Semántica
- C++ permite valores predeterminados para los argumentos de una función o método. Java no. Sin embargo, la sobrecarga de métodos puede utilizarse para obtener resultados similares en Java, aunque generando código auxiliar redundante.
- El código mínimo necesario para compilar en C++ es una función, mientras que en Java es una clase. Sin embargo, desde Java 21, con la introducción de la clase sin nombre, es posible escribir un programa Java que consista únicamente en una función principal.
- C++ permite una variedad de conversiones implícitas entre tipos nativos (incluidas algunas conversiones de restricción), y también permite definir conversiones implícitas que involucran tipos definidos por el usuario. En Java, solo las conversiones de ampliación entre tipos nativos son implícitas; otras conversiones requieren una sintaxis de conversión explícita.
- Un resultado de esto es que, aunque las condiciones de bucle (
if,whiley la condición de salida enfor) en Java y C++ esperan una expresión booleana, el código como causará un error de compilación en Java porque no hay una conversión implícita de estrechamiento de int a booleano, pero compilará en C++. Esto es útil si el código fue un error tipográfico y fue intencional. Sin embargo, los compiladores de C++ actuales generalmente generarán una advertencia cuando se realiza dicha asignación dentro de una expresión condicional. De manera similar, las sentencias de comparación independientes, por ejemplo , sin un efecto secundario generalmente conducen a una advertencia.if(a=5)if(a==5)a == 5;
- Un resultado de esto es que, aunque las condiciones de bucle (
- Para pasar parámetros a funciones, C++ admite tanto el paso por referencia como el paso por valor . En Java, los parámetros primitivos siempre se pasan por valor. Los tipos de clase, los tipos de interfaz y los tipos de matriz se denominan colectivamente tipos de referencia en Java y también se pasan siempre por valor. [ 12 ] [ 13 ] [ 14 ]
- Los tipos integrados de Java tienen un tamaño y un rango específicos definidos por la especificación del lenguaje. En C++, se define un rango mínimo de valores para los tipos integrados, pero la representación exacta (número de bits) se puede asignar a los tipos nativos que se prefieran en una plataforma determinada.
- Por ejemplo, los caracteres de Java son caracteres Unicode de 16 bits , y las cadenas se componen de una secuencia de dichos caracteres. C++ ofrece caracteres estrechos y anchos, pero el tamaño real de cada uno depende de la plataforma, al igual que el conjunto de caracteres utilizado. Las cadenas se pueden formar con cualquiera de los dos tipos.
- Esto también implica que los compiladores de C++ pueden seleccionar automáticamente la representación más eficiente para la plataforma de destino (es decir, enteros de 64 bits para una plataforma de 64 bits), mientras que la representación es fija en Java, lo que significa que los valores pueden almacenarse en el tamaño menos eficiente o deben rellenarse los bits restantes y agregar código para emular el comportamiento de ancho reducido.
- El redondeo y la precisión de los valores y operaciones de punto flotante en C++ dependen de la implementación (aunque solo las plataformas muy exóticas o antiguas se apartan del estándar IEEE 754 ). Java proporciona un modelo de punto flotante estricto opcional (
strictfp) que garantiza resultados más consistentes en todas las plataformas, aunque a costa de un rendimiento de tiempo de ejecución posiblemente más lento. Sin embargo, Java no cumple estrictamente con el estándar IEEE 754. La mayoría de los compiladores de C++, por defecto, cumplen parcialmente con IEEE 754 (generalmente excluyendo las reglas de redondeo estricto y generando excepciones en los resultados NaN), pero proporcionan opciones de cumplimiento de diversa rigurosidad, para permitir cierta optimización. [ 15 ] [ 16 ] Si etiquetamos esas opciones de menos a más conforme como rápido , consistente ( strictfp de Java ), casi IEEE y estricto IEEE , podemos decir que la mayoría de las implementaciones de C++ por defecto son casi IEEE , con opciones para cambiar a rápido o estricto IEEE , mientras que Java por defecto es rápido con una opción para cambiar a consistente . - En C++, los punteros se pueden manipular directamente como valores de direcciones de memoria. Las referencias de Java son punteros a objetos. [ 17 ] Las referencias de Java no permiten el acceso directo a direcciones de memoria ni permiten manipularlas con aritmética de punteros. En C++ se pueden construir punteros a punteros, punteros a enteros y números de coma flotante, y punteros a ubicaciones de memoria arbitrarias. Las referencias de Java solo acceden a objetos, nunca a tipos primitivos, otras referencias o ubicaciones de memoria arbitrarias. En Java, se puede leer y escribir en memoria con valores arbitrarios usando la
sun.misc.UnsafeAPI, sin embargo, está obsoleto y no se recomienda. - En C++, los punteros pueden apuntar a funciones o funciones miembro ( punteros a funciones ). El mecanismo equivalente en Java utiliza referencias a objetos o interfaces.
- Mediante objetos asignados en la pila, C++ admite la gestión de recursos con ámbito , una técnica utilizada para gestionar automáticamente la memoria y otros recursos del sistema que admite la destrucción determinista de objetos. Si bien la gestión de recursos con ámbito en C++ no se puede garantizar (incluso los objetos con destructores adecuados pueden asignarse usando
newy dejarse sin eliminar), proporciona un medio eficaz de gestión de recursos. Los recursos compartidos se pueden gestionar usandostd::shared_ptr<T>, junto constd::weak_ptr<T>para romper referencias cíclicas. Java admite la gestión automática de memoria mediante la recolección de basura [ 7 ] que puede liberar objetos inaccesibles incluso en presencia de referencias cíclicas, pero otros recursos del sistema (archivos, [ 5 ] flujos, ventanas, puertos de comunicación, subprocesos, etc.) deben liberarse explícitamente porque no se garantiza que la recolección de basura ocurra inmediatamente después de que se abandone la última referencia de objeto. Java permite la gestión de recursos con ámbito a través detrybloques -with-resources para tipos que implementanjava.lang.AutoCloseable, pero a diferencia de C++, el objeto no se elimina de la memoria, sino que solo los recursos propios se eliminan mediante elclose()método. - C++ permite la sobrecarga de operadores definida por el usuario . Esta sobrecarga permite que los tipos definidos por el usuario admitan operadores (aritméticos, comparaciones, etc.) como si fueran tipos primitivos, mediante implementaciones definidas por el usuario para dichos operadores. Generalmente, se recomienda preservar la semántica de los operadores. Java no admite ninguna forma de sobrecarga de operadores (aunque su biblioteca utiliza el operador de suma para la concatenación de cadenas).
- Java ofrece compatibilidad con la interfaz de programación de aplicaciones (API) estándar para la programación reflexiva (reflexión) y la carga dinámica de código nuevo arbitrario.
- C++ admite la vinculación estática y dinámica de binarios.
- Tanto Java como C++ (desde C++26) ofrecen reflexión , lo que permite cierto grado de introspección del código. La reflexión en Java actúa principalmente en tiempo de ejecución y es principalmente conductual, mientras que en C++ actúa en tiempo de compilación, produce meta-objetos y es principalmente generativa.
- Java cuenta con genéricos , cuyo propósito principal es proporcionar contenedores con seguridad de tipos. Sin embargo, los genéricos de Java no se reifican (solo actúan en tiempo de compilación) y se borran en tiempo de ejecución. C++ dispone de plantillas en tiempo de compilación , que ofrecen un soporte más amplio para la programación genérica y la metaprogramación. Las plantillas de C++ instancian una especialización para cada tipo utilizado con ellas.
- Tanto Java como C++ ofrecen anotaciones . Las anotaciones de Java permiten añadir metadatos personalizados arbitrarios a las clases y realizar metaprogramación mediante una herramienta de procesamiento de anotaciones . C++ ofrece atributos para indicar metadatos definidos por el compilador, así como anotaciones (desde C++26) que el usuario puede definir y leer en tiempo de compilación, pero no en tiempo de ejecución como en Java.
- Tanto Java como C++ distinguen entre tipos nativos (también llamados tipos fundamentales o integrados ) y tipos definidos por el usuario (también llamados tipos compuestos ). En Java, los tipos nativos solo admiten semántica de valor, mientras que los tipos compuestos solo admiten semántica de referencia. En C++, todos los tipos admiten semántica de valor, pero se puede crear una referencia a cualquier tipo, lo que permite manipular el objeto mediante semántica de referencia.
- C++ admite la herencia múltiple de clases arbitrarias. En Java, una clase puede derivar de una sola clase, [ 1 ] pero una clase puede implementar múltiples interfaces [ 18 ] (en otras palabras, admite la herencia múltiple de tipos, pero solo la herencia simple de implementación).
- Java distingue explícitamente entre interfaces y clases. En C++, la herencia múltiple y las funciones virtuales puras permiten definir clases que funcionan casi como las interfaces de Java, con algunas pequeñas diferencias.
- Java cuenta con soporte tanto en el lenguaje como en la biblioteca estándar para la multihilo . La
synchronizedpalabra clave en Java proporciona bloqueos mutex para admitir aplicaciones multihilo. [ 19 ] [ 20 ] Java también proporciona bibliotecas para la sincronización multihilo más avanzada. C++11 tiene un modelo de memoria definido para la multihilo en C++ y soporte de biblioteca para la creación de hilos y para muchas primitivas de sincronización. - Las funciones miembro de C++ se pueden declarar como funciones virtuales , lo que significa que el método que se va a llamar viene determinado por el tipo de objeto en tiempo de ejecución (también conocido como despacho dinámico). Por defecto, los métodos en C++ no son virtuales (es decir, virtualización opcional ). En Java, los métodos son virtuales por defecto, pero se pueden convertir en no virtuales usando la
finalpalabra clave `virtual` (es decir, virtualización opcional ). - C++ incluye una palabra clave a nivel de lenguaje
overridepara indicar la sobrescritura de un método virtual. Java no la incluye, pero sí una@Overrideanotación para indicar la sobrescritura, la cual genera un error de compilación si no se sobrescribe ningún método existente. - Las enumeraciones de C y C++ son tipos primitivos. Las enumeraciones de C
enumse convierten implícitamente a tipos enteros (pero no desde tipos enteros), mientras que las enumeraciones de C++enum classson fuertemente tipadas y no se convierten implícitamente. Las enumeraciones de Java se comportan como clases y pueden definir constructores y métodos. - Operadores unarios
++y--: en C++ "El operando debe ser un lvalue modificable . [omitido] El resultado es el operando actualizado; es un lvalue...", [ 21 ] pero en Java "la promoción numérica binaria mencionada anteriormente puede incluir la conversión de desempaquetado y la conversión de conjunto de valores. Si es necesario, la conversión de conjunto de valores {y/o [...] la conversión de empaquetado} se aplica a la suma antes de que se almacene en la variable.", [ 22 ] es decir, en Java, después de la inicialización cambia la referencia asignando un nuevo objeto, mientras que en C++ el objeto sigue siendo el mismo.Integeri=2;++i;i - En Java, las expresiones lambda son "expresiones polifónicas", cuyos tipos dependen del contexto [ 23 ] , mientras que en C++, las expresiones lambda tienen una clase de tiempo de ejecución real a la que se puede acceder
decltypey que forma parte del modelo del lenguaje. Las expresiones lambda de Java dependen de la interfaz funcional a la que se asignan.
Gestión de recursos
- Java ofrece recolección automática de basura , la cual puede omitirse en circunstancias específicas mediante la especificación Java en tiempo real . La gestión de memoria en C++ generalmente se realiza mediante constructores, destructores y punteros inteligentes . El estándar de C++ permite la recolección de basura, pero no la exige. En la práctica, la recolección de basura rara vez se utiliza.
- C++ puede asignar bloques de memoria arbitrarios. Java solo asigna memoria mediante la instanciación de objetos. En Java, los bloques de memoria arbitrarios pueden asignarse como una matriz de bytes.
- Java y C++ utilizan diferentes métodos para la gestión de recursos. Java se basa principalmente en la recolección de basura, que puede recuperar memoria, [ 7 ] mientras que C++ se basa principalmente en el método de adquisición de recursos mediante inicialización (RAII). Esto se refleja en varias diferencias entre ambos lenguajes:
- En C++, es común asignar objetos de tipos compuestos como variables locales en la pila, las cuales se destruyen cuando salen del ámbito. En Java, los tipos compuestos siempre se asignan en el montón y son recolectados por el recolector de basura (excepto en máquinas virtuales que utilizan análisis de escape para convertir las asignaciones del montón en asignaciones de la pila).
- C++ tiene destructores, [ 7 ] mientras que Java tiene finalizadores . [ 7 ] Ambos se invocan antes de la desasignación de un objeto, pero difieren significativamente. El destructor de un objeto C++ debe invocarse implícitamente (en el caso de variables ligadas a la pila) o explícitamente para desasignar un objeto. El destructor se ejecuta síncronamente justo antes del punto en un programa en el que se desasigna un objeto. La desinicialización y desasignación síncronas y coordinadas en C++ satisfacen así el patrón RAII. Los destructores en C++ son la forma normal de recuperar los recursos asociados con un objeto, y son una contraparte necesaria de los constructores. [ 7 ] En Java, la desasignación de objetos es manejada implícitamente por el recolector de basura. El finalizador de un objeto Java se invoca asíncronamente algún tiempo después de que se haya accedido a él por última vez y antes de que se desasigne. Muy pocos objetos necesitan finalizadores. Un finalizador es necesario solo para objetos que deben garantizar alguna limpieza del estado del objeto antes de desasignarse, normalmente liberando recursos externos a la JVM. [ 7 ] El uso directo de finalizadores no suele ser aconsejable, ya que son impredecibles, generalmente peligrosos y, en la mayoría de los casos, innecesarios. [ 7 ] Hay que tener cuidado de no pensar en los finalizadores como destructores de C++. [ 7 ] Más bien, el bloque
try-with-resources otry-finallylogra un propósito más similar al del destructor. [ 7 ] Un problema con los finalizadores o limpiadores es que no se garantiza que se ejecuten inmediatamente. [ 7 ] Por lo tanto, un finalizador nunca debe usarse para tareas que sean críticas en cuanto al tiempo. [ 7 ] Además, los finalizadores conllevan graves penalizaciones de rendimiento y aumentan significativamente el tiempo que tardan los objetos en desasignarse, por lo que su uso está desaconsejado y obsoleto en Java 9. - Con RAII en C++, un tipo de recurso se encapsula típicamente dentro de una clase pequeña que asigna el recurso al construirse y lo libera al destruirse, y proporciona acceso al recurso entre esos puntos. Cualquier clase que contenga solo dichos objetos RAII no necesita definir un destructor, ya que los destructores de los objetos RAII se llaman automáticamente cuando se destruye un objeto de esta clase. En Java, la desasignación síncrona segura de recursos se puede realizar de forma determinista utilizando la construcción
try`try-catchwith-resources` . Alternativamente, la construcción `try-with-resources`, introducida en Java 7, debería usarse en lugar de la construcción ` try-with-resources` . [ 24 ] La construcción `try-with-resources` es más concisa y legible. [ 24 ] También proporciona información de diagnóstico más útil, ya que las excepciones suprimidas no se descartan y se imprimen en el rastreo de la pila con información que indica que fueron suprimidas. [ 24 ]finallytrytryfinally - En C++, es posible tener un puntero colgante , una referencia obsoleta a un objeto que ya ha sido liberado. Intentar usar un puntero colgante generalmente provoca un fallo en el programa. En Java, el recolector de basura no destruye un objeto referenciado.
- En C++, es posible tener objetos primitivos sin inicializar. Java impone la inicialización por defecto.
- En C++, es posible tener un objeto asignado al que no exista una referencia válida. Dicho objeto inaccesible no puede ser destruido (desasignado) y resulta en una fuga de memoria . En cambio, en Java, un objeto no será desasignado por el recolector de basura hasta que se vuelva inaccesible (por el programa de usuario). ( Se admiten referencias débiles , que funcionan con el recolector de basura de Java para permitir diferentes niveles de accesibilidad). La recolección de basura en Java previene muchas fugas de memoria, pero aún son posibles en algunas circunstancias. [ 25 ] [ 26 ] [ 27 ] El recolector de basura automático puede dar la falsa impresión de que en Java no es necesario pensar en la gestión de memoria. [ 5 ] Sin embargo, esto no es del todo cierto. [ 5 ] En términos generales, esto se debe a que un programa puede tener "fugas de memoria", conocidas más formalmente como "retenciones de objetos no intencionadas". [ 5 ] Un ejemplo de fuga de memoria que puede ocurrir es para un programa que se ha escrito sin errores lógicos, excepto que no eliminó referencias obsoletas. [ 5 ] Esto resulta en un mayor uso de la actividad del recolector de basura, mayor huella de memoria . [ 5 ] En circunstancias extremas, este problema puede llevar a un
java.lang.OutOfMemoryError, pero esto rara vez sucede.
[ 5 ] La solución a esto es anular las referencias a objetos. [ 5 ] Una segunda razón común para las fugas de memoria es el uso de caché que ya no es relevante. La solución a las fugas de memoria debidas al uso de caché antigua es representar la caché usando unjava.util.WeakHashMap<K, V>.
Bibliotecas
- C++ proporciona acceso multiplataforma a muchas características que normalmente se encuentran en bibliotecas específicas de cada plataforma. El acceso directo desde Java a las funciones nativas del sistema operativo y del hardware requiere el uso de la Interfaz Nativa de Java o, desde Java 21, la API de Funciones y Memoria Externas, que permiten asignar y administrar memoria fuera de la Máquina Virtual de Java, así como llamar a funciones nativas (es decir, C/C++).
- La biblioteca estándar de C++ está diseñada para ser minimalista, proporcionando solo un conjunto estandarizado de características de uso general, mientras que la biblioteca de clases de Java y el sistema de módulos de la plataforma Java (la biblioteca estándar de Java) son mucho más extensos, proporcionando un conjunto estandarizado mucho más amplio y completo de características, como gráficos, creación de interfaces de usuario y más.
Tiempo de ejecución
- Debido a su expresividad sin restricciones, las características de bajo nivel del lenguaje C++ (por ejemplo, acceso a matrices sin verificación, punteros sin procesar, tipado aleatorio ) no se pueden verificar de manera confiable en tiempo de compilación ni sin sobrecarga en tiempo de ejecución. Los errores de programación relacionados pueden provocar desbordamientos de búfer de bajo nivel y fallos de segmentación . La biblioteca de plantillas estándar proporciona abstracciones RAII de nivel superior (como vector, lista y mapa) para ayudar a evitar dichos errores. En Java, los errores de bajo nivel no pueden ocurrir o son detectados por la máquina virtual de Java (JVM) y notificados a la aplicación en forma de excepción .
- Las excepciones están estrechamente acopladas en el entorno de ejecución de Java y las operaciones a nivel de lenguaje (incluidas, entre otras, la división por cero, el acceso a referencias nulas, la conversión no válida y el acceso a matrices fuera de los límites) pueden lanzar excepciones, mientras que en C++ normalmente solo los objetos lanzan (con la excepción de que
typeid()puede lanzar unastd::bad_typeidexcepción [ 28 ] ,newque puede lanzarstd::bad_allocostd::bad_array_new_length[ 29 ] ,newque puede lanzarstd::bad_alloc, odynamic_castque puede lanzarstd::bad_cast[ 30 ] ). Además, en C++, las excepciones pueden ser "deshabilitadas" (como con-no-exceptionsen GCC o Clang [ 31 ] , o/Ehscen MSVC ), lo que impedirá que el compilador genere código para el manejo de excepciones y terminará un programa constd::terminate()en unathrowinstrucción. - Java cuenta con excepciones verificadas , que son excepciones que deben manejarse dentro de un
catchbloque y solo pueden propagarse a través de funciones que las declaren explícitamente con unathrowscláusula. Cualquier excepción que no extiendajava.lang.RuntimeExceptionse considera una excepción verificada. Mientras tanto, en C++, el concepto de "excepciones verificadas" no existe, pero se puede especificar que las funciones no lancen excepciones con unnoexceptespecificador. Hasta C++17, C++ permitía especificaciones de excepciones dinámicas a través de unathrowcláusula en la firma de la función, que, al igual que las cláusulas de Javathrows, permitía a las funciones especificar qué tipos podían lanzar. [ 32 ] - Java solo permite que las clases que extienden
java.lang.Throwablesean lanzadas por unathrowinstrucción. En C++, cualquier objeto, incluidos los primitivos, puede ser lanzado y capturado. Java diferencia entrejava.lang.Error(que representa errores de tiempo de ejecución considerados irrazonables para capturar) yjava.lang.Exception(que representa posibles errores recuperables considerados razonables para capturar), mientras que en C++, la clase de excepción base habitual esstd::exception.
- Las excepciones están estrechamente acopladas en el entorno de ejecución de Java y las operaciones a nivel de lenguaje (incluidas, entre otras, la división por cero, el acceso a referencias nulas, la conversión no válida y el acceso a matrices fuera de los límites) pueden lanzar excepciones, mientras que en C++ normalmente solo los objetos lanzan (con la excepción de que
- El lenguaje Java requiere un comportamiento específico en caso de acceso a un array fuera de los límites, lo que generalmente requiere la comprobación de límites de los accesos a arrays. Esto elimina una posible fuente de inestabilidad, pero normalmente a costa de ralentizar la ejecución. En algunos casos, especialmente desde Java 7, el análisis del compilador puede demostrar que la comprobación de límites es innecesaria y eliminarla. C++ no tiene un comportamiento requerido para el acceso fuera de los límites de los arrays nativos, por lo que no requiere la comprobación de límites para los arrays nativos.
std::vector<T>Sin embargo, las colecciones de la biblioteca estándar de C++ como , ofrecen comprobación de límites opcional. En resumen, los arrays de Java (T[]) son "normalmente seguros; ligeramente restringidos; a menudo tienen sobrecarga" mientras que los arrays nativos de C++ "tienen sobrecarga opcional; son ligeramente no restringidos; posiblemente no seguros". Las colecciones de Java comojava.util.ArrayList<T>pueden lanzar excepciones comojava.lang.IndexOutOfBoundsException. C++26 añade "endurecimiento de límites" a la biblioteca estándar, que ahora define ciertos comportamientos indefinidos (incluido el acceso fuera de los límites) como violaciones de contrato. [ 33 ] [ 34 ]
Plantillas frente a genéricos
Tanto C++ como Java ofrecen herramientas para la programación genérica , plantillas y genéricos , respectivamente. Si bien fueron creados para resolver problemas similares y tienen una sintaxis parecida, son bastante diferentes.
Misceláneas
- Java y C++ utilizan métodos diferentes para dividir el código en varios archivos fuente.
- Java utiliza un sistema de paquetes que dicta el nombre y la ruta del archivo para todas las definiciones de programas. Su compilador importa los archivos de clase ejecutables .
- Antes de C++20 , C++ utilizaba un sistema de inclusión de código fuente mediante archivos de cabecera para compartir declaraciones entre archivos fuente. Sin embargo, a partir de C++20, se introdujeron los módulos , que ofrecen una funcionalidad similar a la de los paquetes de Java. Todos los símbolos marcados son accesibles tras importar un módulo.
export - Desde C++23 , la biblioteca estándar de C++ ahora se puede importar como un módulo.
- El término " módulo " se refiere a diferentes cosas. En Java, un módulo se usa para agrupar varios paquetes, mientras que en C++ un módulo representa una única unidad de traducción que se declara como tal.
importEn C++, se importa un módulo cargando su BMI (interfaz de módulo construido) durante la compilación; sin embargo, en C++, los módulos no dictan el espacio de nombres al que pertenece un símbolo. Por otro lado,importen Java se utiliza para crear alias de clases y evitar calificarlas completamente (equivalente a en C++), y no se "importan" definiciones durante la compilación. Esto se debe a que el cargador de clases de Javausinggestiona todas las clases según sea necesario durante el tiempo de ejecución , y se pueden usar incluso sin una declaración calificando completamente la clase.import
- Un archivo fuente Java debe coincidir con el espacio de nombres de la clase pública que declara (puede tener cualquier nombre si no hay clases públicas), y el paquete al que pertenece debe coincidir con la ruta donde se encuentra. Un paquete solo puede declarar como máximo una clase pública (pero puede tener varias clases no públicas).
- Un archivo fuente de C++ (ya sea un archivo de cabecera o un módulo) puede tener cualquier nombre y contener tantas clases como el programador desee. Los módulos no tienen la obligación de coincidir con la ruta de su ubicación.
- Los archivos de clase Java compilados suelen ser más pequeños que los archivos objeto en C++, ya que el código de bytes de Java suele ser más compacto que el código máquina nativo , y Java no realiza enlaces estáticos.
- La compilación de C++ incluye una fase de preprocesamiento de texto , mientras que Java no. Por lo tanto, algunos usuarios añaden una fase de preprocesamiento a su proceso de compilación para mejorar la compatibilidad con la compilación condicional.
- Los operadores de división y módulo de Java están bien definidos para truncar a cero. Antes de C++11 , C++ no especificaba si estos operadores truncaban a cero o "truncaban a infinito negativo".
-3/2siempre será-1en Java y C++11, pero un compilador de C++03 puede devolver-1o-2, dependiendo de la plataforma. C99 define la división de la misma manera que Java y C++11. Ambos lenguajes garantizan (donde a y b son tipos enteros) que para todo y ( distinto de cero). La versión de C++03 a veces será más rápida, ya que se le permite elegir el modo de truncamiento nativo del procesador.(a / b) * b + (a % b) == aabb - En Java, el tamaño de los tipos enteros es fijo (por ejemplo,
intes de 32 bits,longes de 64 bits), mientras que en C++ el tamaño de los enteros y punteros depende del compilador y de la interfaz binaria de la aplicación (ABI) dentro de ciertas restricciones. Por lo tanto, un programa Java tendrá un comportamiento consistente en todas las plataformas, mientras que un programa C++ puede requerir adaptaciones para algunas plataformas, pero puede ejecutarse más rápido con tamaños de enteros más naturales para la plataforma local. Sin embargo, C/C++ también tienen tamaños de ancho fijo (comoint32_tpara enteros con signo de 32 bits,uint64_tpara enteros sin signo de 64 bits, etc.).
En Wikibooks existe un ejemplo que compara C++ y Java .
Actuación
Además de ejecutar un programa Java compilado, los ordenadores que ejecutan aplicaciones Java generalmente también deben ejecutar la máquina virtual Java (JVM), mientras que los programas C++ compilados pueden ejecutarse sin aplicaciones externas. Las primeras versiones de Java fueron superadas significativamente por lenguajes compilados estáticamente como C++. Esto se debe a que las instrucciones de programa de estos dos lenguajes estrechamente relacionados pueden compilarse en unas pocas instrucciones de máquina con C++, mientras que se compilan en varios códigos de bytes que involucran varias instrucciones de máquina cada uno cuando son interpretados por una JVM. Por ejemplo:
Dado que la optimización del rendimiento es un tema muy complejo, resulta difícil cuantificar la diferencia de rendimiento entre C++ y Java en términos generales, y la mayoría de las pruebas de rendimiento son poco fiables y sesgadas. Debido a la naturaleza tan diferente de ambos lenguajes, también es difícil establecer diferencias cualitativas definitivas. En resumen, Java presenta ineficiencias inherentes y limitaciones importantes en la optimización, dado que depende en gran medida de abstracciones flexibles de alto nivel. Sin embargo, el uso de un compilador JIT potente (como en las implementaciones modernas de la JVM) puede mitigar algunos problemas. En cualquier caso, si las ineficiencias de Java son demasiado grandes, se puede llamar a código C o C++ compilado desde Java mediante JNI.
Algunas ineficiencias inherentes al lenguaje Java incluyen, principalmente:
- Todos los objetos se asignan en el montón. Si bien la asignación es extremadamente rápida en las JVM modernas que utilizan la asignación por incremento (bump allocation), cuyo rendimiento es similar al de la asignación en la pila, la invocación del recolector de basura puede afectar negativamente al rendimiento. Los compiladores JIT modernos mitigan este problema en cierta medida mediante el análisis o la detección de errores de escape para asignar algunos objetos en la pila, desde Oracle JDK 6.
- Los proyectos críticos para el rendimiento, como los sistemas de bases de datos eficientes y las bibliotecas de mensajería, han tenido que utilizar API internas no oficiales para
sun.misc.Unsafeacceder a la gestión manual de recursos y poder realizar la asignación de pila, manipulando efectivamente los pseudopunteros. - La gran cantidad de conversiones de tipo necesarias en tiempo de ejecución, incluso utilizando contenedores estándar, conlleva una penalización en el rendimiento. Sin embargo, la mayoría de estas conversiones se eliminan estáticamente mediante el compilador JIT.
- Las garantías de seguridad conllevan un coste en tiempo de ejecución. Por ejemplo, el compilador debe incluir comprobaciones de rango adecuadas en el código. Proteger cada acceso a un array con una comprobación de rango no es eficiente, por lo que la mayoría de los compiladores JIT intentarán eliminarlas de forma estática o sacándolas de los bucles internos (aunque la mayoría de los compiladores nativos de C++ harán lo mismo cuando las comprobaciones de rango se utilicen opcionalmente).
- La falta de acceso a detalles de bajo nivel impide que el desarrollador mejore el programa donde el compilador no puede hacerlo. [ 38 ]
- El uso obligatorio de la semántica de referencia para todos los tipos definidos por el usuario en Java puede introducir grandes cantidades de indirecciones de memoria superfluas (o saltos) (a menos que el compilador JIT las omita), lo que puede provocar fallos de caché frecuentes (también conocido como saturación de caché ). Además, la optimización de caché, generalmente mediante estructuras de datos y algoritmos que tienen en cuenta la caché o que la ignoran , a menudo puede generar mejoras de varios órdenes de magnitud en el rendimiento, así como evitar la degeneración de la complejidad temporal característica de muchos algoritmos que reducen el uso de caché, y por lo tanto es una de las formas más importantes de optimización; la semántica de referencia, tal como se exige en Java, hace que dichas optimizaciones sean imposibles de realizar en la práctica (ni por el programador ni por el compilador JIT).
- Recolección de basura , [ 39 ] ya que esta forma de administración automática de memoria introduce sobrecarga de memoria. [ 40 ]
Sin embargo, el diseño de Java presenta una serie de ventajas, algunas ya demostradas y otras solo teóricas:
- La recolección de basura de Java puede tener una mejor coherencia de caché que el uso habitual de / para la asignación de memoria. Sin embargo, existen argumentos que indican que ambos asignadores fragmentan el montón por igual y ninguno presenta una mejor localidad de caché. No obstante, en C++, la asignación de objetos individuales en el montón es poco frecuente, y grandes cantidades de objetos individuales generalmente se asignan en bloques a través de un contenedor STL y/o con un asignador de objetos pequeños. [ 41 ] [ 42 ]
std::mallocnew - La compilación en tiempo de ejecución puede utilizar información sobre la plataforma en la que se ejecuta el código para mejorarlo de forma más eficaz. Sin embargo, la mayoría de los compiladores nativos de última generación (C, C++, etc.) generan múltiples rutas de código para aprovechar al máximo las capacidades computacionales del sistema. [ 43 ] Asimismo, se puede argumentar que los compiladores nativos pueden explotar mejor la optimización y los conjuntos de instrucciones específicos de la arquitectura que las distribuciones de JVM multiplataforma.
- La compilación en tiempo de ejecución permite una inserción en línea de funciones virtuales más agresiva que la que es posible para un compilador estático, porque el compilador JIT tiene más información sobre todos los posibles objetivos de las llamadas virtuales, incluso si están en diferentes módulos cargados dinámicamente. Las implementaciones de JVM disponibles actualmente no tienen problemas para insertar en línea la mayoría de las llamadas monomórficas, principalmente monomórficas y dimórficas, y se está investigando para insertar en línea también las llamadas megamórficas, gracias a las recientes mejoras dinámicas de invocación añadidas en Java 7. [ 44 ] La inserción en línea puede permitir optimizaciones adicionales como la vectorización de bucles o el desenrollado de bucles , lo que resulta en un gran aumento general del rendimiento.
- En Java, la sincronización de subprocesos está integrada en el lenguaje, [ 20 ] por lo que el compilador JIT puede potencialmente, mediante análisis de escape, eludir bloqueos, [ 45 ] mejorar significativamente el rendimiento del código multihilo ingenuo.
Además, en C++ se producen algunos problemas de rendimiento:
- Permitir que los punteros apunten a cualquier dirección puede dificultar la optimización debido a la posibilidad de alias de punteros .
- Dado que el código generado a partir de distintas instanciaciones de la misma plantilla de clase en C++ no se comparte (a diferencia de los genéricos con tipos borrados en Java), el uso excesivo de plantillas puede provocar un aumento significativo del tamaño del código ejecutable ( inflación de código ). Sin embargo, debido a que las plantillas de función se insertan en línea de forma agresiva, a veces pueden reducir el tamaño del código, pero, lo que es más importante, permiten un análisis estático más riguroso y una optimización del código por parte del compilador, lo que suele hacerlas más eficientes que el código sin plantillas. Por el contrario, los genéricos de Java son necesariamente menos eficientes que el código sin genéricos.
- Dado que en un compilador C++ tradicional la vinculación dinámica se realiza después de la generación y optimización del código, las llamadas a funciones que abarcan diferentes módulos dinámicos no se pueden integrar en línea. Sin embargo, los compiladores C++ modernos como MSVC y Clang+LLVM ofrecen opciones de generación de código en tiempo de vinculación que permiten compilar los módulos a formatos intermedios, lo que posibilita la integración en línea en la etapa final de vinculación.
Norma y referencia oficial del idioma
Especificación del lenguaje
El lenguaje C++ está definido por la norma ISO /IEC 14882 , publicada por el comité ISO/IEC JTC1/SC22/WG21 . C++ suele publicarse cada tres años. [ 46 ]
El lenguaje C++ evoluciona a través de un comité directivo abierto llamado Comité de Estándares de C++. El comité está compuesto por el creador de C++, Bjarne Stroustrup , el coordinador Herb Sutter y otras figuras destacadas, incluyendo numerosos representantes de la industria y grupos de usuarios (es decir, las partes interesadas). Al ser un comité abierto, cualquier persona puede unirse, participar y aportar propuestas para las próximas versiones del estándar y las especificaciones técnicas. El comité tiene como objetivo publicar un nuevo estándar cada pocos años, aunque en el pasado, los rigurosos procesos de revisión y las discusiones han provocado retrasos más prolongados entre las publicaciones de nuevos estándares (1998, 2003 y 2011).
El lenguaje Java se define mediante la Especificación del Lenguaje Java , [ 47 ] un libro publicado por Oracle . Java suele publicarse en un ciclo semestral, aunque tradicionalmente se publica una vez cada dos años. [ 48 ] [ 49 ]
El lenguaje Java evoluciona continuamente a través de un proceso llamado Proceso de la Comunidad Java , y la comunidad mundial de programadores está representada por un grupo de personas y organizaciones —los miembros de la Comunidad Java [ 50 ] — que participan activamente en la mejora del lenguaje, enviando solicitudes públicas —las Solicitudes de Especificación Java— que deben pasar revisiones formales y públicas antes de que se integren en el lenguaje.
La falta de un estándar firme para Java y la naturaleza algo volátil de sus especificaciones han sido objeto de críticas constantes por parte de las partes interesadas, que buscan mayor estabilidad y conservadurismo en la incorporación de nuevas características al lenguaje y a las bibliotecas. Por otro lado, el comité de C++ también recibe críticas constantes, pero por la razón opuesta: ser demasiado estricto y conservador, y tardar demasiado en lanzar nuevas versiones.
Marcas comerciales
"C++" no es una marca registrada de ninguna empresa u organización y no es propiedad de ningún individuo. [ 51 ] "Java" es una marca registrada de Oracle . [ 52 ]
Véase también
- GNU Compiler for Java , un compilador ahora descontinuado que ofrecía interoperabilidad entre Java y C++.
Referencias
Citas
- 1 2 3 Bloch 2018 , págs. xi–xii, Prólogo.
- 1 2 Bloch 2018 , pág. 285, Capítulo §11 Punto 66: Utilice los métodos nativos con criterio.
- ↑ "API de aritmética de enteros sin signo ahora en JDK 8" . Archivado del original el 25 de febrero de 2017. Consultado el 17 de marzo de 2014 .
- ↑ "Tutoriales de Java: Pasar información a un método o a un constructor" . Oracle . Consultado el 17 de febrero de 2013 .
- 1 2 3 4 5 6 7 8 9 Bloch 2018 , págs. 123–125, Capítulo §2 Punto 7: Eliminar referencias obsoletas.
- ↑ "Los tutoriales de Java: El objeto como superclase" . Oracle . Consultado el 17 de febrero de 2013 ..
- 1 2 3 4 5 6 7 8 9 10 11 12 Bloch 2018 , págs. 29–33, Capítulo §2 Punto 8: Evite los finalizadores y limpiadores.
- ↑ "Software XMPP » Bibliotecas" . xmpp.org . Consultado el 13 de junio de 2013 .
- ↑ Herb Sutter (14 de abril de 2026). "Anuncio: actualización de cppreference.com" . isocpp.org . Standard C++ Foundation.
- 1 2 Goetz et al. 2006 , p. 48, §3.4.1 Campos finales.
- ↑ Robert C. Martin (enero de 1997). "Java vs. C++: una comparación crítica" (PDF) . Archivado del original (PDF) el 11 de mayo de 2008. Consultado el 15 de diciembre de 2007 .
- ↑ "Tipos y valores de referencia" . Especificación del lenguaje Java, tercera edición . Consultado el 9 de diciembre de 2010 .
- ↑ Horstmann, Cay; Cornell, Gary (2008). Core Java . Vol. I (Octava ed.). Sun Microsystems. págs. 140–141 . ISBN 978-0-13-235476-9Algunos programadores (y, lamentablemente ,
incluso algunos autores de libros) afirman que el lenguaje de programación Java utiliza la llamada por referencia para los objetos. Sin embargo, esto es falso. Dado que se trata de un malentendido tan común, vale la pena examinar un contraejemplo con cierto detalle... Esta discusión demuestra que el lenguaje de programación Java no utiliza la llamada por referencia para los objetos. En cambio, las referencias a objetos se pasan por valor .
- ↑ Deitel, Paul; Deitel, Harvey (2009). Java para programadores . Prentice Hall. pág. 223. ISBN 978-0-13-700129-3
A diferencia de otros lenguajes, Java no permite a los programadores elegir entre pasar argumentos por valor o por referencia; todos los argumentos se pasan por valor. Una llamada a un método puede pasar dos tipos de valores: copias de valores primitivos (por ejemplo, valores de tipo int y double) y copias de referencias a objetos (incluidas las referencias a arreglos). Los objetos en sí mismos no se pueden pasar a los métodos
. - ↑ "Semántica de las matemáticas de punto flotante en GCC" . Fundación GNU . Consultado el 20 de abril de 2013 .
- ↑ "Compilador de C++ de Microsoft, /fp (Especificar comportamiento de punto flotante)" . Microsoft Corporation . Consultado el 19 de marzo de 2013 .
- ↑ "Especificación del lenguaje Java 4.3.1: Objetos" . Sun Microsystems . Consultado el 9 de diciembre de 2010 .
- ↑ Bloch 2018 , págs. 87–92, Capítulo §8 Punto 8: Favorecer la composición sobre la herencia.
- ↑ Goetz et al. 2006 , pp. 25–26, §2.3.1 Bloqueos intrínsecos.
- ↑ Estándar para el lenguaje de programación C++ '11, 5.3.2 Incremento y decremento [expr.pre.incr].
- ↑ Especificación del lenguaje Java™, Java SE 7 Edition, Capítulos 15.14.2, 15.14.3, 15.15.1, 15.15.2, http://docs.oracle.com/javase/specs/
- ↑ Oracle Corporation. "Capítulo 15. Expresiones" . docs.oracle.com . Oracle Corporation . Consultado el 31 de mayo de 2026 .
- 1 2 3 Bloch 2018 , págs. 34–36, Capítulo §2 Punto 9: Preferir intentar con recursos a intentar finalmente.
- ↑ Satish Chandra Gupta; Rajeev Palanki (16 de agosto de 2005). "Fugas de memoria en Java: atrápame si puedes" . IBM DeveloperWorks. Archivado del original el 22 de julio de 2012. Consultado el 2 de abril de 2015 .
- ↑ Cómo solucionar fugas de memoria en Java por Veljko Krunic (10 de marzo de 2009)
- ↑ Cómo crear una fuga de memoria con Java en stackoverflow.com
- ↑ cppreference.com. "operador typeid" . cppreference.com . cppreference.com . Consultado el 13 de abril de 2026 .
- ↑ cppreference.com. "nueva expresión" . cppreference.com . cppreference.com . Consultado el 13 de abril de 2026 .
- ↑ cppreference.com. "conversión dynamic_cast" . cppreference.com . cppreference.com . Consultado el 13 de abril de 2026 .
- ↑ Colección de compiladores GNU. "Excepciones: Capítulo 3. Uso" . gcc.gnu.org . Colección de compiladores GNU . Consultado el 13 de abril de 2026 .
- ↑ cppreference.com. "Especificación de excepciones dinámicas (hasta C++17)" . cppreference.com . cppreference.com . Consultado el 13 de abril de 2026 .
- ↑ Sutter, Herb. "Entrenamiento en jaula para Tiamat, desvinculando a Cthulhu: domesticando a los monstruos UB en C++" . Sutter's Mill .
- ↑ Konstantin Varlamov, Louis Dionne (14 de febrero de 2025). "Refuerzo de la biblioteca estándar" . open-std.org . WG21.
- ↑ "Escriba alias, plantilla de alias" . cppreference.com . Consultado el 4 de octubre de 2022 .
- ↑ "Plantilla variable" . cppreference.com . Consultado el 4 de octubre de 2022 .
- ↑ Los genéricos de Java son Turing completos
- ↑ Clark, Nathan; Amir Hormati; Sami Yehia; Scott Mahlke (2007). "Liquid SIMD: Abstraer el hardware SIMD usando mapeo dinámico ligero". Hpca'07 : 216–227 .
- ↑ Hundt, Robert (27 de abril de 2011). "Reconocimiento de bucles en C++/Java/Go/Scala" (PDF) . Stanford, California: Scala Days 2011. Archivado (PDF) del original el 9 de octubre de 2022. Recuperado el 17 de noviembre de 2012.
Java muestra un gran componente de recolección de basura, pero un buen rendimiento del código. [...] Encontramos que, en cuanto al rendimiento, C++ gana por un amplio margen. [...] La versión de Java fue probablemente la más sencilla de implementar, pero la más difícil de analizar en cuanto a rendimiento. Específicamente, los efectos en torno a la recolección de basura fueron complicados y muy difíciles de ajustar; 318
kB
- ↑ Matthew Hertz, Emery D. Berger (2005). "Cuantificación del rendimiento de la recolección de basura frente a la gestión explícita de memoria" (PDF) . OOPSLA 2005. Archivado del original (PDF) el 6 de julio de 2017. Recuperado el 15 de marzo de 2015.
En particular, cuando la recolección de basura tiene cinco veces más memoria de la requerida, su rendimiento en tiempo de ejecución iguala o supera ligeramente el de la gestión explícita de memoria. Sin embargo, el rendimiento de la recolección de basura se degrada sustancialmente cuando debe usar montones más pequeños. Con tres veces más memoria, se ejecuta un 17 % más lento en promedio, y con el doble de memoria, se ejecuta un 70 % más lento.
- ↑ Alexandrescu, Andrei (2001). Addison-Wesley (ed.). Diseño moderno de C++: Programación genérica y patrones de diseño aplicados. Capítulo 4. págs. 77–96 . ISBN 978-0-201-70431-0.
- ↑ "Biblioteca Boost Pool" . Boost . Consultado el 19 de abril de 2013 .
- ↑ Selección de procesadores con arquitectura IA-32 para la comprobación del rendimiento en tiempo de ejecución
- ↑ "Solucionando el problema de la inserción de código en línea" por el Dr. Cliff Click |Azul Systems: Blogs" . Archivado del original el 7 de septiembre de 2011. Consultado el 23 de septiembre de 2011 .
- ↑ Red de tecnología Oracle para desarrolladores Java
- ↑ Herb Sutter (13 de julio de 2019). "Preguntas frecuentes sobre el borrador: ¿Por qué se publica el estándar C++ cada tres años?" . herbsutter.com . herbsutter.com.
- ↑ Especificación del lenguaje Java
- ↑ Reinhold, Mark (6 de septiembre de 2017). "Impulsando Java hacia adelante más rápido" . Recuperado el 16 de septiembre de 2017 .
- ↑ "Llamando a 'todos a bordo' al tren de lanzamiento de Java de seis meses" . theserverside.com. 12 de septiembre de 2017. Consultado el 16 de septiembre de 2017 .
- ↑ Programa Java Community Process(SM) - Participación - Miembros de JCP
- ↑ Preguntas frecuentes de Bjarne Stroustrup: ¿Tienes C++?
- ↑ ZDNet: Oracle compra Sun; ahora es propietaria de Java. Archivado el 10 de abril de 2010 en Wayback Machine .
Fuentes
Enlaces externos
- Diferencia entre C++ y Java
- Gestión de memoria orientada a objetos: Java vs. C++
- Capítulo 2: En qué se diferencia Java de C , capítulo de Java en pocas palabras, de David Flanagan.
- Comparación de la gestión de recursos en Java y C++ : un artículo completo con ejemplos.
- Rendimiento de Java vs C... otra vez... - Análisis en profundidad de las diferencias de rendimiento entre Java y C/C++
- Hyperpoly: Comparación entre Java y C++
- Comparación de lenguajes de programación individuales
- Java (lenguaje de programación)
- C++