1、类与类之间的关系 一、继承关系 继承指的是一个类(称为子类、子接口)继承另外的一 个类(称为父类、父 接口)的功能,并可以增加它自己的新功能的能力。 二 、实现关系 实现指的是一个 class 类实现 interface 接口(可以是多 个)的功能,实现是 类与接口之间最常见的关系。 三 、依赖关系 简单的理解,依赖就是一个类 A 使用到了另一个类 B, 而这种使用关系是 具有偶然性的、临时性的、非常弱的,但是类 B 的变化 会影响到类 A。比如某 人要过河, 需要借用一条船, 此时人与船之间的关 系就是依赖。 表现在代码层面, 为类 B 作为参数被类 A 在某个 method 方 法中使用。 四、关联关系 关联体现的是两个类之间语义级别的一种强依赖关系, 比如我和我的朋友,这 种关系比依赖更强、不存在依赖关系的偶然性、关 系也不是临时性的,一般是长 期性的,而且双方的关系一般是平等的。关 联可以是单向、双向的。表现在代码 层面,为被关联类 B 以类的属性形式 出现在关联类 A 中,也可能是关联类 A 引用了一个类型为被关联类 B 的全 局变量。 五 、聚合关系 聚合是关联关系的一种特例,它体现的是整体与部分 的关系,即 has-a 的关 系。此时整体与部分之间是可分离的,它们可以具 有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象 共享。比如计算机与 CPU、公司与 员工的关系等,比如一个航母编队包括 海空母舰、驱护舰艇、舰载飞机及核动力 攻击潜艇等。表现在代码层面, 和关联关系是一致的,只能从语义级别来区分。 六 、组合关系 组合也是关联关系的一种特例,它体现的是一种 contains-a 的关系,这种关系比聚合更强,也称为强聚合。它同样体现整体 与部分间的关系,但此时整体与 部分是不可分的,整体的生命周期结束也 就意味着部分的生命周期结束,比如人 和人的大脑。表现在代码层面,和 关联关系是一致的,只能从语义级别来区分。 七、总结 对于继承、实现这两种关系没多少疑问,它们体现的是一种 类和类、或者类 与接口间的纵向关系。 其他的四种关系体现的是类和类、 或者类与接口间的引用、 横向关系,是比较难区分的,有很多事物间的关 系要想准确定位是很难的。前面也提到, 这四种关系都是语义级别的, 所 以从代码层面并不能完全区分各种关系, 但总的来说,后几种关系所表现 的强弱程度依次为:组合>聚合>关联>依赖。 2、java内存的分布 1. 寄存器 我们在程序中无法控制 2. 栈 存放基本类型的变量数据,局部变量,和对象的引用,但 对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中 (字符串常量对象存放在常量池中。) 3. 堆 存放用new产生的对象,数组。为了给垃圾回收器使用, 堆主要分成三个区域,分别叫作New Generation,Old Generation或叫 Tenured Generation,以及Perm space。New Generation是用来存放新建的 对象的空间,在对象新建的时候被使用。如果长时间还使用的话,它们会 被垃圾回收器移动到Old Generation(或叫Tenured Generation)。Permspace 是JVM存放Meta数据的地方,例如类,方法,字符串池和类级别的详细 信息。 4. 静态域 存放在对象中用static定义的静态成员 5. 常量池 存放字符串常量和基本类型常量(public static final)。 3、开发中我们主要关心栈,堆和常量池 栈: 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的 栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存 空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存 空间,该内存空间可以立即被另作他用。存取速度快,仅次于寄存器。 栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时, 这个数据就会消失 引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到 其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到 使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占 据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为 垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的 时间被垃圾回收器收走(释放掉)。这也是 Java 比较占内存的原因。 堆 : 需要运行时动态分配内存,因此存取速度慢 堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定, 具有很大的灵活性。 常量池 : 存放字符串常量和基本类型变量,比如String str1=”abc”; 实际上”abc”是 在常量池里边。 在程序执行的时候,常量池 会储存在Method Area,而不是堆中。 栈中数据的可共享性 int a = 3; int b = 3; 编译器先处理int a = 3;首先它会在栈中创建一 个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3 存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后, 因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b 同时均指向3的情况。这时,如果再令 a=4;那么编译器会重新搜索栈中 是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了, 则直接将a指向这个地址。因此a值的改变不会影响 到b的值。要注意这 种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的, 因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节 省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一 个对象引用变量。 对于基础类型的变量和常量:变量和引用存储在栈中 ,常 量存储在常量池中. |