解析 Java 类和对象的初始化过程
- 中国
- [ 选择 ]
dW 全部内容-------------- AIX and UNIX Info Mgmt Lotus Rational WebSphere-------------- Java technology Linux Open source SOA & Web services Web dev XML--------------IBM 全部内容
- 首页
- 解决方案
- 按行业分类
- 银行
- 保险业
- 零售业
- 制造业
- 电子
- 电信
- 媒体与娱乐业
- 交通运输
- 航空航天
- 汽车制造
- 石油石化
- 政府与公众事业
- 教育
- 医疗与生命科学
- 按业务需求分类
- IT 基础架构解决方案
- 商务智能(BI)
- 供应链管理(SCM)
- 企业资源规划(ERP)
- 客户关系管理(CRM)
- 产品生命周期管理(PLM)
- 办公自动化(OA)
- 企业资产管理(EAM)
- 内容管理
- 信息集成
- 按顶级业务合作伙伴分类
- IBM 和 Cisco
- IBM 与 SAP
- 业务咨询
- IBM 动态架构
- IBM智慧运作
- IBM新锐洞察
- IBM智慧产品与服务
- 面向服务架构 (SOA)
- 融资租赁
- 面向中型企业及机构的解决方案
- 软件行业解决方案
- IBM 区域解决方案
- 更多业务解决方案
- 按行业分类
- 服务
- 按服务项目分类
- 弹性运维服务
- 业务连续与灾难恢复服务
- 企业终端用户服务
- 网络服务
- IT 策略与基础架构服务
- 维护与技术支持服务
- 中间件服务
- 外包服务
- 企业 IT 安全服务
- 服务器服务
- 数据中心及智能化集成服务
- 数据与存储服务
- 按业务类型分类
- 竞争策略
- 营运/委外
- 顾客服务及忠诚度
- 通路策略实施
- IT 最适化
- 全新的工作环境
- 灵活可靠的基础建设
- 安全和防御
- 价值链效益
- 按行业分类
- 跨行业
- 金融业
- 银行业
- 保险业
- 零售业
- 消费品
- 批发业
- 电子业
- 电信业
- 媒体与娱乐
- 旅游和运输业
- 汽车行业
- 石油石化行业
- 政府部门
- 能源与公用事业
- 教育业
- 医疗保健
- 生命科学
- 培训服务
- 软件服务
- 面向中型企业及机构的服务
- 更多服务
- 按服务项目分类
- 产品
- 特惠产品和方案
- 软件
- 所有软件
- 产品目录
- Information Management 信息管理软件
- Lotus 协作办公软件
- Rational 开发软件
- Tivoli 服务管理软件
- WebSphere 应用系统和整合软件
- System z 服务器软件
- Systems 与服务器
- 所有 IBM Systems 和服务器
- Power Systems
- System i (i系列)服务器
- System p (p系列)服务器
- System x (x系列)服务器
- System z (z系列)服务器
- BladeCenter 刀片服务器
- OpenPower 服务器
- 群集服务器
- UNIX 服务器
- Linux 服务器
- POWER 处理器的服务器
- 基于英特尔架构的服务器
- 存储产品
- 所有存储产品
- 磁盘存储系统
- 磁带存储系统
- 存储区域网络
- 网络连接存储
- 存储软件
- 存储产品排序(A - Z)
- 网络安全
- 零售终端
- 打印机 (InfoPrint)
- IBM 官方认证再制造设备
- 选件
- 中低端产品特惠商城
- 面向中型企业及机构的特惠产品
- 支持与下载
- 下载
- 驱动程序和软件下载
- 故障诊断与排除
- 搜索
- 按产品查看
- 软件产品
- 存储产品
- 打印机 (InfoPrint)
- 个性化支持
- 产品资料中心
- 电子化工具
- 提交服务请求
- 专项服务
- 技术知识库
- 在线客户支持
- 保修、许可和维护
- 下载
- 个性化服务
- 我的账户
- 我的收藏夹
- 我的概要信息
- 客户支持
- 合同
- 订单与发货
- 库存与维护
- 发票与付款
- 更多客户支持
- 了解更多
- developerWorks 中国
- Java technology
- 文档库
解析 Java 类和对象的初始化过程
由一个单态模式引出的问题谈起
简介:
类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来分析的文章更是鲜有所见。
本文主要对类和对象初始化全过程进行分析,通过一个实际问题引入,将源代码转换成 JVM 字节码后,对 JVM 执行过程的关键点进行全面解析,并在文中穿插入了相关 JVM 规范和 JVM 的部分内部理论知识,以理论与实际结合的方式介绍对象初始化和类初始化之间的协作以及可能存在的冲突问题。
发布日期: 2006 年 8 月 31 日
级别: 初级
访问情况 1146 次浏览
建议: 1 (查看或添加评论)
问题引入
近日我在调试一个枚举类型的解析器程序,该解析器是将数据库内一万多条枚举代码装载到缓存中,为了实现快速定位枚举代码和具体枚举类别的所有枚举元素,该类在装载枚举代码的同时对其采取两种策略建立内存索引。由于该类是一个公共服务类,在程序各个层面都会使用到它,因此我将它实现为一个单例类。这个类在我调整类实例化语句位置之前运行正常,但当我把该类实例化语句调整到静态初始化语句之前时,我的程序不再为我工作了。
下面是经过我简化后的示例代码:
[清单一]
package com.ccb.framework.enums;import java.util.Collections;import java.util.HashMap;import java.util.Map;public class CachingEnumResolver { //单态实例 一切问题皆由此行引起 private static final CachingEnumResolver SINGLE_ENUM_RESOLVER = new CachingEnumResolver(); /*MSGCODE->Category内存索引*/ private static Map CODE_MAP_CACHE; static { CODE_MAP_CACHE = new HashMap(); //为了说明问题,我在这里初始化一条数据 CODE_MAP_CACHE.put("0","北京市"); } //private, for single instance private CachingEnumResolver() { //初始化加载数据 引起问题,该方法也要负点责任 initEnums(); } /** * 初始化所有的枚举类型 */ public static void initEnums() { // ~~~~~~~~~问题从这里开始暴露 ~~~~~~~~~~~// if (null == CODE_MAP_CACHE) { System.out.println("CODE_MAP_CACHE为空,问题在这里开始暴露."); CODE_MAP_CACHE = new HashMap(); } CODE_MAP_CACHE.put("1", "北京市"); CODE_MAP_CACHE.put("2", "云南省"); //..... other code... } public Map getCache() { return Collections.unmodifiableMap(CODE_MAP_CACHE); } /** * 获取单态实例 * * @return */ public static CachingEnumResolver getInstance() { return SINGLE_ENUM_RESOLVER; } public static void main(String[] args) { System.out.println(CachingEnumResolver.getInstance().getCache()); }} |
想必大家看了上面的代码后会感觉有些茫然,这个类看起来没有问题啊,这的确属于典型的饿汉式单态模式啊,怎么会有问题呢?
是的,他看起来的确没有问题,可是如果将他 run 起来时,其结果是他不会为你正确 work。运行该类,它的执行结果是:
[清单二]
CODE_MAP_CACHE为空,问题在这里开始暴露.{0=北京市} |
我的程序怎么会这样?为什么在 initEnum() 方法里 CODE_MAP_CACHE 为空?为什么我输出的 CODE_MAP_CACHE 内容只有一个元素,其它两个元素呢????!!
看到这里,如果是你在调试该程序,你此刻一定觉得很奇怪,难道是我的 Jvm 有问题吗?非也!如果不是,那我的程序是怎么了?这绝对不是我想要的结果。可事实上无论怎么修改 initEnum() 方法都无济于事,起码我最初是一定不会怀疑到问题可能出在创建 CachingEnumResolver 实例这一环节上。正是因为我太相信我创建 CachingEnumResolver 实例的方法,加之对 Java 类初始化与对象实例化底层原理理解有所偏差,使我为此付出了三、四个小时--约半个工作日的大好青春。
那么问题究竟出在哪里呢?为什么会出现这样的怪事呢?在解决这个问题之前,先让我们来了解一下JVM的类和对象初始化的底层机制。
回页首
类的生命周期
上图展示的是类生命周期流向;在本文里,我只打算谈谈类的"初始化"以及"对象实例化"两个阶段。
回页首
类初始化
类"初始化"阶段,它是一个类或接口被首次使用的前阶段中的最后一项工作,本阶段负责为类变量赋予正确的初始值。
Java 编译器把所有的类变量初始化语句和类型的静态初始化器通通收集到 <clinit> 方法内,该方法只能被 Jvm 调用,专门承担初始化工作。
除接口以外,初始化一个类之前必须保证其直接超类已被初始化,并且该初始化过程是由 Jvm 保证线程安全的。另外,并非所有的类都会拥有一个 <clinit>() 方法,在以下条件中该类不会拥有 <clinit>() 方法:
- 该类既没有声明任何类变量,也没有静态初始化语句;
- 该类声明了类变量,但没有明确使用类变量初始化语句或静态初始化语句初始化;
- 该类仅包含静态 final 变量的类变量初始化语句,并且类变量初始化语句是编译时常量表达式。
回页首
对象初始化
在类被装载、连接和初始化,这个类就随时都可能使用了。对象实例化和初始化是就是对象生命的起始阶段的活动,在这里我们主要讨论对象的初始化工作的相关特点。
Java 编译器在编译每个类时都会为该类至少生成一个实例初始化方法--即 "<init>()" 方法。此方法与源代码中的每个构造方法相对应,如果类没有明确地声明任何构造方法,编译器则为该类生成一个默认的无参构造方法,这个默认的构造器仅仅调用父类的无参构造器,与此同时也会生成一个与默认构造方法对应的 "<init>()" 方法.
通常来说,<init>() 方法内包括的代码内容大概为:调用另一个 <init>() 方法;对实例变量初始化;与其对应的构造方法内的代码。
如果构造方法是明确地从调用同一个类中的另一个构造方法开始,那它对应的 <init>() 方法体内包括的内容为:一个对本类的 <init>() 方法的调用;对应用构造方法内的所有字节码。
如果构造方法不是通过调用自身类的其它构造方法开始,并且该对象不是 Object 对象,那 <init>() 法内则包括的内容为:一个对父类 <init>() 方法的调用;对实例变量初始化方法的字节码;最后是对应构造子的方法体字节码。
如果这个类是 Object,那么它的 <init>() 方法则不包括对父类 <init>() 方法的调用。
回页首
类的初始化时机
本文到目前为止,我们已经大概有了解到了类生命周期中都经历了哪些阶段,但这个类的生命周期的开始阶段--类装载又是在什么时候被触发呢?类又是何时被初始化的呢?让我们带着这三个疑问继续去寻找答案。
Java 虚拟机规范为类的初始化时机做了严格定义:"initialize on first active use"--" 在首次主动使用时初始化"。这个规则直接影响着类装载、连接和初始化类的机制--因为在类型被初始化之前它必须已经被连接,然而在连接之前又必须保证它已经被装载了。
在与初始化时机相关的类装载时机问题上,Java 虚拟机规范并没有对其做严格的定义,这就使得 JVM 在实现上可以根据自己的特点提供采用不同的装载策略。我们可以思考一下 Jboss AOP 框架的实现原理,它就是在对你的 class 文件装载环节做了手脚--插入了 AOP 的相关拦截字节码,这使得它可以对程序员做到完全透明化,哪怕你用 new 操作符创建出的对象实例也一样能被 AOP 框架拦截--与之相对应的 Spring AOP,你必须通过他的 BeanFactory 获得被 AOP 代理过的受管对象,当然 Jboss AOP 的缺点也很明显--他是和 JBOSS 服务器绑定很紧密的,你不能很轻松的移植到其它服务器上。嗯~……,说到这里有些跑题了,要知道 AOP 实现策略足可以写一本厚厚的书了,嘿嘿,就此打住。
说了这么多,类的初始化时机就是在"在首次主动使用时",那么,哪些情形下才符合首次主动使用的要求呢?
首次主动使用的情形:
- 创建某个类的新实例时--new、反射、克隆或反序列化;
- 调用某个类的静态方法时;
- 使用某个类或接口的静态字段或对该字段赋值时(final字段除外);
- 调用Java的某些反射方法时
- 初始化某个类的子类时
- 在虚拟机启动时某个含有main()方法的那个启动类。
除了以上几种情形以外,所有其它使用JAVA类型的方式都是被动使用的,他们不会导致类的初始化。
回页首
我的问题究竟出在哪里
好了,了解了JVM的类初始化与对象初始化机制后,我们就有了理论基础,也就可以理性的去分析问题了。
下面让我们来看看前面[清单一]的JAVA源代码反组译出的字节码:
[清单三]
public class com.ccb.framework.enums.CachingEnumResolver extendsjava.lang.Object{static {}; Code: 0: new #2; //class CachingEnumResolver 3: dup 4: invokespecial #14; //Method "<init>":()V ① 7: putstatic #16; //Field SINGLE_ENUM_RESOLVER:Lcom/ccb/framework/enums/CachingEnumResolver; 10: new #18; //class HashMap ② 13: dup 14: invokespecial #19; //Method java/util/HashMap."<init>":()V 17: putstatic #21; //Field CODE_MAP_CACHE:Ljava/util/Map; 20: getstatic #21; //Field CODE_MAP_CACHE:Ljava/util/Map; 23: ldc #23; //String 0 25: ldc #25; //String 北京市 27: invokeinterface #31, 3; //InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; ③ 32: pop 33: returnprivate com.ccb.framework.enums.CachingEnumResolver(); Code: 0: aload_0 1: invokespecial #34; //Method java/lang/Object."<init>":()V 4: invokestatic #37; //Method initEnums:()V ④ 7: returnpublic static void initEnums(); Code: 0: getstatic #21; //Field CODE_MAP_CACHE:Ljava/util/Map; ⑤ 3: ifnonnull 24 6: getstatic #44; //Field java/lang/System.out:Ljava/io/PrintStream; 9: ldc #46; //String CODE_MAP_CACHE为空,问题在这里开始暴露. 11: invokevirtual #52; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 14: new #18; //class HashMap 17: dup 18: invokespecial #19; //Method java/util/HashMap."<init>":()V ⑥ 21: putstatic #21; //Field CODE_MAP_CACHE:Ljava/util/Map; 24: getstatic #21; //Field CODE_MAP_CACHE:Ljava/util/Map; 27: ldc #54; //String 1 29: ldc #25; //String 北京市 31: invokeinterface #31, 3; //InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; ⑦ 36: pop 37: getstatic #21; //Field CODE_MAP_CACHE:Ljava/util/Map; 40: ldc #56; //String 2 42: ldc #58; //String 云南省 44: invokeinterface #31, 3; //InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; ⑧ 49: pop 50: returnpublic java.util.Map getCache(); Code: 0: getstatic #21; //Field CODE_MAP_CACHE:Ljava/util/Map; 3: invokestatic #66; //Method java/util/Collections.unmodifiableMap:(Ljava/util/Map;)Ljava/util/Map; 6: areturnpublic static com.ccb.framework.enums.CachingEnumResolver getInstance(); Code: 0: getstatic #16; //Field SINGLE_ENUM_RESOLVER:Lcom/ccb/framework/enums/CachingEnumResolver; ⑨ 3: areturn} |
如果上面[清单一]显示,清单内容是在 JDK1.4 环境下的字节码内容,可能这份清单对于很大部分兄弟来说确实没有多少吸引力,因为这些 JVM 指令确实不像源代码那样漂亮易懂。但它的的确确是查找和定位问题最直接的办法,我们想要的答案就在这份 JVM 指令清单里。
现在,让我们对该类从类初始化到对象实例初始化全过程分析[清单一]中的代码执行轨迹。
如前面所述,类初始化是在类真正可用时的最后一项前阶工作,该阶段负责对所有类正确的初始化值,此项工作是线程安全的,JVM会保证多线程同步。
第1步:调用类初始化方法 CachingEnumResolver.<clinit>(),该方法对外界是不可见的,换句话说是 JVM 内部专用方法,<clinit>() 内包括了 CachingEnumResolver 内所有的具有指定初始值的类变量的初始化语句。要注意的是并非每个类都具有该方法,具体的内容在前面已有叙述。
第2步:进入 <clinit>() 方法内,让我们看字节码中的 "①" 行,该行与其上面两行组合起来代表 new 一个 CachingEnumResolver 对象实例,而该代码行本身是指调用 CachingEnumResolver 类的 <init>()方法。每一个 Java 类都具有一个 <init>() 方法,该方法是 Java 编译器在编译时生成的,对外界不可见,<init>() 方法内包括了所有具有指定初始化值的实例变量初始化语句和java类的构造方法内的所有语句。对象在实例化时,均通过该方法进行初始化。然而到此步,一个潜在的问题已经在此埋伏好,就等着你来犯了。
第3步:让我们顺着执行顺序向下看,"④" 行,该行所在方法就是该类的构造器,该方法先调用父类的构造器 <init>() 对父对象进行初始化,然后调用 CachingEnumResolver.initEnum() 方法加载数据。
第4步:"⑤" 行,该行获取 "CODE_MAP_CACHE" 字段值,其运行时该字段值为 null。注意,问题已经开始显现了。(作为程序员的你一定是希望该字段已经被初始化过了,而事实上它还没有被初始化)。通过判断,由于该字段为 NULL,因此程序将继续执行到 "⑥" 行,将该字段实例化为 HashMap()。
第5步:在 "⑦"、"⑧" 行,其功能就是为 "CODE_MAP_CACHE" 字段填入两条数据。
第6步:退出对象初始化方法 <init>(),将生成的对象实例初始化给类字段 "SINGLE_ENUM_RESOLVER"。(注意,此刻该对象实例内的类变量还未初始化完全,刚才由 <init>() 调用 initEnum() 方法赋值的类变量 "CODE_MAP_CACHE" 是 <clinit>() 方法还未初始化字段,它还将在后面的类初始化过程再次被覆盖)。
第7步:继续执行 <clinit>()方法内的后继代码,"②" 行,该行对 "CODE_MAP_CACHE" 字段实例化为 HashMap 实例(注意:在对象实例化时已经对该字段赋值过了,现在又重新赋值为另一个实例,此刻,"CODE_MAP_CACHE"变量所引用的实例的类变量值被覆盖,到此我们的疑问已经有了答案)。
第8步:类初始化完毕,同时该单态类的实例化工作也完成。
通过对上面的字节码执行过程分析,或许你已经清楚了解到导致错误的深层原因了,也或许你可能早已被上面的分析过程给弄得晕头转向了,不过也没折,虽然我也可以从源代码的角度来阐述问题,但这样不够深度,同时也会有仅为个人观点、不足可信之嫌。
回页首
如何解决
要解决上面代码所存在的问题很简单,那就是将 "SINGLE_ENUM_RESOLVER" 变量的初始化赋值语句转移到 getInstance() 方法中去即可。换句话说就是要避免在类还未初始化完成时从内部实例化该类或在初始化过程中引用还未初始化的字段。
回页首
写在最后
静下浮燥之心,仔细思量自己是否真的掌握了本文主题所引出的知识,如果您觉得您已经完全或基本掌握了,那么很好,在最后,我将前面的代码稍做下修改,请思考下面两组程序是否同样会存在问题呢?
程序一
public class CachingEnumResolver { public static Map CODE_MAP_CACHE; static { CODE_MAP_CACHE = new HashMap(); //为了说明问题,我在这里初始化一条数据 CODE_MAP_CACHE.put("0","北京市"); initEnums(); } |
程序二
public class CachingEnumResolver { private static final CachingEnumResolver SINGLE_ENUM_RESOLVER; public static Map CODE_MAP_CACHE; static { CODE_MAP_CACHE = new HashMap(); //为了说明问题,我在这里初始化一条数据 CODE_MAP_CACHE.put("0","北京市"); SINGLE_ENUM_RESOLVER = new CachingEnumResolver(); initEnums(); } |
最后,一点关于 JAVA 群体的感言:时下正是各种开源框架盛行时期,Spring 更是大行其道,吸引着一大批 JEE 开发者的眼球(我也是 fans 中的一员)。然而,让我们仔细观察一下--以 Spring 群体为例,在那么多的 Spring fans 当中,有多少人去研究过 Spring 源代码?又有多少人对 Spring 设计思想有真正深入了解呢?当然,我是没有资格以这样的口吻来说事的,我只是想表明一个观点--学东西一定要"正本清源"。
献上此文,谨以共勉。
关于作者
北京高伟达西南分软 Java EE 软件工程师,三年 Java EE 项目经验,行业方向为银行 OCRM 系统。对 JAVA 有着浓厚的兴趣,业余研究 AOP/ESB 方向。
建议
1 条评论 | 登录添加评论举报不良信息
添加评论
标有星号(*)的是必填项目。
评论:*
非常敬佩楼主这种刨根揭底的精神,在楼主这里学到了很多。关于类初始化,关键是理解类初始化顺序问题,这个问题搞明白了,关于楼主的CachingEnumResolver问题,也就很容易理解。 |
由 freshmanInJava 于 14 11 2010 |
显示最新的 5 条评论 | 显示后 5 条评论 | 显示所有评论
登录添加评论
回页首
商标 | My developerWorks 使用条款与条件
内容
- 问题引入
- 类的生命周期
- 类初始化
- 对象初始化
- 类的初始化时机
- 我的问题究竟出在哪里
- 如何解决
- 写在最后
- 关于作者
- 建议
标签
使用 滑动条 调节标签的数量。
热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。
我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。
搜索所有标签
热门文章标签 |
我的文章标签跳转到标签列表
热门文章标签 |
我的文章标签
跳转到标签列表
- 关于IBM
- 隐私条约
- 联系IBM
- 使用条款
- IBM RSS 可定制阅读服务
- 求才启事
转载于:https://www.cnblogs.com/leaveaisun/archive/2011/01/11/1933339.html
解析 Java 类和对象的初始化过程相关推荐
- 解析 Java 类和对象的初始化过程 由一个单态模式引出的问题谈起
在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 问题引入 近日我在调试一个枚举类型的解析器程序,该解析器是将数据库内一万多条枚举代码装载到缓存中,为了实现快速定位枚举代码 ...
- 解析 Java 类和对象的初始化过程(zhuang张 国建 (guojian.zhang@gmail
[url]http://www.blogjava.net/rendong/default.html?page=2[/url]
- 从Java类到对象的创建过程都做了些啥?内存中的对象是啥样的?
转载自 从Java类到对象的创建过程都做了些啥?内存中的对象是啥样的? 先回顾一下Java程序执行的过程: Java程序执行时,第一步系统创建虚拟机进程,然后虚拟器用类加载器Class Loade ...
- Java类和对象的初始化顺序
本文摘录于http://blog.csdn.net/socoolfj/archive/2006/05/23/750425.aspx,并修改例子的代码,加上自己的见解. 类装载步骤 在Java中,类装载 ...
- 杨校老师课堂之Java类与对象、封装、构造方法
杨校老师课堂之Java类与对象.封装.构造方法 本篇文章内容如下: 面向对象 类与对象 三大特征--封装 构造方法 教学目标 能够理解面向对象的思想 能够明确类与对象关系 能够掌握类的定义格式 能够掌 ...
- java类和对象在内存的表现形式
Java内存分配与管理是Java的核心技术之一,不管学习任何一门语言,我们要知其然,知其所以然,本文主要分析下Java中类和对象在内存中的表现形式,方便我们对其有更深了解.一般Java在内存分配时会涉 ...
- Java 面向对象与对象的创建过程及变量
Java 面向对象与对象的创建过程及变量: 1.面向对象和面向过程的思想对比 : 面向过程 :是一种以过程为中心的编程思想,实现功能的每一步,都是自己实现的 面向对象 :是一种以对象为中心的编 ...
- JAVA类和对象(1)
JAVA类和对象 1.类和对象的初步认识 2.类的实例化 3.类的成员 3.1 字段/属性/成员变量 3.2 null 3.3 引用的指向 3.3 方法 (method) 3.4 static关键字 ...
- java 类与对象、封装、构造方法
java 类与对象.封装.构造方法 面向对象 类与对象 三大特征--封装 构造方法 第1章 面向对象思想 1.1 面向对象思想概述 概述 Java语言是一种面向对象的程序设计语言,而面向对象思想是一种 ...
最新文章
- LinearLayout、RelativeLayout、FrameLayout居中显示
- XDP/eBPF — BPF
- OpenLayers 3 之 地图样式(ol.style)详解
- VTK:Math之MatrixInverse
- mac找不到mysql_mac找不到mysql
- 配置Tomcat的server.xml以适应web-content文件系统的位置改变
- POI--HSSFCellStyle类
- Azkaban的Web Server源码探究系列22: 一次性执行execute的提交准备
- spring 获取一个包下的所有bean_面试官问我:为什么 Spring 中的 bean 默认为单例?...
- c++ 代码_C|函数调用约定与堆栈平衡的汇编代码分析
- Python实现照片更换背景色
- Spring Boot 监听 Activemq 中的特定 topic ,并将数据通过 RabbitMq 发布出去
- 基于Springboot+mybatis+mysql+html实现CRM智能办公系统
- 2019年安徽省大数据与人工智能应用赛总结---本科组
- 使用kermit串口工具时出现 /dev/ttyS0 is not a terminal device 错误
- 程序员薪酬榜来了!这9类程序员上榜:AI第1 全栈第3,你排第几?
- React类式组件基础内容补充
- 10分钟带你彻底搞懂微内核架构
- 信号与系统——基本概念
- 【网课必备】学浪视频下载方法
热门文章
- JAVA打字小游戏,面向对象完成
- 用计算机怎么求锐角三角函数值,用计算器求锐角三角函数值与由锐角三角函数值求锐角.doc...
- 图像细节增强(直方图均衡化,对数变换,Gamma变换(校正))
- 前端小demo_day02_聚光灯(CSS)实现
- html写樱花场景的程序,描写樱花的优美语句,樱花飘落的场景描写
- 我在金蝶用户年会上的讲话
- wallpaper engine怎么用?
- FFMPEG录屏(3)----捕获系统声音和麦克风
- Java基础学习生疏知识点总结(4)——面向对象、单一职责原则、this关键字、构造方法
- win7关闭计算机控制器,win7自动关机设置方法 win7自动关机怎么取消的详细操作技巧...