Javac编译时报“非法的前向引用”,以及Eclipse自带的Java编译器的缺陷

编译以下类的时候,如果切换WARNING_LEVEL的赋值方式为"= StatusDef.WARNING",javac会报“非法的前向引用”。 Eclipse自带的编译器会编译通过,这是Eclipse编译器的一个缺陷。

产生这个编译错误的原因是,cinit方法是按照字段在源码中的声明顺序依次执行各个初始化代码段。 对于ForwardReference类,cinit方法依次执行以下功能:

  1. 通过NORMAL_LEVEL的数值,创建C0000_1字段。 在ForwardReference.class文件中,NORMAL_LEVEL字段的初始值是写在字段的attribute属性中的, 因此在进入cinit方法以前,NORMAL_LEVEL字段已经被设置好了初始值,即0x32.
  2. 通过WARNING_LEVEL的数值,创建C0000_2字段。但是,此时WARNING_LEVEL字段的数值还是0。
  3. 把WARNING_LEVEL字段的数值设置为StatusDef.WARNING。 可以看到,第二步创建的C0000_2并没有包含开发者期望的结果。
    public enum ForwardReference {
    	C0000_1 (ForwardReference.NORMAL_LEVEL),
    	C0000_2 (ForwardReference.WARNING_LEVEL);
    
    	public static final short NORMAL_LEVEL = 0x32;
    
    	// 切换以下注释行,以在javac下产生”非法前向引用的错误“
    //	public static final short WARNING_LEVEL = StatusDef.WARNING;
    	public static final short WARNING_LEVEL = 0x08;
    
    	private final short statusLevel;
    
    	public short getStatusLevel() {
    		return statusLevel;
    	}
    
    	private ForwardReference(short statusLevel){
    		this.statusLevel = statusLevel;
    	}
    
    	public static void main(String[] args){
    		System.out.println(ForwardReference.C0000_1.getStatusLevel());
    		System.out.println(ForwardReference.C0000_2.getStatusLevel());
    	}
    }
    
    class StatusDef {
    	public final static Short WARNING = 0x08;
    }
时间: 2025-01-05 06:31:26

Javac编译时报“非法的前向引用”,以及Eclipse自带的Java编译器的缺陷的相关文章

java 报错非法的前向引用

今天在看<thinking in java>的时候,第四章提到了非法的前向引用,于是自己试了一下,书中的例子倒是一下就明白了,但是自己写的一个却怎么也不明白,于是上网问了一位前辈,终于明白啦! 这个是错误的代码: class BB { static int a = 0 ; public BB() { a++ ; System.out.println("执行BB" + a) ; } public void printA() { System.out.println("

关于javac编译时出现“非法字符:\65279”的解决方法

一般用UE或记事本编辑过的UTF-8的文件头会加入BOM标识,该标识由3个char组成.在UTF-8的标准里该BOM标识是可有可无的,Sun 的javac 在编译带有BOM的UTF-8的格式的文件时会出现"非法字符:\65279"的错误,但是用Eclipse进行编译却没有问题,原因在于Eclipse使用的是自己的JDT,而非javac,关于JDT的描述可以到eclipse的官网上去查看. 出现这种情况时,有两种解决方法: a) 利用UE.Editplus等文本编辑器重新保存文件为不带B

Javac编译和JIT编译

编译过程 不论是物理机还是虚拟机,大部分的程序代码从开始编译到最终转化成物理机的目标代码或虚拟机能执行的指令集之前,都会按照如下图所示的各个步骤进行: 其中绿色的模块可以选择性实现.很容易看出,上图中间的那条分支是解释执行的过程(即一条字节码一条字节码地解释执行,如JavaScript),而下面的那条分支就是传统编译原理中从源代码到目标机器代码的生成过程. 如今,基于物理机.虚拟机等的语言,大多都遵循这种基于现代经典编译原理的思路,在执行前先对程序源码进行词法解析和语法解析处理,把源码转化为抽象

【深入Java虚拟机】之七:Javac编译与JIT编译

转载请注明出处:http://blog.csdn.net/ns_code/article/details/18009455 编译过程 不论是物理机还是虚拟机,大部分的程序代码从开始编译到最终转化成物理机的目标代码或虚拟机能执行的指令集之前,都会按照如下图所示的各个步骤进行: 其中绿色的模块可以选择性实现.很容易看出,上图中间的那条分支是解释执行的过程(即一条字节码一条字节码地解释执行,如JavaScript),而下面的那条分支就是传统编译原理中从源代码到目标机器代码的生成过程. 如今,基于物理机

javac 编译与 JIT 编译

编译过程 不论是物理机还是虚拟机,大部分的程序代码从开始编译到最终转化成物理机的目标代码或虚拟机能执行的指令集之前,都会按照如下图所示的各个步骤进行: 其中绿色的模块可以选择性实现.很容易看出,上图中间的那条分支是解释执行的过程(即一条字节码一条字节码地解释执行,如 JavaScript),而下面的那条分支就是传统编译原理中从源代码到目标机器代码的生成过程. 如今,基于物理机.虚拟机等的语言,大多都遵循这种基于现代经典编译原理的思路,在执行前先对程序源码进行词法解析和语法解析处理,把源码转化为抽

Intellij编译时报“java: System Java Compiler was not found in classpath” 解决办法

Intellij编译时报“java: System Java Compiler was not found in classpath” 解决方法: Project Settings > Compiler > Java Compiler changed the drop down Use compiler from Javac to Eclipse!

java和javac编译运行java程序

目录 目录 前言 编译命令介绍 javac java 代码编译与运行 java类发现规则 分离class和java文件 参考链接 前言 给自己定了一个月学习JVM虚拟机的计划,不管有没有卵用,学点新东西总是好的. 但是在学习过程中,我想在命令行测试一些JVM参数的时候,发现自己脱离了IDE,竟然无法直接编译java程序!! 我的原则不能抱怨太多,像个Loser,不会的就花时间补回来. 下面,主要是总结一些如何在命令行中编译java程序.主要是想记录总结一下java的类发现原则. 编译命令介绍 其

JAVAC 编译JAVA文件

1.编译带有包声明的JAVA类 package aa; public class B { public static void main(String[] args) { System.out.println("f"); } } 用JAVAC编译完这个文件时,如果直接用java B 来执行的话,会报错 Exception in thread "main" java.lang.NoClassDefFoundError: B (wrong name: aa/B) at

javac 编译异常总结

1 error: package com.sun.image.codec.jpeg does not exist 使用Ant编译类时,当类中引用了com.sun.image.*下的类时会报错,找不到类 [解决办法] 将%JAVA_HOME%/jre/rt.jar拷贝到%ANT_HOME%/lib或其他文件夹,然后在javac时指定 eg: <javac destdir="target/ROOT/WEB-INF/classes"         optimize="off