[Java编程思想] 第七章 复用类
第七章 复用类
第一种方法非常直观:只需在新的类中产生现有类的对象(组合)。
第二种方法更细致一些:它按照现有类的类型来创建新类(继承)。
7.1 组合语法
只需将对象引用置于新类中即可。
class A{}
class B{
	A a = new A();
}
如果想初始化这些引用,可在下列位置进行:
- 在定义对象的地方。
- 在类的构造器中。
- 在真正使用这些对象之前,惰性初始化。
- 使用实例初始化。
7.2 继承语法
当创建一个类时,总是在继承。
在继承过程中,需要先声明“新类与旧类相似”。在基类名称后紧随关键词extends,当这么做时,会自动得到基类中所有的域和方法。
为了继承,一般将数据成员指定为private,将方法指定为public(protected成员也可以借助导出类访问)。
Java使用super关键字表示超类,当前类就是从超类继承来的,如super.scrub()将调用基类(父类)版本的scrub()。
7.2.1 初始化基类
当创建一个导出类对象,该对象包含了一个基类的子对象。这个字对象与你用基类直接创建的对象是一样的。
Java会自动在导出类的构造器中插入对基类构造器的调用。
7.3 代理
代理是继承和组合之家你的中庸之道。将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象所有方法(就像继承)。
class AControls{
    void up(){}
    void down(){}
}
class B{
    AControls a = new AControls();
    void up(int i){
        a.up(i);
    }
    void down(int i){
        a.down(i);
    }
}
7.4 在组合和继承之间选择
is-a(是一个)的关系用继承来表达。
has-a(有一个)的关系用组合来表达。
7.5 protected关键字
就类用户而言,这是private的,但对于任何继承于此类的导出类或其他任何位于同一包内的类来说,它却可以访问。
7.6 向上转型
“为新的类提供方法”并不是继承最总要的,最重要的方面是用来表现新类和基类之间的关系。这种关系可以用“新类是现有类的一种类型”概括。
class A{
	public void play(){}
	static void tune(A a){
		a.play();
	}
}
class B extends A{
    public static void main(String[] args){
    	B b = new B();
        A.tune(b);		// 向上转型
    }
在tune()中,程序代码可以对A(父类)和他所有的导出类(子类)起作用,这种将B(子)引用转换为A(父)引用的动作,称之为向上转型。
7.6.1 为什么称为向上转型
由导出类转型为基类,在继承图上是向上移动的,一般称向上转型。由于向上转型是从一个较专用类型向较普通类型转换,所以总是很安全的。
7.6.2 再论组合与继承
一个最清晰的判断办法就是问一问自己是否需要从新类向基类进行向上转型。如果必须向上转型,则继承是必要的,但如果不需要,则应当考虑是否继承。
7.7 final关键字
7.7.1 final数据
- 一个永不改变的编译时常量。
- 一个在运行时被初始化的值,而你不希望它被改变。
一个既是static又是final的域只占据一段不能被改变的存储空间。
当对对象引用而不是基本类型运用final时,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法把它改为指向另一个对象,然而,对象其自身却可以修改(指针不能变,对象内存域中的值可以变)。
不能因为某数据是final就认为在编译时可知的,如果使用随机数初始化在编译时不可知。
空白final
被声明为final但又未给初始值的域,提高了灵活性,必须在域的定义处或每个构造器中用表达式对final进行赋值。
final参数
Java允许在参数列表中将参数声明为final,意味着方法中无法更改引用指向。可以读参数,无法修改参数,主要用来向匿名内部类传递数据。
7.7.2 final方法
- 锁定方法,防止任何继承类修改它的含义,使方法形为不变,不会被覆盖。
- (早期)使用final方法效率高。
final和private关键字
类中所有的private方法都是隐式地指定为final的。
这会造成混淆,如果你覆盖一个private方法(隐含final),似乎是奏效的。“覆盖”只有在某方法是基类的接口的一部分时才会出现(能向上转型为基类并调用相同方法)。如果某方法为private,它就不是基类的接口的一部分。如果在导出类中以相同名称生成public、protected或包访问权限方法,此时没有覆盖该方法,仅是生成新方法。由于private无法触及而且有效隐藏,只看成它归属类的组织结构,其他情况不考虑。
7.7.3 final类
当将某个类定义为final,表明不打算继承该类,且不允许别人这样做。该类设计永不变动,并且不希望它有子类。final类中的方法也是隐式final的,无法覆盖。
7.8 初始化及类的加载
Java中的所有事物都是对象。每个类的编译文件都存在于它自己的独立文件中。该文件只有需要使用时才被加载。一般来说”类的代码在初次使用时才加载”。
初次使用指:
- 创建类的第一个对象(创建对象调用构造器,构造器也是隐式static,准确的说,类是在任何static成员被访问时加载)。
- 访问static域或static方法。
7.8.1 继承与初始化
class A{
	private int i = 9;
	protected int j;
	A(){
		System.out.println("i = " + i + ", j = " + j);
		j = 39;
	}
	private static int x1 = printInit("static A.x1 initialized");
	static int printInit(String s){
		System.out.println(s);
		return 47;
	}
}
class B extends A{
	private int k = printInit("B.k initialized");
	public B(){
		System.out.println("k = " + k);
		System.out.println("j = " + j);
	}
	private static int x2 = printInit("static B.x2 initialized");
	public static void main(String[] args){
		System.out.println("B constructor");
		B b = new B();
	}
}
输出
static A.x1 initialized-------------父类静态成员初始化
static B.x2 initialized-------------子类静态成员初始化
B constructor-----------------------子类main(静态)打印语句
                                    //此时声明B b = new B();
                                    父类普通成员初始化i=9
i = 9, j = 0------------------------父类构造器打印语句
                                    父类构造器中初始化j=39
B.k initialized---------------------子类普通成员初始化k=47
k = 47------------------------------子类构造器打印语句
j = 39                              子类构造器打印语句
初始化过程如下:
父类静态-子类静态-父类构造-父类变量-子类构造-子类变量
- 在B上运行Java时,发生的第一件事就是试图访问B.main()(一个static方法),于是加载器开始启动并找出B类的编译代码(在名为B.class的文件中)。 
- 在对B.class加载过程中,编译器注意到B有一个基类A,于是它继续进行加载A。不管你是否打算产生一个该基类对象,这都要发生。 - 2.1 如果该基类还有其自身的基类,那么第二个基类被加载,以此类推。 
- 根基类(A类)中的static初始化被执行。 - 3.1 然后是下一个导出类的static初始化,以此类推。 
- 到此为止,必要的类都已加载完毕,对象可以被创建。 - 4.1 首先,基类(A类)对象所有的基本类型都被设为默认值,对象引用设为null。 - 4.2 基类(A类)构造器被调用。 - 4.3 基类(A类)构造器和导出类(B类)构造器一样,以相同顺序执行。 - 4.4 在基类构造器完成之后,实例变量按照其次续被初始化。 - 4.5 最后构造器的其余部分被执行。 
[Java编程思想] 第七章 复用类的更多相关文章
- Java编程思想第七章复用类
		7.1组合语法 在一个类中引入多个对象,以提高代码的复用性与功能. 7.2继承语法 使用继承子类可以获得,导出类可以获得基类的成员(变量与方法). 注:这里注意权限控制,若基类中的成员为默认权限,只有 ... 
- Java编程思想——第17章 容器深入研究 读书笔记(三)
		七.队列 排队,先进先出. 除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: ad ... 
- Java编程思想——第17章 容器深入研究(two)
		六.队列 排队,先进先出.除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: add ... 
- Java编程思想 第21章 并发
		这是在2013年的笔记整理.现在重新拿出来,放在网上,重新总结下. 两种基本的线程实现方式 以及中断 package thread; /** * * @author zjf * @create_tim ... 
- java编程思想笔记(第一章)
		Alan Kay 第一个定义了面向对象的语言 1.万物皆对象 2.程序是对象的集合,他们彼此通过发送消息来调用对方. 3.每个对象都拥有由其他对象所构成的存储 4.每个对象都拥有其类型(TYpe) 5 ... 
- 《Java编程思想》笔记 第七章 复用类
		1.组合 将其他类的对象引用置于新的类中. 3.继承 extends 从已知的一个类中派生出新的一个类,叫子类.子类实现了父类所有 非私有化 非静态 的属性和方法,并能根据自己的实际需求扩展出新的行为 ... 
- 《java编程思想》P125-P140(第七章复用类部分)
		1.类的成员默认的是包访问权限.允许包内成员访问 2.super.scrub() 调用基类的scrub方法 3.继承并不是复制基类的接口.当创建了一个导出类(子类)对象时,该对象包含了一个基类的子对象 ... 
- 初读"Thinking in Java"读书笔记之第七章 --- 复用类
		组合语法 将对象引用置于新类中,即形成类的组合. 引用初始化方法 在定义处初始化. 在类的构造器中初始化. 在使用这些对象之前,进行"惰性初始化". 使用实例初始化. 继承语法 J ... 
- Java编程思想学习(七) 抽象类和接口
		1.抽象类和抽象方法 抽象方法:不完整的,仅有声明而没有方法体. abstract void f(); 抽象类:包含抽象方法的类.(若一个类包含一个或多个抽象方法,则该类必须限定为抽象的.) 1.用抽 ... 
随机推荐
- Solution -「HDU 6875」Yajilin
			\(\mathcal{Description}\) Link.(HDU 裂开了先放个私链 awa.) 在一个 \(n\times n\) 的方格图中,格子 \((i,j)\) 有权值 \(w_ ... 
- C# 不区分大小写替换文本
			C# .NET类库自带的str.Replace() 方法替换文本不能区分大小写.我们可以自己编写一个扩展方法,支持文本忽略大小写替换.以下扩展方法实现了使用正则表达式忽略大小写替换文本. public ... 
- Dump Lsass内存转储新旧方法
			之前看到一篇关于Lsass内存dump的文章,学习记录一下. lsass.exe(Local Security Authority Subsystem Service)进程空间中,存有着机器的 ... 
- Spring Security即将弃用WebSecurityConfigurerAdapter配置类
			用过WebSecurityConfigurerAdapter的都知道对Spring Security十分重要,总管Spring Security的配置体系.但是马上这个类要废了,你没有看错,这个类将在 ... 
- 异常Java
			异常 1.什么是异常 异常指程序运行过程中出现的不期而至的各种状况,如:文件找不到.网络连接失败等 异常发生在程序运行期间,它影响了正常的程序执行流程 public class Demo01 { pu ... 
- 微服务从代码到k8s部署应有尽有系列(七、支付服务)
			我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ... 
- Python中如何取字典中的键值
			1 for k,v in DictName.items(): 2 #遍历字典的键值对,k对应键,v对应值 3 #k,v 的名字可以自己取,DictName是字典名 举例: tv_dict = {'芒果 ... 
- Redis 7.0 新功能新特性总览
			说明:本文根据Redis 7 RC2 的release note 整理并翻译 近日,Redis 开源社区发布了7.0的两个预览版.在这两个预览版中,有很多Redis 7.0中新增加的特性,新增加的命令 ... 
- Linux下忘记MySQL密码的解决办法
			一.使用免密码登录 1.使用 #find / -name my.cfg 找到mysql配置文件 2.vim /etc/mysql/my.cfg (我的配置文件是这个路径,每个人的路径可能有所不同,用f ... 
- POJ1990 题解
			题目大意:有若干头牛,每个牛有一个音量值,两头牛能互相听见对方说话需要发出两头牛中音量值较大者的音量*两头牛的距离的音量,求使任意两头牛都互相听见对方需要发出的音量总和.每头牛的音量值可以相同,但坐标 ... 
