Java编程思想第7章

组合:在新的类中产生现有类的对象

继承:按照现有类的类型创建新类

7.1 组合语法

组合语法,只需要将对象引用置于新类中即可

1.每一个非基本类型的对象都有一个toString()方法,而且当编译器需要一个String而你却只有一个对象时,该方法便会被调用

2.编译器并不简单的为每一个引用都创建默认对象,这一点是很有意义的,因为若真要那样做的话,就会在许多情况下增加不必要的负担。如果想初始化这些引用,可以在代码中的下列位置进行:

(1)在定义对象的地方。这意味着它们总是在构造器被调用之前得到初始化。

(2)在类的构造器中

(3)就在正要使用这些对象之前(惰性初始化)

(4)使用实例初始化

7.2 继承语法

1.在Java中,当创建一个类时,总是在继承,因此,除非以明确指出要从其他类中继承,否则就是在隐式地从Java的标准跟类Object进行继承

2.继承使用的是一种特殊的语法。在继承过程中,需要先声明“新类与旧类相似”。这种声明是通过在类主体的左边花括号之前,书写后面紧随基类名称的关键字extends而实现的。当这么做,会自动得到基类的所有方法和域。如:class xxxx extends yyyy

3.在继承的过程中,并不一定非得使用基类的方法。也可以在子类中添加新的方法,其添加方式与在类中添加任意方法一样

继承一般规则:是将所有的数据成员都指定为private,将所有的方法指定为public

4.可以将继承看作是对类的复用

7.2.1 初始化基类

1.基类与子类具有相同接口的新类。或许还会有一些额外的方法或域。但继承并不只是复制基类的接口。当创建一个子类对象的时候,该对象包含了一个基类的子对象,这个子对象与你用基类直接创建的对象是一样的。二者区别在于,后者来自于外部,而基类的子对象被包装在子类对象内部

2.基类子对象准确初始化的方法:在构造器中调用基类构造器来执行初始化,而基类构造器具有执行基类初始化所需要的知识和能力。Java在自动在子类的构造器中插入对基类构造器的调用

3.构造过程是从基类“向外”扩散的,所以基类在子类构造器可以访问它之前,就已经完成了初始化

初始化基类推荐文章:https://www.jb51.net/article/159467.htm

7.2.2 带参数的构造器

1.如果没有默认的基类构造器,或者想调用一个带参数的基类构造器,就必须用关键字super显示地编写调用基类构造器的语句,并且配以适当的参数列表。而且super必须放到构造器的第一行

2.调用基类构造器必须是在导出类构造器中要做的第一件事

super出现在继承了父类的子类中的三种存在方式:

第一种:super.xxx;(xxx为变量名或对象名)

这种方法意义为,获取父类中的名字为xxx的变量或方法引用

使用这种方法可以直接访问父类中的变量或对象,进行修改赋值等操作

第二种:super.xxx();(xxx为方法名)

这种方法意义为,直接访问并调用父类中的方法

第三种:super();

这种方法意义为,调用父类的初始化方法,其实就是调用父类中的public xxx()方法

7.3 代理

1.第三种关系称为代理,Java没有提供直接的支持。这是继承与组合之间的关系。因为我们将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了改成员对象的所有方法(就像继承)。因此代理解决了此问题

2.我们使用代理可以拥有更多的控制权,因为我们可以选择只提供在成员对象中的方法的某个子集

3.尽管Java中不直接支持代理,但是很多开发工具支持代理

代理推荐文章:

(1)https://www.cnblogs.com/xiaocao123/p/10686424.html

(2)https://www.cnblogs.com/boboxing/p/8126046.html

7.4 结合使用组合和继承

虽然编译器强制去你初始化基类,并且要求你要在构造器起始就要这么做,但是它并不监督你必须将成员对象也初始化,因此在这一点上你自己必须时刻注意

7.4.1确保准确清理

1.在Java中垃圾回收器负责销毁对象。但有时类可能要在其生命周期内执行一些必须的清理活动。你根本不知道垃圾回收器何时被调用,或者它是否已经被调用。因此,如果你想要某个类清理一些东西,就必须显示的编写一个特殊方法来做这个事,并要确保客户端程序员知晓他们必须要调用这个方法

2.在清理方法中,还必须注意对基类清理方法和成员对象清理方法的调动顺序,以防某个子对象依赖于另一个子对象情形的发生。首先,执行类的所有特定的清理动作,其顺序同生成顺序相反;然而,就如我们所示范的那样,调用基类的清理方法

3.许多情况下,清理并不是问题,仅需要让垃圾回收器完成该动作就行。但当必须亲自处理清理时,你得多做努力并多加小心。因此,一旦涉及垃圾回收,能够信赖的事就不会很多了。垃圾回收器可能永远也不会被调用,即使被调用,它也可能以任何它想要的顺序来回收对象。最好的办法就是除了内存以外,不能依赖垃圾回收器去做任何事情。如果需要进行清理,最好是编写自己的清理方法。但不要使用finalize()方法

针对try和finally一些总结:
(1)不管有没有异常,finally中的代码都会执行

(2)当try、catch中有return时,finally中的代码依然会继续执行

(3)finally是在return后面的表达式运算之后执行的,此时并没有返回运算之后的值,而是把值保存起来,不管finally对该值做任何的改变,返回的值都不会改变,依然返回保存起来的值。也就是说方法的返回值是在finally运算之前就确定了的。

(4)finally代码中最好不要包含return,程序会提前退出,也就是说返回的值不是try或catch中的值

public static int tryCatch(){
        int i = 1;
        try {
            return i;
        }finally {
//            return ++i;
            ++i;
        }
    }
验证结论23
  输出结果1

推荐文章:

(1)https://blog.csdn.net/m0_37524661/article/details/88081465

(2)https://www.cnblogs.com/jiangxiulian/p/7151269.html

7.4.2名称屏蔽

1.如果Java的基类拥有某个以被多次重载的方法名称,那么在子类中重新定义该方法的名称并不会屏蔽其在基类中的任何版本,因此,无论是改层或者它的基类中对方法进行定义,重载机制都可以正常工作

2.JavaSE5增加了@Override注解,它并不是关键字,但是可以把它当做关键字使用。当你需要覆写某个方法时,就添加这个注解。在你不留心重载而并非覆写了该方法时,编译器就会生成一条错误信息

7.5 在组合与继承之间的选择

1.组合和继承都允许在新的类中放置子对象,组合是显示地这样做,而继承则是隐式地做

2.组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。即,在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。为取得此效果,需要在新类中嵌入一个现有类的private对象

有时,允许类的用户直接访问新类中的组合成分是极具有意义的。也就是说,将成员对象声明为public。如果成员对象自身都隐藏了具体实现,那么这种做法是安全的。当用户能够了解到你正在组装部件时,会使得端口更加易于理解

3.在继承的时候,使用某个现有类,并开发一个它的特殊版本。通常,这意味着你在使用一个通用类,并为了某种特殊需要而将其特殊化。比如:用一个“交通工具”对象来构建一部"车子“是毫无意义的,因为”车子“并不包含”交通工具“,它仅是一种交通工具(is-a),这个关系是用继承来表示的,而has-a关系则是用组合来表示的

组合和继承是面向对象中两种代码复用的方式:

组合:在新类里面创建原有类的对象,重复利用已有类的功能。(has-a关系)

继承:可以使用现有类的功能,并且在无需重复编写原有类的情况下对原有类进行功能上的扩展。(is-a关系)

引用网友的一句很经典的话应该更能让大家分清继承和组合的区别:组合可以被说成“我请了个老头在我家里干活” ,继承则是“我父亲在家里帮我干活"

7.6 protected关键字

1.在实际项目中,经常会想要某些事物尽可能对这个世界隐藏起来,但仍然允许子类的成员访问它们

关键字protected就起这个作用。它指明”就类用户而言,这是private,但对于任何继承与此类的子类或其他任何位于同一个包内的类来说,它却是可以访问

2.尽管可以创建protected域,但是最好的方式还是将域保持为private。你应当一直保留“更改底层实现”的权利。然后通过protected方法来控制类的继承者的访问权限

访问修饰符推荐文章:https://www.cnblogs.com/yuechuan/p/8973849.html

7.7 向上转型

1.为“新的类型提供方法”并不是继承技术中最重要的方面,其最重要的方面是用来标示新类和基类之间的关系。这种关系可以由“新类是现有类的一种类型”加以概括

2.Java对类型的检测是非常严格的,接收某种类型的方法同样可以接收另外一种类型就显得很奇怪。除非你认识到子类也是一种基类对象。这种子类引用转换为基类引用,称为 向上转换

7.7.1为什么称为向上转换

历史原因,并且是传统的继承图的绘制法为基础的:将根植于页面的顶部,然后逐渐向下,如下:
在这里插入图片描述
由子类型转基类型,在继承图上是先上移动的,因此一般称为:向上转型。由于向上转型是一个专用类型向通用类型转换的,所以总是很安全的。也就是说,子类是基类的一个超集。它可能比基类含有更多的方法,但它必须至少具备基类中所含有的方法。在向上转型的过程中,类接口中唯一可能发生的事情是丢失方法,而不是获得它们。这就是为什么编译器在“未曾明确表示转型”或“未曾指定特殊标记”的情况下,仍然允许向上转型的原因

JAVA-向上转型、向下转型推荐文章:https://www.cnblogs.com/lifexy/p/10812841.html

7.7.2再论组合和继承

到底是改用结合或继承?

问一问自己是否需要从新类向基类进行向上转型,如果必须向上转型,则继承是必要的。但如果不需要,则应当好好考虑自己是否需要继承

7.8 final关键字

根据上下文环境,Java的关键字final的含义存在细微的区别,别通常它指的是“这是无法改变的”,不想做改变可能处于两种原因:

(1)设计

(2)效率

由于这两个愿意相差很远,所以final有可能被误用

final关键字推荐文章:https://www.jianshu.com/p/9b8d3a9873f9

空白final

Java允许生成“空白final”,所谓空白final指被声明为final但有未给定初识的值的域。无论什么情况,编译器都确保空白final在使用前必须初始化。但是,空白final在关键字final的使用上提供了更大的灵活性,因此,一个类中final域就可以做到根据对象而有所不同,却又保持其永恒不变的特性

必须在域定义处或每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因所在

7.9初始化及类的加载

1.Java采用不同的加载方式,以为Java中所有都是对象。请记住,每一个类的编译代码都存在于它自己的独立的文件中。该文件只在需要使用程序代码时才会被加载。一般来说,可以说“类的代码在初始化使用时才加载”。这通常是值加载发生于创建类的第一个实例对象之前,但是当访问static域或者方法时,也会发生加载

2.初次使用之处也是static初始化发生之处。所有的static对象和static代码段都会在加载时依程序中的顺序而依次初始化。当然,定义为static的东西只会被初始化一次

初始化及类的加载推荐文章:
(1)https://www.cnblogs.com/yangyongjie/p/11002844.html

(2)https://www.cnblogs.com/one-apple-pie/p/10503948.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值