`
RednaxelaFX
  • 浏览: 3052952 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

默认构造器在javac里是什么时候加上去的?

    博客分类:
  • Java
阅读更多
读到ZangXT写的默认构造方法并非总是public的,顺便一提。

碰到语言问题先看规范。Java语言规范第三版8.8.9小节如是说:
Java Language Specification, 3rd Edition 写道
8.8.9 Default Constructor

...

In an enum type (§8.9), the default constructor is implicitly private. Otherwise, if the class is declared public, then the default constructor is implicitly given the access modifier public (§6.6); if the class is declared protected, then the default constructor is implicitly given the access modifier protected (§6.6); if the class is declared private, then the default constructor is implicitly given the access modifier private (§6.6); otherwise, the default constructor has the default access implied by no access modifier.

如ZangXT同学所说,默认构造器的可访问性是与类自身的可访问性相关的,并不总是public。

看完规范看实现。在Sun的javac编译器中,com.sun.tools.javac.main.JavaCompiler类中的compile()方法里有:
delegateCompiler = processAnnotations(enterTrees(stopIfError(parseFiles(sourceFileObjects))),
                                      classnames);

delegateCompiler.compile2();

同一个类中的compile2()方法里有:
while (todo.nonEmpty())
    generate(desugar(flow(attribute(todo.next()))));

也就是说javac编译Java源码可以分为下述几步:
1、解析(parseFiles),如果有语法错误则停止(stopIfError);
2、将类型的信息补全,检查是否存在循环依赖等问题,没有问题则将类型信息输入到符号表里(enterTrees);
3、处理注解(processAnnotations),如果这步生成了新的类型则对新类型从第1步开始递归处理;
4、为语法树标注属性(attribute);
5、对程序做流相关分析(flow),用于检查确定性赋值等流相关语义分析;
6、解语法糖(desugar):将泛型类型转换为非泛型的;将for-each等语法糖转换为基本语法结构,包括Java 7新增的switch里的String支持也在这步;将内部类和嵌套类转换后当作顶层类处理;
7、生成Class文件(generate),包括元信息和字节码。

OpenJDKCompiler项目中也有描述javac的编译步骤的文档
(不过OpenJDK站上不是所有文档都完全可信。在Compiler Grammar项目中的介绍:
引用
The parser that is currently in the javac compiler is a hand-written LALR parser.
就是错的。实际上现在的javac是基于LL(1)语法的递归下降式+运算符优先级解析,之前一帖已经提过了。)

在上述流程中,默认构造器是在哪一步加进来的呢?下面用一段代码为例说明:
package test.debug.javac;

public class TestDefaultConstructorVisibility {
    public class TestDefaultConstructorVisibilityPublicInnerClass {
    }

    class TestDefaultConstructorVisibilityDefaultInnerClass {
    }

    protected class TestDefaultConstructorVisibilityProtectedInnerClass {
    }

    private class TestDefaultConstructorVisibilityPrivateInnerClass {
    }
}

class TestDefaultConstructorVisibilityPackageVisibilityCase {
}


打开调试器,跟踪javac的编译过程,观察解析出来的语法树toString()之后的样子:
parseFiles后:
package test.debug.javac;

public class TestDefaultConstructorVisibility {
    
    public class TestDefaultConstructorVisibilityPublicInnerClass {
    }
    
    class TestDefaultConstructorVisibilityDefaultInnerClass {
    }
    
    protected class TestDefaultConstructorVisibilityProtectedInnerClass {
    }
    
    private class TestDefaultConstructorVisibilityPrivateInnerClass {
    }
}
class TestDefaultConstructorVisibilityPackageVisibilityCase {
}


stopIfError对语法树没有修改。

enterTrees后:
package test.debug.javac;

public class TestDefaultConstructorVisibility {
    
    public TestDefaultConstructorVisibility() {
        super();
    }
    
    public class TestDefaultConstructorVisibilityPublicInnerClass {
        
        public TestDefaultConstructorVisibilityPublicInnerClass() {
            super();
        }
    }
    
    class TestDefaultConstructorVisibilityDefaultInnerClass {
        
        TestDefaultConstructorVisibilityDefaultInnerClass() {
            super();
        }
    }
    
    protected class TestDefaultConstructorVisibilityProtectedInnerClass {
        
        protected TestDefaultConstructorVisibilityProtectedInnerClass() {
            super();
        }
    }
    
    private class TestDefaultConstructorVisibilityPrivateInnerClass {
        
        private TestDefaultConstructorVisibilityPrivateInnerClass() {
            super();
        }
    }
}
class TestDefaultConstructorVisibilityPackageVisibilityCase {
    
    TestDefaultConstructorVisibilityPackageVisibilityCase() {
        super();
    }
}

嗯,默认构造器已经加进来了。那么关注一下enterTrees里的逻辑。

Enter.complete()里,classEnter(trees, null);后都还没加上默认构造器。是在紧随其后的循环中clazz.complete();的调用加上了默认构造器。这是"enterTree"中的第二阶段,调用了MemberEnter.complete()。
com.sun.tools.javac.comp.MemberEnter.complete()
/* ********************************************************************
* Source completer
*********************************************************************/

/** Complete entering a class.
 *  @param sym         The symbol of the class to be completed.
 */
public void complete(Symbol sym) throws CompletionFailure {
    // Suppress some (recursive) MemberEnter invocations
    // ...

    ClassSymbol c = (ClassSymbol)sym;
    ClassType ct = (ClassType)c.type;
    Env<AttrContext> env = enter.typeEnvs.get(c);
    JCClassDecl tree = (JCClassDecl)env.tree;
    boolean wasFirst = isFirst;
    isFirst = false;

    JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
    try {
        // ...

        // Add default constructor if needed.
        if ((c.flags() & INTERFACE) == 0 &&
            !TreeInfo.hasConstructors(tree.defs)) {
            List<Type> argtypes = List.nil();
            List<Type> typarams = List.nil();
            List<Type> thrown = List.nil();
            long ctorFlags = 0;
            boolean based = false;
            if (c.name.len == 0) {
                JCNewClass nc = (JCNewClass)env.next.tree;
                if (nc.constructor != null) {
                    Type superConstrType = types.memberType(c.type,
                                                            nc.constructor);
                    argtypes = superConstrType.getParameterTypes();
                    typarams = superConstrType.getTypeArguments();
                    ctorFlags = nc.constructor.flags() & VARARGS;
                    if (nc.encl != null) {
                        argtypes = argtypes.prepend(nc.encl.type);
                        based = true;
                    }
                    thrown = superConstrType.getThrownTypes();
                }
            }
            JCTree constrDef = DefaultConstructor(make.at(tree.pos), c,
                                                typarams, argtypes, thrown,
                                                ctorFlags, based);
            tree.defs = tree.defs.prepend(constrDef);
        }

        // ...
    } catch (CompletionFailure ex) {
        chk.completionError(tree.pos(), ex);
    } finally {
        log.useSource(prev);
    }

    // ...
}

其中在DefaultConstructor()方法中:
/** Generate default constructor for given class. For classes different
 *  from java.lang.Object, this is:
 *
 *    c(argtype_0 x_0, ..., argtype_n x_n) throws thrown {
 *      super(x_0, ..., x_n)
 *    }
 *
 *  or, if based == true:
 *
 *    c(argtype_0 x_0, ..., argtype_n x_n) throws thrown {
 *      x_0.super(x_1, ..., x_n)
 *    }
 *
 *  @param make     The tree factory.
 *  @param c        The class owning the default constructor.
 *  @param argtypes The parameter types of the constructor.
 *  @param thrown   The thrown exceptions of the constructor.
 *  @param based    Is first parameter a this$n?
 */
JCTree DefaultConstructor(TreeMaker make,
                        ClassSymbol c,
                        List<Type> typarams,
                        List<Type> argtypes,
                        List<Type> thrown,
                        long flags,
                        boolean based) {
    List<JCVariableDecl> params = make.Params(argtypes, syms.noSymbol);
    List<JCStatement> stats = List.nil();
    if (c.type != syms.objectType)
        stats = stats.prepend(SuperCall(make, typarams, params, based));
    if ((c.flags() & ENUM) != 0 &&
        (types.supertype(c.type).tsym == syms.enumSym ||
         target.compilerBootstrap(c))) {
        // constructors of true enums are private
        flags = (flags & ~AccessFlags) | PRIVATE | GENERATEDCONSTR;
    } else
        flags |= (c.flags() & AccessFlags) | GENERATEDCONSTR;
    if (c.name.len == 0) flags |= ANONCONSTR;
    JCTree result = make.MethodDef(
        make.Modifiers(flags),
        names.init,
        null,
        make.TypeParams(typarams),
        params,
        make.Types(thrown),
        make.Block(0, stats),
        null);
    return result;
}

正是其中的 flags |= (c.flags() & AccessFlags) | GENERATEDCONSTR; 这句实现了默认构造器的可访问性与类的可访问性挂钩。c.flags()返回的long是一组标识位,其中包含了可访问性修饰符的记录。
11
1
分享到:
评论
4 楼 ZangXT 2010-02-23  
的一本书,好像叫深入cpp对象模型,则花了很多篇幅讲述了产生默认构造函数的意义.
mxswl 写道
受益了.
这篇文章讲述了在编译阶段javac何时帮你拼凑constructor.
以前看过的一本书,好像叫深入cpp对象模型,则花了很多篇幅讲述了产生默认构造函数的意义.

cpp太麻烦,啥时候生成,啥时候不生成……
java起码编译层保持个一致性
3 楼 mxswl 2010-02-23  
受益了.
这篇文章讲述了在编译阶段javac何时帮你拼凑constructor.
以前看过的一本书,好像叫深入cpp对象模型,则花了很多篇幅讲述了产生默认构造函数的意义.
2 楼 RednaxelaFX 2010-02-23  
zhxing 写道
说实话,没怎么看明白你。。可能功力不够深。。
最近也在看深入Java 虚拟机,大概意思是,Java 编译器为它编译的每一个类至少生成一个实例初始化方法(也就是构造方法),如果没有显示声明的任何构造方法的话,会默认生成一个无参数的构造方法,如果一个类没有显示调用另外一个构造方法的话,会自动生成一个超类的无参数的构造方法的调用。
在P168 页上有说明。但未说明它的访问权限。

我这里是写得很简略……文中提到的官方文档对javac编译器的编译步骤描述的详细些,可以先阅读那个作为背景。

《深入Java虚拟机》第二版的第7章确实提到了构造器而没有提到可访问性的问题。本来这就是Java语言中的定义而不是JVM的定义,在这么一本书里没做全面的描述也是可以理解的。上面我已经引用了Java语言规范中相应的规定及其链接,读读规范会有更清晰的理解的。

我这篇东西只是作为ZangXT同学的那帖的补充,将规范中的定义与编译器中实现该特性的地方指出来而已。具体有什么不明白的地方我们也可以展开来讨论一下 ^_^
1 楼 zhxing 2010-02-23  
说实话,没怎么看明白你。。可能功力不够深。。
最近也在看深入Java 虚拟机,大概意思是,Java 编译器为它编译的每一个类至少生成一个实例初始化方法(也就是构造方法),如果没有显示声明的任何构造方法的话,会默认生成一个无参数的构造方法,如果一个类没有显示调用另外一个构造方法的话,会自动生成一个超类的无参数的构造方法的调用。
在P168 页上有说明。但未说明它的访问权限。

相关推荐

    基于智能温度监测系统设计.doc

    基于智能温度监测系统设计.doc

    搜广推推荐系统中传统推荐系统方法思维导图整理-完整版

    包括userCF,itemCF,MF,LR,POLY2,FM,FFM,GBDT+LR,阿里LS-PLM 基于深度学习推荐系统(王喆)

    2023-04-06-项目笔记 - 第三百五十五阶段 - 4.4.2.353全局变量的作用域-353 -2025.12.22

    2023-04-06-项目笔记-第三百五十五阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.353局变量的作用域_353- 2024-12-22

    和美乡村城乡融合发展数字化解决方案.docx

    和美乡村城乡融合发展数字化解决方案.docx

    CNN基于Python的深度学习图像识别系统

    基于Python的深度学习图像识别系统是一个利用卷积神经网络(CNN)对图像进行分类的先进项目。该项目使用Python的深度学习库,如TensorFlow,构建和训练一个模型,能够自动识别和分类图像中的对象。系统特别适合于图像处理领域的研究和实践,如计算机视觉、自动驾驶、医疗影像分析等。 项目的核心功能包括数据预处理、模型构建、训练、评估和预测。用户可以上传自己的图像或使用预定义的数据集进行训练。系统提供了一个直观的界面,允许用户监控训练进度,并可视化模型的性能。此外,系统还包括了一个模型优化模块,通过调整超参数和网络结构来提高识别准确率。 技术层面上,该项目使用了Python编程语言,并集成了多个流行的机器学习库,如NumPy、Pandas、Matplotlib等,用于数据处理和可视化。模型训练过程中,系统会保存训练好的权重,以便后续进行模型评估和预测。用户可以通过简单的API调用,将新的图像输入到训练好的模型中,获取预测结果。

    拳皇97.exe拳皇972.exe拳皇973.exe

    拳皇97.exe拳皇972.exe拳皇973.exe

    基于python和协同过滤算法的电影推荐系统

    基于python和协同过滤算法的电影推荐系统 基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法

    DEV-CPP-RED-PANDA

    DEV-CPP-RED-PANDA

    Python语言求解旅行商(TSP)问题,算法包括禁忌搜索、蚁群算法、模拟退火算法等

    Python语言求解旅行商问题,算法包括禁忌搜索、蚁群算法、模拟退火算法等。

    pdfjs2.5.207和4.9.155

    pdfjs 用于在浏览器中查看/预览/打印pdf。 pdfjs 2.5.207 支持firefox/chrome/edge/ie11以上版本。 如果需要支持旧版本浏览器,可以使用这个,是未修改过的原版,支持打印和下载按钮。亲测有效。 pdf 4.9.155分两个包: pdfjs-4.9.155-dist.zip pdfjs-4.9.155-legacy-dist.zip

    建设项目现场高温人员中暑事故应急预案.docx

    建设项目现场高温人员中暑事故应急预案

    数据结构上机实验大作业-线性表选题.zip

    数据结构上机实验大作业-线性表选题.zip

    基于高德地图的校园导航全部资料+详细文档+高分项目.zip

    【资源说明】 基于高德地图的校园导航全部资料+详细文档+高分项目.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    全自动批量建站快速养权重站系统【纯静态html站群版】:(GPT4.0自动根据关键词写文章+自动发布+自定义友链+自动文章内链+20%页面加提权词)

    【静态站群程序视频演示,只有视频,不含程序,下载须知】【静态站群程序视频演示,只有视频,不含程序,下载须知】全自动批量建站快速养权重站系统【纯静态html站群版】:(GPT4.0自动根据关键词写文章+自动发布+自定义友链+自动文章内链+20%页面加提权词)

    9.30 SWKJ 男头7张+女头2张.zip

    9.30 SWKJ 男头7张+女头2张.zip

    基于java+springboot+vue+mysql的技术交流和分享平台 源码+数据库+论文(高分毕业设计).zip

    项目已获导师指导并通过的高分毕业设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 项目都经过严格调试,确保可以运行!可以放心下载 技术组成 语言:java 开发环境:idea、vscode 数据库:MySql5.7以上 部署环境:maven 数据库工具:navicat

    一个通过单片机在各种屏幕上显示中文的解决方案.7z

    一个通过单片机在各种屏幕上显示中文的解决方案.7z

    Halcon模板匹配图像包

    图像

    线上辅导班系统-JAVA-基于springboot的线上辅导班系统的开发与设计(毕业论文)

    一、用户管理功能 用户注册与登录 学生注册:学生可以通过手机号、邮箱、社交账号等方式注册,填写个人信息(如姓名、年龄、学校等)。 家长/监护人账户:支持家长/监护人注册并管理学生账户,查看学习进度和成绩。 教师账户:教师可以注册并设置个人资料,上传资质认证文件。 管理员账户:管理员负责整个系统的管理,包括用户管理、课程管理、平台设置等。 用户权限管理 角色权限:系统根据用户类型(学生、家长、教师、管理员)分配不同权限,确保信息安全。 家长监督:家长可以查看子女的学习进度、成绩和教师反馈,参与学习监督。 个人资料管理 用户可以在个人中心更新基本信息,设置个人头像、联系方式、密码等。 支持学籍信息的维护,例如学生的年级、班级、课程历史等。 二、课程管理功能 课程设置 课程创建与编辑:教师或管理员可以创建和编辑课程内容,上传课件、视频、文档等教学材料。 课程分类:根据学科、年级、难度等维度进行课程分类,方便学生浏览和选择。 课程排课:管理员可以设置课程的时间表、教学内容和授课教师,并调整上课时间和频率。 课程安排与通知 课程预约:学生可以在线选择并预约感兴趣的课程,系统根据学生的时

    英特尔2021-2024年网络连接性和IPU路线图

    内容概要:本文档介绍了英特尔2021年至2024年的网络连接性产品和智能处理单元(IPU)的战略和技术路线图。涵盖了从10GbE到200GbE的不同系列以太网适配器的特性、性能和发布时间。详细列出了各个产品的关键功能,如PCIe接口、安全特性、RDMA支持等。同时,介绍了IPU的发展计划,包括200G、400G和800G的不同代次产品的性能提升和新的功能特点。 适合人群:从事网络工程、数据中心管理、IT架构设计的专业技术人员。 使用场景及目标:本文档主要用于了解英特尔未来几年在以太网适配器和IPU领域的技术和产品规划,帮助企业在采购和部署网络设备时做出决策。同时,为研究人员提供最新技术发展趋势的参考。 其他说明:文档内容涉及的技术细节和时间表可能会有变动,请以英特尔官方发布的最新信息为准。

Global site tag (gtag.js) - Google Analytics