Versión major.minor no compatible 51.0 Cómo resolver el problema
Después de probar los beneficios de JDK1.5, creo que muchas personas encontraron el error No compatible major.minor versión 49.0 y estaban perdidas en ese momento. Porque al principio no había mucha información china relacionada con esto en Internet. Ahora, puedes encontrar cómo solucionarlo buscando en Internet. La mayoría te indicará que vuelvas a compilar con JDK 1.4. En cuanto a por qué, ¿qué es mayor.menor? De eso se trata esta publicación de blog para que lo sepas antes de cometer un error.
Supongo que tuve suerte porque antes de encontrarme con este error, había leído "Dentro de la máquina virtual Java" (segunda edición) y sabía dónde se escondía major.minor, pero no lo he experimentado. así que tendré que esperar hasta tener la oportunidad de lidiar con major.minor no compatible. Realmente habrá una entrevista con la versión 49.0 major.minor no compatible, solo para verificar un hecho por mí.
En primer lugar, debemos establecer una idea directa de la versión 49.0 de major.minor no compatible: las clases compiladas de JDK1.5 no se pueden ejecutar en JVM 1.4 y deben compilarse en JVM 1.4 para ejecutarse. (Por supuesto, tal vez todavía esté usando JVM 1.3 o JVM 1.2, por lo que debe compilar en una clase que la JVM de destino pueda reconocer). Así es como se soluciona el problema.
Dos: ¿Dónde se encuentra major.minor?
¿Qué es major.minor y dónde se encuentra? Primer sentido y encontrar mayor.menor.
Escribe un Java ¡Hola mundo! código y luego use el compilador JDK 1.5 para compilarlo en HelloWorld.java
paquete com.unmi
clase pública HelloWorld
{
;public static void main(String[] args)
{
System.out.println("¡Hola, mundo!");
}
paquete com.unmi; clase pública HolaMundo{ public static void main(String[] args) { System.out.println("¡Hola mundo!"); }
Utilice JDK 1.5 javac -d para compilar HelloWorld.java. Utilice UltraEdit para abrir el código de bytes compilado de HelloWorld.java. El contenido de HelloWorld.class se muestra en la figura:
En la figura anterior podemos ver cuál es la versión mayor.menor, que es equivalente a. la versión principal de un software y el número de versión secundaria, pero aquí está el número de versión principal y el número de versión secundaria que identifican una clase Java. Al mismo tiempo, vemos que versión_menor es 0x0000, versión_mayor es 0x0031, convertido a diez. dígitos, es decir, 0 y 49, es decir, mayor.menor es 49,0.
3. ¿Qué es mayor.menor? ¿Qué es major.minor y para qué se utiliza?
Los bytes 5-8 del archivo de clase son minor_version y major_version. A medida que cambia el formato del archivo de clase, el número de versión también cambiará. Para la JVM, el número de versión identifica un formato de archivo de clase específico y, por lo general, la JVM solo puede leer un archivo de clase si obtiene un número de versión principal y un conjunto de números de versión menores. Si el número de versión de un archivo de clase excede el rango válido que la JVM puede procesar, la JVM no procesará el archivo de clase.
En la versión JDK 1.0.2 de Sun, la JVM implementó soporte para formatos de archivos de clase 45.0 a 45.3. Todas las JVM en JDK 1.1 admiten las versiones 45.0 a 45.65535 del formato de archivo de clase. En la versión 1.2 SDK de Sun, la JVM admite las versiones 45.0 a 46.0 del formato de archivo de clase.
Un compilador versión 1.0 o 1.2 puede generar archivos de clase versión 45.3. En la versión 1.2 del SDK de Sun, el compilador Javac genera archivos de clase con la versión 45.3 de forma predeterminada. Sin embargo, si se especifica el indicador -target 1.2 en la línea de comando javac, un compilador de la versión 1.2 generará archivos de clase con el número de versión 46.0.
En la versión 2 de la implementación JVM, la interpretación de los números de versión mayor y menor del archivo de clase cambió. En la versión 2, el número de versión principal de un archivo de clase es consistente con el número de versión de la versión principal de la plataforma Java (por ejemplo, en la versión de la plataforma Java 2, el número de versión principal se aumentó de 45 a 46), mientras que el número de versión secundaria es coherente con la versión principal específica que está asociada a cada versión de la plataforma. Por lo tanto, aunque diferentes formatos de archivos de clase pueden representarse mediante diferentes números de versión, diferentes números de versión no significan que los formatos de archivos de clase sean diferentes. El motivo de los diferentes números de versión puede ser que estos archivos de clase fueron generados por diferentes versiones de la plataforma Java y es posible que el formato de los archivos de clase no haya cambiado.
Los tres párrafos anteriores están extraídos de "Comprensión profunda de la máquina virtual Java". En pocas palabras, JDK 1.2 abrió la era de Java 2, pero esta era aún está lejos de nosotros. Todavía estamos en JDK 1.4. Salté directamente a él, que es casi lo mismo para mí, pero debido a los requisitos del proyecto, tuve que retroceder temporalmente y usar JDK 1.3. Pero la información general que podemos obtener es que los archivos de clase compilados por cada versión del compilador JDK tienen un número de versión. El rango de números de versión de clase que diferentes JVM pueden aceptar es diferente, lo que excede el rango de error. Pero esto es generalmente compatible con versiones anteriores. ¿Conoces el eslogan de Solaris de Sun? Mantener una compatibilidad binaria del 100 % con versiones anteriores protege las inversiones de los clientes.
Cuatro: Otros métodos para determinar la versión mayor.menor de una clase
1) Vista de Eclipse
Eclipse 3.3 agrega una nueva característica, cuando una clase lo hace no coincide Cuando el código fuente está asociado, al abrirlo se mostrará información más detallada sobre la clase. Por supuesto, no ha alcanzado el nivel del código fuente. La siguiente imagen muestra la información que se muestra al abrir 2.0 spring.jar ClasspathXmlApplicationContext.class
2) Comando javap -verbose
Para archivos de clase compilados, use javap -verbose para mostrar la versión mayor.menor de la clase, como se muestra a continuación:
3) El comando javap -verbose -verbose -verbose -verbose puede mostrar la versión mayor.menor de la clase.
Vea la imagen a continuación:
3) Archivo MANIFEST
Cuando la clase se coloca en el paquete JAR, habrá un archivo META-INF/MANIFEST. Este archivo generalmente tiene información del compilador. , como se detalla a continuación, le mostraré el contenido de los archivos META-INF/MANIFEST de varios paquetes.
La parte META-INFO/MANIFEST de -Velocity -Velocity-1.5.jar
Versión de manifiesto: 1.0
Versión de Ant: Apache Ant 1.7.0
Creado por: Apache Ant
Paquete: org.apache.velocity
Build-Jdk: 1.4.2_08
Extensión: speed
Podemos ver que está empaquetado con ant, y el JDK usado para construirlo es 1.4 .2_08, por lo que las clases compiladas que utilicen 1.4, por supuesto, se ejecutarán en 1.4. Por supuesto, la JVM ejecutará clases compiladas con 1.4 en una JVM 1.4. Sería aburrido si este tipo compilara con 1.5 JDK y luego empaquetara con JDK 1.4 ANT.
-2.0 Sección META-INFO\MANIFEST de spring.jar
Versión de manifiesto: 1.0
Versión de Ant: Apache Ant 1.6.5
Creado por: 1.5.0_08 -b03 (Sun Microsystems Inc.)
Título de implementación: Ahora tenga en cuenta que está compilado con JDK 1.5, por lo que viene con -target 1.4 o -objetivo 1.3? Sí, puedes verificar el binario de la clase, eso es lo más seguro. b28 (Sun Microsystems Inc.)
Construido con JDK 1.4.
El primer y segundo método pueden comprender claramente la versión mayor.menor. El tercer método no debería ser un problema, pero si encuentra compilaciones anormales, por ejemplo, cambie META-INFO\MANIFEST Empaquetado y cámbielo. es difícil saberlo. Un enfoque directo para observar el archivo binario garantizaría la precisión y también aceptaría el hecho de que fue manipulado por herramientas.
Cinco: Comparación del compilador y el meollo del problema
Ahora puede ser la versión menor.mayor predeterminada de las clases compiladas por el compilador JDK 1.1 a JDK 1.7.
(Luego fui al sitio web de Sun para buscar antigüedades antiguas que nunca había usado)
Parámetro de destino de la versión del compilador JDK hexadecimal minor.major decimal minor.major
jdk1.1.8 no puede aceptar el parámetro de destino 00 03 00 2D 45.3
jdk1.2.2 sin (el valor predeterminado es -target 1.1) 00 03 00 2D 45.3
jdk1.2.2 -target 1.2 00 00 00 2E 46.0
jdk1.3.1_19 sin (el valor predeterminado es -target 1.1) 00 03 00 2D 45.3
jdk1.3.1_ 19 -target 1.3 19 -target 1.3 00 00 00 2F 47.0
j2sdk1.4.2_10 sin (el valor predeterminado es -target 1.2) 00 00 00 2E 46.0
j2sdk1.4.2_10 -target 1.4 00 00 00 30 48.0
jdk1.5.0 ._11 sin (el valor predeterminado es -target 1.5) 00 00 00 31 49.0
jdk1.5.0_11 -target 1.4 -source 1.4 00 00 30 48.0
jdk1.6.0_01 sin (valor predeterminado a -objetivo 1.6) 00 00 00 32 50.0
jdk1.6.0_01 -objetivo 1.5 00 00 00 31 49.0
jdk1 6.0_01 -objetivo 1.4 -fuente 1.4. 00 00 30 48.0
jdk1.7.0 sin (el valor predeterminado es -target 1.6) 00 00 32 50.0
jdk1.7.0 -target 1.7 00 00 33 51.0
jdk1.7.0 -target 1.4 -source 1.4 00 00 00 30 48.0
Apache Harmony 5.0M3 sin (el valor predeterminado es -target 1.2) 00 00 2E 46.0
Apache Harmony 5.0M3 -target 1.4 00 00 00 30 48.0
Lo anterior es una comparación de compiladores JDK en la plataforma Windows. Podemos resumirlo aquí:
1) -target 1.1 tiene un número de versión menor. El objetivo es la versión 1.2 y posteriores, solo se utiliza el número de versión principal y el número de versión secundaria es 0
2) La diferencia de idioma de 1.1 a 1.4 es relativamente pequeña, por lo que el objetivo predeterminado de 1.2 a 1.4 no es la versión en sí misma
3) La sintaxis de 1.5 ha cambiado mucho, por lo que el destino predeterminado es 1.5. Por lo tanto, un JDK de 1,5 debe generar un objetivo de 1,5 y un objetivo de 1,5 es 1,5.
Para usar 1.5 JDK para generar código destinado a 1.4, simplemente -target 1.4 no es suficiente. También debe traer -source 1.4 para especificar la compatibilidad del código fuente. El código generado por 1.6/1.7 JDK también se basa en 1.4. .
4) El compilador 1.6 es más agresivo y usa -target 1.6 por defecto.
5) Tenga en cuenta que el destino predeterminado para la compilación 1.7 es 1.6
6) Otros terceros
6) El formato de los archivos de clase generados por otros Los JDK de terceros son los mismos que La versión correspondiente de Sun del JDK es la misma
7) Finalmente, y lo más importante, es necesario comparar entre 1.6 y 1.5. Finalmente, y lo más importante, la versión principal más grande de un archivo de clase que una versión particular de la JVM puede aceptar no debe ser mayor que la versión del archivo de clase que el JDK correspondiente compiló con los parámetros de destino correspondientes.
La oración anterior es un poco larga y no es fácil de leer de una vez, así que aquí hay un ejemplo: El número máximo de versión principal de un archivo de clase aceptado por la JVM 1.4 no puede ser mayor que la clase compilada. por el JDK 1.4 usando el parámetro -target 1.4 El número de versión principal del archivo, que es 48.
Dado que el destino predeterminado es 1.5, los archivos generados no excederán el número de versión principal del archivo de clase compilado con el JDK correspondiente usando el parámetro -target 1.5 y, por lo tanto, no excederán 48. La versión de bytecode major.minor para el objetivo 1.5 es 49.0, por lo que la JVM 1.4 no puede aceptarlo y arroja un error.
Entonces, cuando el JDK se actualiza de 1.1 a 1.2, 1.2 a 1.3 o 1.3 a 1.4, ¿por qué no aparece el error de versión mayor.menor no compatible? Esto se debe a que 1.2/1.3/1.4 mantiene una buena compatibilidad binaria. Los objetivos de 1.2/1.3/1.4 son 1.1/1.1/1.2 respectivamente. En otras palabras, los archivos de clase compilados por el JDK 1.4 de forma predeterminada se pueden cargar y ejecutar en JVM 1.2, y mucho menos en JVM 1.3. (
Seis: encuentre una solución al problema
Así que ahora, si encuentra este problema y sabe cómo resolverlo, también puede encontrar un JDK 1.4, descargarlo e instalarlo. y luego usarlo para recompilar todo el código, como vi que hicieron algunos de mis amigos. De hecho, no tiene por qué ser tan problemático. Debes recordar que hay un parámetro -target en javac. , puede continuar usando el JDK 1.5 y compilar con los parámetros -target 1.4 -source 1.4. Sin embargo, debe tener claro qué API se han agregado al JDK 1.5. No puede transferir sus archivos de clase a la JVM 1.4. Si la JVM de destino es 1.3, la opción de compilación es -target 1.3 -source 1.3. En consecuencia, si se usa ant, su tarea javac también puede corresponder al destino y al código fuente Select
lt;javac target. ="1.4" source="1.4" ......................../ gt;
Si estás desarrollando, es Es seguro decir que muchos IDE de JAVA ahora tienen opciones de compilación que configuran el código de destino del proyecto. Por ejemplo, la configuración del compilador de Java en las propiedades del proyecto de Eclipse, como se muestra en la figura.
En la configuración propia. opciones del compilador, verá los diferentes niveles de cumplimiento del compilador que se pueden seleccionar, y la compatibilidad del archivo de clase generado y la compatibilidad del código fuente también cambian constantemente.
La compatibilidad del archivo de clase generado y la compatibilidad del código fuente también cambian constantemente. También puede ajustar manualmente estos dos elementos. Al configurarlo manualmente, no tiene que preocuparse por la versión del compilador. el código de bytes que queremos y luego expandirlo un poco, incluso si el código fuente está escrito en VB, no importa siempre que pueda compilarse en un código de bytes que pueda ser ejecutado por la JVM. También puede encontrar los cuadros de diálogo de configuración correspondientes en otros entornos de desarrollo integrados.
De lo contrario, debe conocer la versión de la JVM que está utilizando actualmente y los números de versión principal del código de bytes que acepta (consulte la tabla anterior). Hay dos formas de averiguar la versión actual de JVM:
Primero, si usa el comando java para ejecutar el programa directamente desde la consola, puede usar java -version para ver la versión actual de JVM y luego determine cuál es aceptable. Versión del archivo de clase
En segundo lugar, si está ejecutando el programa en un contenedor y no sabe qué JVM está utilizando, puede agregar el código System.getProperty("java). .runtime.version"); o System. getProperty("java.class.version") para obtener la versión de JVM y los números de versión de clase aceptables.
Un último consejo es si no deseas recompilar todo tu código para una versión inferior de la JVM con parámetros de destino; si aún deseas continuar usando la nueva API en tu código o algo peor; Si está utilizando las nuevas características de JDK 1.5, como genéricos, desempaquetado automático, enumeraciones, etc., entonces no puede compilar su código. Entonces no puede usar -target 1.4 -source 1.4 para compilar su código y debe reorganizarlo. código para que funcione correctamente. Entonces déjame contarte el último truco: no necesitas comenzar desde el código fuente, convertir directamente tu código de bytes compilado normalmente y continuar disfrutando de esas nuevas características y nuevas API, es decir: consulta un blog anterior: Retrotranslator Le permite usar las funciones de JDK1.5 para escribir código que se puede ejecutar en JVM1.4. Así es como lo uso, no habrá problemas. Yo lo estoy usando y si pruebas bien no deberías tener ningún problema.
Siete: Otro problema relacionado que realmente ocurrió
Este es un error que no admite la versión 49.0 de major.minor al copiar Tomcat. Esta es la situación: instalé JDK 1.5 localmente y encontré un instalador EXE Tomcat en línea, lo instalé y funcionó. Más tarde, un colega quería un Tomcat pero no quería descargarlo ni instalarlo, así que, según mi experiencia pasada, simplemente le copié todo el directorio de mi Tomcat. Como resultado, todos los archivos jsp que buscó eran importantes no compatibles. Errores menores de la versión 49.0. Estoy seguro de que instaló JDK 1.4, pero todavía estoy un poco confundido. Todavía estoy un poco desconcertado y mi confianza anterior en esta pregunta me dejó sin palabras. La idea habitual es que este tipo de excepciones se producirán cuando los archivos de clases compilados se utilicen en versiones inferiores de JVM, pero ¿es posible ejecutar clases que hayan sido compiladas con JDK 1.5?
Más tarde, leí el mensaje de excepción detenidamente y finalmente descubrí la pista TOMCAT_HOME\common\lib\tools.jar. Debido a que el archivo jsp necesita ser compilado por él, escribí un archivo de clase en estas herramientas. jar. Mira, 49.0, ¡y pronto me di cuenta de que este archivo estaba en mi máquina! Al instalar Tomcat, el instalador de Tomcat lo copió del directorio JDK1.5\lib al directorio lib de Tomcat. Como resultado, al compilar JSP en la máquina de mi colega, la JVM 1.4 se emparejó con el archivo tools.jar 49.0. incorrecto, así que lo encontré. Simplemente reemplace Tomcat con tools.jar de JDK 1.4 y estará bien.
Ocho: Resumen
De hecho, entender major.minor es como podemos imaginar que es imposible que una aplicación de 32 bits se ejecute en un sistema de 16 bits si También es un programa de Microsoft. Ejecútalo.
Si conocemos la versión de la JVM de destino antes de publicarla y sabemos cómo distinguir la versión mayor.menor del archivo de clase Java, entonces no tenemos que esperar a que el servidor informe la excepción. antes de solucionarlo, y también podemos anticiparnos a los problemas que puedan surgir.
Cuando se encuentre con este tipo de problema en otros momentos, debe resolverse de manera específica. En resumen, la causa principal del problema es que la versión inferior de la JVM no puede cargar la versión superior. archivo de clase. El archivo de clase debe encontrar una versión superior del archivo de clase para procesarlo.