thinkinginjava第七章3-1

kyaoyyw      2022-05-01     193

关键词:

Thinking in Java第七章研读3-1总结

问题引入:如何复用代码

1.新的类是由现有类的对象所组成,方法称为组合。(该方法只是复用了现有程序代码的功能,而非他的形式)

2.按照现有类的类型创建新类。方法称为继承。(该方法无需改变现有类的形式,采用现有类的形式并在其中添加新代码)

3.代理proxy

组合Demo(存在问题:对象引用的初始化)

 1 package com.thxy.section.seven;
 2 
 3 public class Compo {
 4     public static void main(String[] args) {
 5         Bath bath = new Bath();
 6         System.out.println(bath);
 7 
 8     }
 9 }
10 
11 class Soap {
12     private String s;
13 
14     Soap() {
15         System.out.println("Soap()");
16         s = "Constructed";
17     }
18 
19     @Override
20     public String toString() {
21         return s;
22     }
23 }
24 
25 class Bath {
26     private String s1 = "Happy";
27     private String s2 = "Happy";
28     private String s3, s4;
29     private Soap castille;
30     private int i;
31     private float toy;
32 
33     Bath() {
34         System.out.println("Inside Bath()");
35         s3 = "Joy";
36         toy = 3.14f;
37         castille = new Soap();
38     }
39 
40     {
41         i = 47;
42     }
43 
44     @Override
45     public String toString() {
46         if (s4 == null) {
47             s4 = "Joy";
48         }
49         return
50                 "s1=" + s1 + "
" + "s2=" + s2 + "
" + "s3=" + s3 + "
" + "s4=" + s4 + "
" + "toy=" + toy + "
" + "castille=" + castille;
51     }
52 }

总结:

初始化引用对象可以在代码中的如下位置

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

技术图片

2.在类的构造器中

技术图片

3.就在正要使用这些对象之前,这种方法称为惰性初始化。

技术图片

使用断点调试执行过程

1.技术图片

由调试结果得知:

1.先初始化s4=Joy

2.初始化s1,s2

3.{i=47}初始化i

2.技术图片

由调试结果得知:

1.先初始化s3,toy

2.再初始化Soup引用对象

4.最后初始化s引用对象

问题:为什么会立即初始化s4引用对象?

技术图片

原著:当toString被调用时,它将填充s4的值,以确保所有的域在使用之时已被妥善初始化。是否这么写就错误了?通过debug调试jvm虚拟机将s4就初始化了。

继承Demo

 1 package com.thxy.section.seven;
 2 
 3 public class Inherit {
 4     public static void main(String[] ars) {
 5         Detergent x = new Detergent();
 6         x.dilute();
 7         x.apply();
 8         x.scrub();
 9         x.foam();
10         System.out.print(x);
11     }
12 }
13 
14 class Cleanser {
15     private String s = "Cleanser.";
16 
17     public void append(String a) {
18         s += a;
19     }
20 
21     public void dilute() {
22         append("dilute()");
23     }
24 
25     public void apply() {
26         append("apply()");
27     }
28 
29     public void scrub() {
30         append("scrub()");
31     }
32 
33     @Override
34     public String toString() {
35         return s;
36     }
37 }
38 
39 class Detergent extends Cleanser {
40     /*
41     覆盖
42      */
43     @Override
44     public void scrub() {
45         append("Detergent.scrub()");
46     }
47 
48     /*
49     新增
50      */
51     public void foam() {
52         append("foam()");
53     }
54 }

总结:

Cleanser.dilute()apply()Detergent.scrub()foam()

1.继承,一般的规则是将所有数据成员都指定为private,将所有方法指定为public(protected成员也可以借助导出来类访问)。

2.由于Detergent是由关键字extends从Cleanser导出,所以它可以在接口中自动获取这些方法,尽管我们不能看到这些方法在Detergent中的显示定义。因此,可以将继承可以看做是对类的复用。

3.对基类中定义的方法对他进行修改是可行的(覆盖/重写)。

4.在继承过程中,不一定非得使用基类的方法。可以在导出类中添加新方法。

5.对于导出来的对象不仅可以使用自己在类中定义的方法,而且还可以使用基类的方法。

基类和导出类构造方法(初始化)Demo

 1 package com.thxy.section.seven;
 2 
 3 public class Init {
 4     public static void main(String[] args) {
 5         Cartoon cartoon=new Cartoon();
 6 
 7     }
 8 }
 9 
10 class Art {
11     Art() {
12 //        super();
13         System.out.println("Art constructor");
14     }
15 }
16 
17 class Drawing extends Art {
18     Drawing() {
19 //        super();
20         System.out.println("Drawing constructor");
21     }
22 }
23 
24 class Cartoon extends Drawing {
25     Cartoon() {
26 //        super();
27         System.out.println("Cartoon constructor");
28     }
29 }

总结:

1.结果

Art constructor
Drawing constructor
Cartoon constructor

2.构造过程是从基类“向外”扩展的。

3.系统会默认地调用super()方法即使程序员不显示调用。

4.系统会默认为类创建一个默认地构造器即使程序员不显示写构造器。

 1 package com.thxy.section.seven;
 2 
 3 public class Init {
 4     public static void main(String[] args) {
 5         Cartoon cartoon = new Cartoon(11);
 6         Cartoon c = new Cartoon();
 7 
 8     }
 9 }
10 
11 class Art {
12     Art() {
13 //      super();
14         System.out.println("Art constructor");
15     }
16 
17     Art(int i) {
18         System.out.println("Art constructor" + i);
19     }
20 }
21 
22 class Drawing extends Art {
23     Drawing() {
24         System.out.println("Drawing constructor");
25 
26     }
27 
28     Drawing(int i) {
29         super(i);
30         System.out.println("Drawing constructor" + i);
31     }
32 }
33 
34 class Cartoon extends Drawing {
35     Cartoon() {
36         System.out.println("Cartoon constructor");
37 
38     }
39 
40     Cartoon(int i) {
41         super(i);
42         System.out.println("Cartoon constructor" + i);
43     }
44 }

总结:

1.结果

Art constructor11
Drawing constructor11
Cartoon constructor11
Art constructor
Drawing constructor
Cartoon constructor

2.如果程序员写了带参数的构造器系统将不会默认创建构造器。

3.如果想调用一个带参数的基类构造器就必须用关键字super显示地编写调用基类构造器的语句。

4.注意:如果基类重写了构造器导出类想调用一个带参数的基类构造器就要显示调用super语句;如果不写则报错因为导出类的构造器会默认调用super()方法。

中国中庸之道之代理Demo(继承和组合的中庸之道)

example:太空船需要一个控制模块

 1 package com.thxy.section.seven;
 2 
 3 public class Proxy {
 4     public static void main(String[] args) {
 5         SpaceShip spaceShip = new SpaceShip("NSEA Protector");
 6         spaceShip.forward(100);
 7     }
 8 }
 9 
10 class SpaceShipControls {
11     void up(int velocity) {
12     }
13 
14     void down(int velocity) {
15     }
16 
17     void left(int velocity) {
18     }
19 
20     void right(int velocity) {
21     }
22 
23     void forward(int velocity) {
24         System.out.println(this+" "+"forward" + " "+velocity);
25     }
26 
27     void back(int velocity) {
28     }
29 
30     void turboBoost() {
31     }
32 }
33 
34 class SpaceShip extends SpaceShipControls {
35     private String name;
36 
37     SpaceShip(String name) {
38         this.name = name;
39     }
40 
41     @Override
42     public String toString() {
43         return name;
44     }
45 }

总结:

1.结果:NSEA Protector forward 100

2.SpaceShip并非真正的SpaceShipControls类型(按向上转型地说SpaceShip对象是一种类型的SpaceShipControls?)(向上转型时说法)中文翻译很难懂。真正逻辑上SpaceShip中包含了SpaceShipControls;应该用组合才对。这里就不适合用继承因为逻辑乱了。

3.SpaceShipControls所有的方法在SpaceShip中暴露了。

需要解决的问题:1.SpaceShip和SpaceShip的关系 2.隐藏SpaceShipControls具体实现方法(结合实际想象我们国防内部技术实现不能透露,可是他的功能是可以暴露的)

逻辑优化Demo(采用单例模式)

  1 package com.thxy.section.seven;
  2 
  3 public class Proxy2 {
  4     public static void main(String[] args) {
  5         SpaceShip2 spaceShip2 = new SpaceShip2();
  6         spaceShip2.up(100);
  7         spaceShip2.down(100);
  8         spaceShip2.forward(100);
  9         spaceShip2.back(100);
 10         spaceShip2.turboBoost();
 11 
 12     }
 13 }
 14 
 15 class SpaceShipControls2 {
 16 
 17     private SpaceShipControls2() {
 18 
 19     }
 20 
 21     /*
 22     一条太空飞船中只有一个控制器
 23      */
 24     private static SpaceShipControls2 spaceShipControls2 = new SpaceShipControls2();
 25 
 26     public static SpaceShipControls2 spaceShipControl() {
 27         return spaceShipControls2;
 28     }
 29 
 30     void up(int velocity) {
 31         System.out.println(this + " " + "up" + " " + velocity);
 32     }
 33 
 34     void down(int velocity) {
 35         System.out.println(this + " " + "down" + " " + velocity);
 36     }
 37 
 38     void left(int velocity) {
 39         System.out.println(this + " " + "left" + " " + velocity);
 40     }
 41 
 42     void right(int velocity) {
 43         System.out.println(this + " " + "right" + " " + velocity);
 44     }
 45 
 46     void forward(int velocity) {
 47         System.out.println(this + " " + "forward" + " " + velocity);
 48     }
 49 
 50     void back(int velocity) {
 51         System.out.println(this + " " + "back" + " " + velocity);
 52     }
 53 
 54     void turboBoost() {
 55         System.out.println(this + " " + "turboBoost");
 56     }
 57 }
 58 
 59 class SpaceShip2 {
 60     private String name;
 61     private SpaceShipControls2 spaceShipControls2 = SpaceShipControls2.spaceShipControl();
 62 
 63     SpaceShip2() {
 64         this.name = name;
 65     }
 66 
 67     @Override
 68     public String toString() {
 69         return name;
 70     }
 71 
 72     void up(int velocity) {
 73         spaceShipControls2.up(velocity);
 74     }
 75 
 76     void down(int velocity) {
 77         spaceShipControls2.down(velocity);
 78     }
 79 
 80     void left(int velocity) {
 81         spaceShipControls2.left(velocity);
 82     }
 83 
 84     void right(int velocity) {
 85         spaceShipControls2.right(velocity);
 86     }
 87 
 88     void forward(int velocity) {
 89         spaceShipControls2.forward(velocity);
 90     }
 91 
 92     void back(int velocity) {
 93         spaceShipControls2.up(velocity);
 94     }
 95 
 96     void turboBoost() {
 97         spaceShipControls2.turboBoost();
 98     }
 99 
100 }

总结:

1.结果:

[email protected] up 100
[email protected] down 100
[email protected] forward 100
[email protected] up 100
[email protected] turboBoost

2.通过上述的实现中可以很好理清逻辑:广泛的说每条太空船都有其名称和专属的控制器:控制器的具体如何实现都隐藏在控制器中巧妙地解决了逻辑问题。

3.从上述的实现中可以很好理解到向上转型中当选择使用继承还是组合时考虑自己是否真的很需要向上转型吗?现实中很多对象都是包含和被包含的关系这时通常不需要向上转型可以使用组合或许更好的解决逻辑关系。但是包含与被包含关系也有部分要利用继承扩张。毛主席曾经说过具体问题具体分析,实事求是是不无道理的。

神奇的名称屏蔽(类和类之间的重载)

重载机制的条件:

1.以参数区分重载方法

2.以返回值区分重载方法(行不通因为有时并不关心返回值只关心方法是如何实现的)

总的来说构成重载机制方法名一致;参数类型和个数和返回值其中一个不同。

 1 package com.thxy.section.seven;
 2 
 3 public class Overloading {
 4     public static void main(String[] args) {
 5         Bart bart = new Bart();
 6         bart.doh(new MilHouse(10));
 7         bart.doh(‘c‘);
 8         bart.doh(0.01f);
 9 
10     }
11 }
12 
13 class Homer {
14     /*
15     重载
16      */
17     void doh(char c) {
18         System.out.println(c);
19     }
20 
21     void doh(float f) {
22         System.out.println(f);
23     }
24 }
25 
26 class MilHouse {
27     private int i;
28 
29     MilHouse(int i) {
30         this.i = i;
31     }
32 
33     @Override
34     public String toString() {
35         return "" + i;
36     }
37 }
38 
39 class Bart extends Homer {
40     /*
41     重载
42      */
43     void doh(MilHouse milHouse) {
44         System.out.println(milHouse);
45     }
46 }

总结:

1.结果

10
c
0.01

2.可以看出在基类定义的重载方法doh(xx)方法,在导出类也定义了重载方法doh(xx)方法。在导出类中不仅可以调用自己的重载方法,也可以调用基类的重载方法。

3.由2知虽然Bart引入了一个新的重载方法,但是在Bart中Homer的所有重载方法都是可用的。

4.在程序员不留意重载而并非重写了该方法时使用Java SE5新增的@Override注解可以大大减少阅读的困难性。

5.有大部分人都认为重载和重写的区别是重载一定是发生在同一类中的,重写是发生在不同类中的。其实这种说法是片面的。当导出类继承了基类也可以重载基类的方法

并且可以调用基类的方法。我想他们那些人会考虑导出类继承了基类就相当于导出类是基类的一种类型也相当在一个类中。

 

备注:本人大二在校生在研读Thinking in Java这本经典书,由于英语水平有限不能读原版的Thinking in Java英文版所以只能读中文版,但是中文翻译读起来也是够呛。如果我对其中知识点理解有误请指正。谢谢。上面有残留一个问题请大神指教。(原著:当toString被调用时,它将填充s4的值,以确保所有的域在使用之时已被妥善初始化。是否这么写就错误了?通过debug调试jvm虚拟机将s4就初始化了。)请将你们答案写在下方留言!!!

第七章数组实验

C程序设计实验报告实验练习: 7.3.1.1、写一个函数,对用随机的函数产生的10个整数按从小到大的顺序排序(升序,用冒泡排序法实现) 7.3.1.2、写一个函数,对随机产生的10个整数按从小到大的顺序排序(升序,用选择... 查看详情

第七篇pythonio操作

文章目录10文件操作10.1打开与关闭10.1.1打开文件10.1.2关闭文件10.2文件的读写10.2.1写数据(write)10.2.2读数据(read)10.2.3读数据(readlines)10.2.4读数据(readline)10.3文件的常用操作10.3.1获取当前读写的位置10.3.2定位到某个位置10.3.3文件... 查看详情

第七篇pythonio操作

文章目录10文件操作10.1打开与关闭10.1.1打开文件10.1.2关闭文件10.2文件的读写10.2.1写数据(write)10.2.2读数据(read)10.2.3读数据(readlines)10.2.4读数据(readline)10.3文件的常用操作10.3.1获取当前读写的位置10.3.2定位到某个位置10.3.3文件... 查看详情

郑捷《机器学习算法原理与编程实践》学习笔记(第七章预测技术与哲学)7.3岭回归

7.3岭回归7.3.1验证多重共线性7.3.2岭回归理论7.3.3岭际分析7.3.4k值的判断7.3.5辅助函数 (1)导入多维数据集:加载数据集defloadDataSet(filename):numFeat=len(open(filename).readline().split(‘ ‘))-1#getnumberoffieldsdataMat=[]labelMat=[]fr=ope 查看详情

html第七章

第七章浮动1.常见的网页布局:      布局类型布局样式图示国字型1-3-1 图1拐角型1-2-1 图2 2.浮动:什么是浮动:在标准文档流中,一个块级元素在水平方向会自动伸展到包含它的元素的边界,在... 查看详情

第七章数组实验报告(代码片段)

C程序设计实验报告实验项目:数组实验姓名:廖云福实验地点:514物联网实验室实验时间:2019年5月29日一实验项目7.3.1一维数组的应用7.3.2二维数组的应用7.3.3字符数组的应用一、实验目的和要求a.掌握一维和多维数组的定义和... 查看详情

java并发编程的艺术--原子操作类和并发工具类(第七八章)(代码片段)

文章目录1、原子操作类1.1、原子更新基本类型1.1.1、原子更新基本类型常用类1.1.2、AtomicInteger的常用方法1.1.3、AtomicInteger的使用1.1.4、getAndIncrement是如何实现原子操作的呢?1.1.5、AtomicInteger类的原理1.2、原子更新数组1.2.1、原... 查看详情

第七周作业

一.pta:1.7-3:(1)实验代码:#include<stdio.h>#include<math.h>intmain(){inti,n,t;floatsum=0;scanf("%d",&n);for(i=1;i<=n;i=i+1){t=pow(-1,i-1);sum=sum+(t*i)/(2.0*i-1.0);}printf("%.3f",sum);}(2 查看详情

第七周作业

一.题目:7-3:1.代码:#include<stdio.h>#include<math.h>intmain(){inti,n,a;doublesum=0;scanf("%d",&n);for(i=1;i<=n;i=i+1){a=pow((-1),i+1); sum=sum+a*i/(2.0f*i-1);}printf("%.3f",sum);return0; 查看详情

计算机网络(谢希仁第七版)第一章--1.3互联网的组成

1.互联网的组成图示:1.1互联网的边缘部分1.1.1互联网的边缘部分概念图示:1.1.2端系统之间通信的含义1.1.3端系统之间的两种通信方式1.1.3.1客户-服务器方式客户-服务器工作方式:客户软件的特点:服务器软件的特点:1.1.3.2对等连接方... 查看详情

java-冒泡排序的优化算法(尚学堂第七章数组)

importjava.util.Arrays;publicclassTestBubbleSort2{publicstaticvoidmain(String[]args){int[]values={3,1,6,2,9,0,7,4,5,8};inttemp=0;for(inti=0;i<values.length-1;i++){booleanflag=true;for(intj=0;j<v 查看详情

java-冒泡排序的基础算法(尚学堂第七章数组)

/***冒泡排序的基础算法*/importjava.util.Arrays;publicclassTestBubbleSort1{publicstaticvoidmain(String[]args){int[]values={3,1,6,2,9,0,7,4,5,8};inttemp=0;/*2.调用内循环length-1次,数字逐渐实现从左到右依次向后排,*每执行n次内循环就出现n个排好的数值,故 查看详情

第七章数组实验实验报告(第一部分)(代码片段)

实验项目:第七章数组实验姓名:谢丽萍 时间:2019年5月29号  地点:514教室一、实验目的与实验要求①7.3.1-1本实验旨在巩固学生对数组这种数据结构的理解,增强程序设计能力。在这个实验中,学生将练习:定义一... 查看详情

设计模式从青铜到王者第七篇:创建型模式之抽象工厂模式(abstractfactory)(代码片段)

系列文章目录文章目录系列文章目录前言1.抽象工厂模式简介2.抽象工厂模式结构3.抽象工厂模式代码实例3.1.定义产品类3.1.1.产品类Ball3.1.2.产品类Shirt3.2.定义工厂类3.3.客户端使用方法示例3.4.效果4.抽象工厂模式总结优点:缺... 查看详情

第二周第七节列表的使用

name=["zhangyang","guyun","xiangpeng"]print(name[0],name[2])zhangyangxiangpengname=["zhangyang","guyun","xiangpeng"] print(name[1:3])#切片,起始位置包括,结束位置不包括,顾头不顾尾"zhangyang","guyun","xiangpeng"  name=["zhangyang","guyun","xiangpeng"]print(name[-1])#取... 查看详情

kubernetes第七篇:使用kubernetes部署prometheus+grafana监控系统(kubernetes工作实践类)(代码片段)

文章目录一、前言二、K8s监控系统架构2.1Prometheus简介2.2Prometheus架构2.3Prometheus知识普及三、K8s监控系统搭建3.1三类数据采集metrics3.2Prometheus+Grafana3.3实践一下:将prometheus+grafana搭建起来3.3.1搭建3.3.2分步测试3.3.2.1安装nodee... 查看详情

thinkinginjava读书笔记2

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6481068.html第十四章:识别对象类型信息(RTTI和反射机制) 查看详情

thinkinginjava----readingnote

#thinkinginjava4th#readingnote#victor#2016.02.10chapter1对象入门1.1抽象的进步   (1)所有东西都是对象。   (2)程序是一大堆对象的组合,对象间通过消息联系。   (3)通过封装现有对象,可制作出新型对象。 &n... 查看详情