JAVA整理

Java成长之路(七)

Posted by MiaoMiaoMiao on January 19, 2021

Java成长之路七

复用

如何在不污染代码的前提下使用现存代码;

  1. 直接了当;在新类中创建现有类类型的对象,这种方法叫做“组合”(composition),复用其功能而非形式;
  2. 创建现有类型的新类。(采用现有类形式,又无需在编码时改动其代码,这种方法叫做“继承”(Inheritance),编译器会做大部分工作,继承是面向编程重要基础之一)

组合语法

  • 只需要把对象的引用(object references)放置在一个新的类里,这就是组合;
  • 编译器不会为每个引用创建一个默认对象,这是有意义的。在许多情况下,会导致不必要的开销。

初始化引用的四种方法

  1. 当对象被定义时,这意味着它们总是在调用构造函数之前初始化;
  2. 在该类的构造函数中;
  3. 在实际使用对象之前。 =>延迟初始化,在对象创建开销大且不需要每次都创建对象的情况下,它可以减少开销;
  4. 使用实例初始化;

继承语法

  • 继承是所有面向对象语言的一个组成部分,事实证明创建类总是要继承的(Object);
  • 使用extends;
  • 如果不是用修饰符,成员默认包访问权限,只允许包内成员访问;
  • 所以为了继承,一般所有字段为私有,所有方法为公共;
  • 继承时,你不受限于使用基类的方法,你可以向类添加任何方法一样额派生类,添加新方法,只需定义它;

初始化基类

  • 当你创建派生类的对象时,它包含基类的子对象,这个子对象与你自己创建基类是一样的,只从外部看基类子对象被包装在派生类的对象中。
  • 必须正确初始化基类对象,而且只有一种方法可以保证这一点。通过调用基类构造函数中执行初始化。该构造函数具有执行基类初始化所需的所有适当信息和特权;Java自动在派生类构造函数中插入对基类构造函数的调用;
  • 构造基类“向外”进行,因此基类在派生类构造函数能够访问它之前进行初始化;

带参数的构造函数

  • 如果没有无参数的基本构造函数,或者必须调用具有参数的基类函数,则必须使用super关键字和适当的参数列表,显示地编写对基类构造函数的调用;
  • 对基类构造函数的调用必须是派生类构造函数中的第一个操作;

委托

  • 在Java中不直接支持的第三种重用关系为委托;这介于继承和组合之间。因为你将一个成员对象放在正在构建的类中,但同时又在新类公开来自成员对象的所有方法(比如继承)
  • 组合:组合就是A类的对象是B类的成员变量;(Has-a的关系)
  • 继承:一个类继承另外的一个类的功能,并可以新增自己的能力;(is-a的关系)

保证适当的清理

  • 通过在finally子句中放置类清理,防止异常;
  • 除了内存够回收之外,不能依赖垃圾收集未做任何事情。如果希望进行清理,可使用自己的清理方法,不是用finalize();

名称隐藏

  • 如果Java基类的方法多次重载,则派生类中重新定义该方法名不会隐藏任何版本;
  • 重写-覆盖同名方法,是用于基类中完全相同的方法签名(方法和参数类型的合称)和返回类型;

继承和组合的选择

  • 组合与继承都允许在心里诶放置子对象(组合是显式的,而继承是隐式的)
  • 当在新类中包含一个已有类的功能时,是用组合,而非继承。在新类中嵌入一个对象(通常是私有的),以实现其功能,使用者看到的是新类的接口,而非嵌入对象的接口。
  • 一种判断使用组合还是继承的最清晰的方法是问一问自己是否需要把新类向上转型为基类;如果必须向上转型,那么继承是必要的。但如果不需要,则要进一步考虑是否该采用继承;

protected

  • 要让一个事物对外界隐藏,而允许派生类的成员访问;
  • protected就类的用户而言,这是private的,但对于任何继承它的子类或在同一个包中的类,它是可访问的;

向上转型

  • 继承保证了基类的所有方法在派生类中也是可用的,所有任意发给该基类消息也发送给派生类;
  • 继承中派生类转型为基类是向上的,称之为向上转型,从一个更为具体的类转化成一个更一般的类;所以向上转型是安全的,派生类是基类的一个超集;
  • 向上转型接口只会失去方法,不会增加方法;

final关键字

final数据(有些数据是恒定不变的,恒定有用的)

  • 一个永不改变的编译时的常量;
  • 一个在运行时初始化就不会改变的值;
  • 在Java中,这类常量必须是基本类型,而且用关键字final修饰,必须在定义常量时赋值;
  • 一个被static和final同事修饰的属性,只会占用一段不能改变的存储空间;
  • final修饰对象引用而非基本类型时,其含义会有一点困惑,一旦引用被初始化指向某个对象,它不能改为指向其他对象,但是对象的含义本身就是可以修改的;

空白的final

  • 空白的final是没有初始化值的final属性,编译器必须保证空白final在使用前被初始化;
  • 你必须在定义时或每个构造器中执行final变量的赋值操作,保证final属性在使用前被初始化;

final参数

  • 在参数列表中,将参数声明为final意味着在方法中不能改变参数指向的对象成基本变量;
  • final基本类型参数,你只能读取不能修改参数,用于传递数据给匿名内部类;

final方法

  • 使用final方法的原因:a.给方法上锁,放置子类通过复写改变方法的行为,确保方法不会因为继承而改变;b.效率(过去),在最近的Java版本中,JVM可以得到(用方法体内实际代码的副本替代方法调用)并优化掉这些效率反而降低了内嵌调用方法;
  • 只有在为了明确禁止覆写方法时才使用finial;

final和private

  • 类中所有的private方法都隐式地指定为final,可以给private方法添加final修饰,但并不能给方法带来额外的含义;

final类

  • 当一个类是final,就意味着它不能被继承;
  • 当使用final目的就是永远不要改动或作出安全考虑,不希望其有子类;
  • final类禁止继承,类中的所有的方法都被隐式地指定为final,没办法覆写;

类初始化的加载

  • 一个类当它任意一个static成员被访问时,就会被加载;
  • 首次使用时就是static初始化发生时,所有的static对象和static代码块在加载时按照文本的顺序依次初始化;

继承的初始化

  • 首先对象中的所有基本类型变量都被置为默认值,对象引用被设为null——这是通过将对象内存设为二进制零值一举生成的。接着会调用基类的构造器,基类的构造器和派生类构造器一样以相同的经历相同的过程;

小结

  • 继承和组合都是从已有类型创建新类型,组合将已有类型作为新类型底层实现的一部分,继承复用的是接口;
  • 使用继承时,派生类具有基类接口,可以向上转型为基类;

bye