public class A {
    B b = new B();
}public class B {
    A a = new A();
}类之间循环引用问题,单独使用javac A 不能通过编译,会报“找不到类符号B”的错误。但使用javac *.java却可以编译通过,有谁知道原理
本人学了两年java想不通惭愧ing

解决方案 »

  1.   

    ...这没什么原理可说 你B.class不存在 他上哪去找 打包一起编译才能过
    你一样可以用javac A.java B.java
      

  2.   

    打包和引用的问题吧a需要引用b
    b也需要引用a
    但是你得在a引用b的时候告诉b在哪里吧
    同时也得告诉系统b引用a的时候a在哪里啊如果没有提前打包
    b的定义在a后面
    系统都还没有跑到哪里去编译
    当然就不存在b
    自然就找不到b咯
      

  3.   

    A引用了B,然后你单独编译A,肯定就找不到B啦。
      

  4.   

    javac -verbose *.java
      

  5.   

    编译A的时候
    B b = new B(); 需要用到B类型,已经B()构造函数,这个时候,就需要编译器去检查B是否存在,而且B()是否存在
    如果没有,就去找.java,编译一下。感觉循环引用,确实违反直觉,其实没什么想不通的:java.lang.Object {public String toString() {....}}
    Object这个元始天尊都需要依赖别人。编译A的时候,只要知道B存在,而且所有对B的操作都是合法的(方法存在、参数类型正确等),那么A就能编译通过。因为编译到A中的只是B和B()这个名字(可以想象成字符串)而不是B本身。
      

  6.   

    有点类似反射
    你可以先没有B,直接写Class.forName("B"),然后只要在运行以前编写class B就可以了。
      

  7.   


    上面这样是会内存溢出,不过将B的声明改为
    public class B {
      A a ;
    }
    就不会有任何问题了
      

  8.   


    感觉这位说得挺对的,不过照这样说的话,那么在javac A的时候其实就应该是已经对的了,因为编译器会去智能的去找B的声明。而不应该在javac *.java的时候才去找吧。
      

  9.   

    大概是编译的时候只会在javac命令后面找要编译的类,单独列出A时会导致找不到B,但是*.java的时候就行了
      

  10.   


    public class A {}即使上面代码,楼主只javac A仍然会编译不通过,必须javac A.java才可以
      

  11.   

    额,你单独编译当然不行,你相关的引用找不到,但是用* 就不一样了,是全部,这个javac 内部有处理
      

  12.   

    另外,如果你没有包,而且在当前目录编译的话,不可能存在
    javac A.java编译不通过的情况:D:\test>del *.classD:\test>type A.java
    public class A {
      B b = new B();
    }
    D:\test>type B.java
    public class B {
      A a = new A();
    }
    D:\test>javac -version
    javac 1.6.0_27D:\test>javac -verbose A.java
    [解析开始时间 A.java]
    [解析已完成时间 15ms]
    [源文件的搜索路径: .]
    [类文件的搜索路径: D:\Java\jdk1.6.0\jre\lib\resources.jar,D:\Java\jdk1.6.0\jre\
    lib\rt.jar,D:\Java\jdk1.6.0\jre\lib\sunrsasign.jar,D:\Java\jdk1.6.0\jre\lib\jsse
    .jar,D:\Java\jdk1.6.0\jre\lib\jce.jar,D:\Java\jdk1.6.0\jre\lib\charsets.jar,D:\J
    ava\jdk1.6.0\jre\lib\modules\jdk.boot.jar,D:\Java\jdk1.6.0\jre\classes,D:\Java\j
    dk1.6.0\jre\lib\ext\dnsns.jar,D:\Java\jdk1.6.0\jre\lib\ext\localedata.jar,D:\Jav
    a\jdk1.6.0\jre\lib\ext\sunjce_provider.jar,.]
    [正在装入 java\lang\Object.class(java\lang:Object.class)]
    [正在装入 .\B.java]
    [解析开始时间 .\B.java]
    [解析已完成时间 1ms]
    [正在检查 A]
    [已写入 A.class]
    [正在检查 B]
    [已写入 .\B.class]
    [总时间 406ms]D:\test>
      

  13.   

    如果你在其他目录的话,或者有包的话:
    可以使用-sourcepath参数
    D:\test>cd \D:\>del test\*.classD:\>type test\A.java
    public class A {
      B b = new B();
    }
    D:\>type test\B.java
    public class B {
      A a = new A();
    }
    D:\>javac -verbose test\A.java
    [解析开始时间 test\A.java]
    [解析已完成时间 15ms]
    [源文件的搜索路径: .]
    [类文件的搜索路径: D:\Java\jdk1.6.0\jre\lib\resources.jar,D:\Java\jdk1.6.0\jre\
    lib\rt.jar,D:\Java\jdk1.6.0\jre\lib\sunrsasign.jar,D:\Java\jdk1.6.0\jre\lib\jsse
    .jar,D:\Java\jdk1.6.0\jre\lib\jce.jar,D:\Java\jdk1.6.0\jre\lib\charsets.jar,D:\J
    ava\jdk1.6.0\jre\lib\modules\jdk.boot.jar,D:\Java\jdk1.6.0\jre\classes,D:\Java\j
    dk1.6.0\jre\lib\ext\dnsns.jar,D:\Java\jdk1.6.0\jre\lib\ext\localedata.jar,D:\Jav
    a\jdk1.6.0\jre\lib\ext\sunjce_provider.jar,.]
    [正在装入 java\lang\Object.class(java\lang:Object.class)]
    test\A.java:2: 找不到符号
    符号: 类 B
    位置: 类 A
      B b = new B();
      ^
    [正在检查 A]
    test\A.java:2: 找不到符号
    符号: 类 B
    位置: 类 A
      B b = new B();
                ^
    [总时间 243ms]
    2 错误D:\>javac -verbose -sourcepath test test\A.java
    [解析开始时间 test\A.java]
    [解析已完成时间 15ms]
    [源文件的搜索路径: test]
    [类文件的搜索路径: D:\Java\jdk1.6.0\jre\lib\resources.jar,D:\Java\jdk1.6.0\jre\
    lib\rt.jar,D:\Java\jdk1.6.0\jre\lib\sunrsasign.jar,D:\Java\jdk1.6.0\jre\lib\jsse
    .jar,D:\Java\jdk1.6.0\jre\lib\jce.jar,D:\Java\jdk1.6.0\jre\lib\charsets.jar,D:\J
    ava\jdk1.6.0\jre\lib\modules\jdk.boot.jar,D:\Java\jdk1.6.0\jre\classes,D:\Java\j
    dk1.6.0\jre\lib\ext\dnsns.jar,D:\Java\jdk1.6.0\jre\lib\ext\localedata.jar,D:\Jav
    a\jdk1.6.0\jre\lib\ext\sunjce_provider.jar,.]
    [正在装入 java\lang\Object.class(java\lang:Object.class)]
    [正在装入 test\B.java]
    [解析开始时间 test\B.java]
    [解析已完成时间 0ms]
    [正在检查 A]
    [已写入 test\A.class]
    [正在检查 B]
    [已写入 test\B.class]
    [总时间 262ms]D:\>
      

  14.   

    试了楼上的方法 javac A.java -sourcepath exception B.java 是可以编译通过的,这个可以解决不同包下相互依赖的问题
      

  15.   

    两个问题:
    1 为什么循环引用可以编译的道理,见上面9F,10F
    2 会报“找不到类符号B”的错误的原因,见26F,27F
      

  16.   


    下面是通过jasml看到的java字节码
    public class exception.A extends java.lang.Object{
    exception.B b
    public void <init> (){
               aload_0  
               invokespecial  void java.lang.Object.<init>()
               return  
    [MaxStack : 1]
    [MaxLocal : 1]
    }[SourceFile : A.java]
    }
    里面是只需要B的名字    不过既然这样,那在单独编译A的时候,java编译器为啥不会直接去当前目录智能的搜索class B的定义呢
    而非要通过javac A.java -sourcepath exception B.java这样的命令去指定依赖关系
        之所以是当前目录是因为两个类是声明在同一个包下的,如果不是同一个包则通过com.sun.xx声明去找相应的包,java编译器不会这么傻吧
      

  17.   

    ...我以为你俩class写一个java文件里 结果看完全文才知道... 没看懂难在哪里..
      

  18.   


    为啥不能智能,因为路径可能性太大假设D:\src是src目录有test包D:\src>javac test\A.java
    D:\src\test>javac A.java
    D:\src\test>javac ..\test\A.java
    E:\>javac D:\src\test\A.java
    ....另外,可能还会有多个src路径,假设D:\test\A.java,C:\B.java
    javac -sourcepath D:\test;C:\ D:\test\A.java
    不指定-sourcepath,没法搞
      

  19.   

    云里雾里的,没听明白如何学习java底层啊
      

  20.   

    #19楼是正解,楼主不要被大家侃晕了
    你只是打错了 少打了个.java
    我刚才亲自试了一下 javac A.java是可以的 但是他会把B.class也编译出来
    看了下
    好多人只是研究 从理论上探讨 运用自己并不熟悉的知识试图去解决问题 这简直太符合应试教育下的学生了
    对待问题就像考试一样 会不会的不管 不分析问题 而是把自己会的全部写出来其实自己去试一下就知道怎么回事了
    哎 悲哀啊
      

  21.   

    Oracle官网上关于javac -sourcepath的解释
    -sourcepath sourcepath
    Specify the source code path to search for class or interface definitions. As with the user class path, source path entries are separated by semicolons (;) and can be directories, JAR archives, or ZIP archives. If packages are used, the local path name within the directory or archive must reflect the package name.
    Note that classes found through the classpath are subject to automatic recompilation if their sources are found.
      

  22.   


    刚照你说的做了下javac -sourcepath D:\test\A.java 是不行的哈,用javac -sorucepath D:\test就可以。
    官方文档是的说明sourcepath 后面所接的参数can be directories, JAR archives, or ZIP archives.
      

  23.   


    我也没有刻意去学,只是涉及到这个问题时去google和在这边讨论发现的,今天参考了java虚拟机规范,接触了字节码。哈哈,一步一步积累吧CSDN的“连续3次回复限制”真蛋疼
      

  24.   

    结贴散分了~
    感谢各位的回复,尤其感谢shine333
    如果有没明白的请看shine333的回复~
      

  25.   

    Exception in thread "main" java.lang.StackOverflowError
      

  26.   


    我认为哈,会有这种想法的是不是不太理解汇编语言,编译原理等计算机基础课程的人呢?在汇编级别的程序里面哪有什么类啊,全都是指令和数据。public class A {
       B b = new B();
    }public class B {
       A a = new A();
    }
    这两个类其实很简单
    在A类里面有一个类型为B的数据,
    在B类里面有一个类型为A的数据。
    对计算机来说A,B和一个string没啥区别,都是某种类型的数据而已。
      

  27.   

    ....很想知道这个怎么运行啊还是 这个编译能通过但是运行不了我运行以后的结果为。        at A.<init>(A.java:2)
            at B.<init>(B.java:2)
            at A.<init>(A.java:2)
            at B.<init>(B.java:2)
            at A.<init>(A.java:2)
            at B.<init>(B.java:2)
            at A.<init>(A.java:2)
            at B.<init>(B.java:2)
            at A.<init>(A.java:2)
            at B.<init>(B.java:2)无线重复以后
    自动退出来了!
    这个应该是 报错吧
      

  28.   


    这个当然是死循环喽,不能运行的,除非去掉一个new ,比如说把A a = new A();改为A a;就可以了
      

  29.   

    还以为楼主省略了".java"呢?
    话说没把握的事得验证一下,没有人了解所有东西。
      

  30.   

    已经忽略了CSDN首面,难道还要忽略CSDN论坛首页?!
    推荐的帖子质量不断下降啊
      

  31.   

    某表示javac A.java 找不到符号javac *.java 仅当显式请求注释处理时才接受名称"A.java, B.java"javac A.java B.java 通过
    LS有个人说javac A.java直接通过  我估计你没删干净.class文件
      

  32.   


    不知道是不是JVM版本的问题,现在编译完全没有问题啊?