• 20145326 《Java程序设计》第3周学习总结


    20145326 《Java程序设计》第3周学习总结

    教材学习内容总结

    >

    从了解java平台概论,JDK到IDE的介绍,基础语法的运用到现在的类与对象,封装。前三章的知识其实都不是特别难。但从第四章就要开始接触java程序设计的核心知识了。第三周的任务是学习第四章和第五章,内容较之前的知识更为复杂抽象难懂且比较繁多,不过我始终相信熟能生巧的道理,于是我几乎用了一周晚自习的时间将第四章和第五章完完整整仔仔细细的看了三遍,每一遍都有新的体会与感悟,看来付出总是有回报的! (这篇博客是目前为止人生中写的字数最多的一篇文章,字数已破万,用了星期六一天的时间,边思考边体会边记录,虽然工作量大,但还是很开心,很有成就感!~代码也托管完毕!!)

    第四章

    一、类与对象

    1.定义类

    java中有基本类型与类类型两个类型系统,我们之前在第三章谈到过基本类型,所谓基本类型,就是在使用时,得考虑一下数据用多少内存长度来存比较经济,利用程序语法告诉JVM,然后由JVM自动为你在内存中配置与管理。而类类型是什么呢?我们使用java撰写程序几乎都是在使用对象,要产生对象必须先定义类,类是对象的设计图,对象是类的实例。

    例如书上的例子: class clothes {
    String color;
    char size;}
    new clothes();
    clothes c1;
    clothes c1=new clothes();
    类定义时,用class关键词,名称使用clothes,建立衣服实例要用new关键词,在对象术语中这叫作新建一个对象。然后要声明一个参考名称c1,若将c1绑到新建的对象上,可以使用“=”指定,以java的术语来说,称为将c1名称参考至新建对象。对象与实例在java中几乎是等义的名词。在clothes类中定义了color与size两个变量,在java中也叫作定义两个值域成员,或叫作定义两个对象数据成员,这将表示每个新建的clothes实例可以拥有个别size与color的值。(看第一遍书的时候,觉得这里的概念太抽象,不过当我再回过头来看的时候,我将这种抽象的概念具体化,将其建立成模型,思路就清晰多了!)
    一个.java 文档中可以同时定义多个类,但是公开类只能有一个,且公开类名称必须与主文档名称相同,注意只要有一个类定义,编译程序就会产生一个.class文档。如果想在建立对象时,一并进行某个初始流程,像是指定数据成员值,则可以定义构造函数。构造函数是与类名称同名的方法(书上85页有范例)。当参数color与数据成员color同名时,不可以直接写color=color,这是将color参数的值指定给color参数,而要在对象成员color前面加上 this ,这表示将color参数的值指定给这个对象(this)的color成员。

    2.使用标准类

    javaSE提供了标准API,这些API就是由许多类组成的。我们可以直接取用这些标准类,省去撰写程序时重新打造基础的要求。书上介绍了两个标准类:java.util.Scanner与java.math.BigDecimal。到目前为止的程序都是很无聊的,因为变量值都是死的,没有办法接受用户的输入。这个时候我们就可以使用java.util.Scanner来解决输入问题。如果不想每次都输入java.util.Scanner,则我们一开始可以用import,这是之前的知识了。在建立Scanner实例的时候,必须传入java.io.InputStream的实例。在第十章的时候会有介绍,System.in就是一种InputStream(书上86页范例)。另外Scanner的nextInt()方法会看看标准输入中,有没有输入下一个字符串,有的话则将之剖析为int型,Scanner对于每个基本类型,都会有个对应的nextxxx()方法。如果直接取得上一个字符串,则可以用next(),如果想取得用户输入的整行文字,则使用nextline()。习惯上,包名称为java开头的类,表示标准API提供的类。 我记得在第二章学习基本类型的时候留下一个问题,1.0—0.8=0.2?答案是0.199999999996。这不是bug,这是由于java遵守IEEE754浮点数运算规范,使用分数与指数来表示浮点数。如果要求精度,那就要小心使用浮点数,而且别用==直接比较浮点数运算结果。这个时候java.math.BigDecimal就起作用了,它能有效解决浮点数计算和比较时的误差问题。equals()是比较两个BigDecimal实质上是否相同,所以有了a.add(b).add(c).equals(result)的方法(书上88页范例)。

    3.对象指定与相等性

    当=用于基本类型时,是将值复制给变量,当==用于基本类型时,是比较两个变量储存的值是否相同。如果你在操作对象,=是用在指定参考名称参考某个对象,而==是用在比较两个参考名称是否参考至同一对象。若两个对象里的实质内容相同,也不能草率的将其称之为“==”。内涵值相同用equals()。


    如:
    BigDecimal a = new BigDecimal(“0.1”);BigDecimal b = new BigDecimal(“0.1”);System.out.println(a==b);//显示false System.out.println(a.equals(b));//显示true

    二、基本类型打包器

    1.打包基本类型

    java中的两大类型系统,即基本类型和类类型,使用基本类型目的在于效率,然而更多时候,会使用类建立实例,因为对象本身可以携带更多信息,如果要让基本类型像对象一样操作,可以使用Long、Integer、Double等来打包基本类型。这些就是所谓的打包器,这些类主要目的就是提供对象实例作为“壳”,将基本类型打包在对象之中,这样就可以操作这个对象,就像是将基本类型当成对象操作。书上91页的范例有一处知识点我印象很深刻,即Integer提供compareTo()方法,可与另一个Integer对象进行比较,如果打包值相同就返回0,小于compareTo()传入对象打包值就返回-1,否则就是1。与==或!=只能比较是否相等或不相等,compareTo()方法返回更多信息。

    2.自动装箱、拆箱

    除了使用new创建基本类型打包器外,从J2SE5.0之后提供了自动装箱功能。
    可以这样打包基本类型:Integer wrapper=10;
    编译程序会自动判断是否能进行自动安装,在上例中你的wrapper会参考Integer实例;同样的动作可适用于boolean、byte、short等基本类型,分别会使用对应的Boolean、Byte、Short等打包基本类型。

    3.自动装箱、拆箱的内幕

    自动装箱与拆箱的功能事实上是编译程序蜜糖,也就是编译程序让你撰写程序时吃点甜头,编译时期根据所撰写的语法,决定是否进行装箱与拆箱动作。编译程序蜜糖虽然提供了方便性,但也因此隐藏了一些细节。我们可以通过反编译后的程序代码来观察更多语法蜜糖的细节。
    如书上93页的例子:
    Integer i1=100; Integer i2=100; if(i1==i2){ System.out.println("i1==i2");}else{System.out.println("i1!=i2");} 这个程序理所当然会显示“i1==i2”。但你如果将i1与i2都赋值为200,输出就会显示“i1!=i2”,为什么?通过反编译我知道了Integer.valueOf()创建Integer实例时,对i是有限制范围的,默认为-128~127。但这个范围自己可以更改。

    三、数组对象

    1.数组基础

    数组在java中就是对象,如果要储存10个学生的成绩,
    我们可以这么做:int[] Scores={88,81,74,68,78,76,77,86,56,78};这个程序片段建立了一个数组,因为使用了int[]声明,所以会在内存中分配长度为10的int连续空间,各个空间储存了88、81、74、68、78、76、77、86、56、78.各个空间都给予索引编号,索引由0开始,由于长度是10,所以最后一个索引为9,如果存取超出索引范围,就会抛出ArrayIndexOutOfBoundsException错误。若我们想依次取出数组中的每个值,方法之一是使用for循环。因为在java中,数组是对象,而不是单纯的数据集合,数组的length属性可以取得数组长度,也就是数组的元素个数。一维数组使用一个索引存取数组元素,你也可以声明二维数组,二维数组使用两个索引存取数组元素。(书上97页有范例)。有一点值得注意,那就是声明二维数组时,要在类型关键词旁加上 [] []。用增强式for循环在程序中会显得比较简洁。如果是三维数组以上,则不要用 [] [] [],因为不容易撰写,自定义类来解决这类需求会是较好的方式。

    2.操作数组对象

    我们之前遇见的都是事先知道元素值建立数组的例子,如果事先不知道元素值,只知道元素个数,那可以使用new关键词指定长度来建立数组,例如预先建立长度为10的数组:
    int[] scores =new int[10]; 在java中只要看到new,一定是建立对象,这个语法代表了数组就是对象,使用new建立数组后,每个索引元素会有默认值(书98页有数组元素初始值的表)。如果默认初始值不符合你的需求,则可以使用java.util.Arrays的fill()方法来设定新建数组的原始值。一开始就说了,对象是根据类而建立的实例,代表建立数组对象的类定义在哪里呢?是由JVM动态产生的。
    int[][] cords=new int[2][3],在某些书籍里的说法是,这建立了2X3的数组,每个索引都是默认值,但这只是简化的说法,这个语法实际上建立了一个int[][]类型的对象,里面有两个int[]类型的索引,分别是参考长度为3的一维数组对象,初始值都是0。如果将int[] []中的int[]看作一个整体,将其视为一个类X,实际上是在声明X的一维数组,也就是X[],java中的多维数组基本上都是由一维数组组成的。当然没有人规定二维数组一定要是矩阵,你也可以建立不规则数组。例如书上101页的例子,范例中 new int[2] []仅提供了第一个[]的数值,这表示arr参考的对象会有两个索引,但暂时参考到null。 Integer[] scores=new Integer[3];这个程序片段里建立的Integer对象数为0!,因为如果是类类型,这个片段的写法建立的数组,每个索引都是参考至null!

    3.数组复制

    要知道java和c语言虽然有很多共同点,但在有些地方千万不可混为一谈!

    如: int[] scores1={88,81,74,68,78,76,77,85,95,93};
    int[] scores2 = scores1; 在类类型中,这是代表将scores1参考的数组对象也给scores2参考,这并不是数组的复制!如果要实现数组复制的功能,基本做法就是另行建立新数组。建立一个与scores1相同的新数组,再逐一访问scores1每个索引元素,并指定给scores2对应的索引位置,事实上,我们可以使用System.arraycopy()方法,这个方法会使用原生方式复制每个索引元素,比自行使用循环来得快。还有个更为简便的方法,是用Arrays.copyOf()方法,它会自动帮我们建立一个新数组。在java中,数组一旦建立了,长度就固定了。如果事先建立的数组长度不够怎么办?那就只好建立新数组,将原数组内容复制至新数组。参考的行为分为浅层复制和深层复制。在书上106页的例子,实际上循环中仅将c1每个索引处所参考的对象,也给c2每个索引参考,并没有实际复制出Clothes对象,术语上来说,这叫做复制参考,或称这个行为是浅层复制。无论System .arraycopy()还是Arrays.copyOf(),用在类类型声明的数组时都是浅层复制。何为深层复制?就是在实际上c1每个索引参考的对象会被复制,分别指定给c2每个索引。

    四、字符串对象

    1.字符串基础

    在java中,字符串本质是打包字符数组的对象,是java.lang.String类的实例。我们可以使用+运算来连接字符串,如果要将字符串转为整数,浮点数等基本类型,则可参考书上108页的剖析表。

    2.字符串特性

    在java中,为了效率考虑,以“”包括的字符串,只要内容相同(序列、大小写相同),无论在程序代码中出现几次,JVM都只会建立一个String实例,并在字符串池中维护。前面一直强调,如果想比较对象实质内容是否相同,不要使用==,要使用equals()。同样的,如果想比较字符串实际字符内容是否相同,不要使用==,使用equals()。字符串对象一旦建立,就无法更改对象中任何内容,如果使用+连接字符串,会变成建立java.lang.StringBuilder对象,使用其append()方法来进行+左右两边字符串附加,最后再转换为toString()返回。使用+连接字符串会产生新的String实例,这并不是告诉你,不要使用+连接字符串,毕竟+连接字符串很方便,这只是告诉你,不要将+用在重复性的连接场合,因为频繁产生新对象,会造成效能上的负担。我们可以用StringBuilder来解决这个问题。StringBuilder每次append()调用后,都会返回原有的StringBuilder对象,方便你进行下一次操作。这个程序片段只产生了一个StringBuilder对象,只进行一次输出,效能大大提高!

    3.字符串编码

    之前就谈到过,java支持Unicode,所以写下一个英文字符或写下一个汉字字符,都是双字节。JVM在加载.class之后,就是读取Unicode编码并产生对应的字符串对象,而不是最初在原始码中写下的内容。当使用javac指令没有指定—encoding选项时,会使用操作系统默认编码,如果你的文字编译程序是使用UTF—8编码,那么编译时就要指定—encoding为—UTF8。如: > javac -encoding UTF-8 main.java。

    第五章

    一、何谓封装

    1.封装对象初始流程

    有个概念必须理清,定义类并不等于做好了面向对象中封装的概念,我们必须以对象的角度来思考问题!根据书上123页的范例,我们得知如果想存取对象的数据成员,可以通过“.”运算符加上数据成员名称。但每次在建立储值卡对象时,都会做相同的初始工作,这个流程是重复的。更多的对象建立会带来更多的程序代码重复。我们可以通过定义构造函数来解决这个问题。若构造函数的参数与类的数据成员同名了,为了区别,在对象数据成员前加上this关键字。表示将参数的值指定给这个对象(this)的数据成员。如果你的类用户想建立5个对象,并将数据显示出来,可以用数组而无需个别声明参考名称。

    2.封装对象操作流程

    结合书上126页的范例,在CashCard类中,除了定义储值用的store()方法外,你还考虑到扣款用的charge()方法,以及兑换红利点数的exchange()方法。在类中定义方法,如果不用返回值,方法名称前可以声明void。也就是说前面看到的储值重复流程,现在都封装到store()方法中了!可以直接调用。当然就算改变了store()流程,CashCard用户也无需修改程序。为了知道兑换红利点数后,剩余的点数还有多少,exchange()必须返回剩余的点数值,方法若会返回值,必须在方法前声明返回值的类型。在java的命名习惯中,方法名称首字母是小写。

    3.封装对象内部数据

    之前的例子在CashCard类上定义了store()等方法,你“希望”用户照你的意思去撰写程序,这样才可以执行store()等方法中的相关条件检查流程。如果我们的“希望”是一厢情愿怎么办,用户完全可以根据自己的意愿编写代码跳过我的相关条件检查。问题在哪儿?因为没有封装CashCard中不想让用户直接存取的私有数据,用户撰写程序时,就有了自由存取类私有数据的选择,如果有些数据是类所私有,在java中可以使用private关键字定义。如果没有提供方法存取private成员,那用户就不能存取。在CashCard的例子中,如果想修改balance或bonus,就一定得通过store()、charge()、exchange()等方法,也就是说一定要通过你定义的流程。除非你愿意提供方法,让用户可以取得number、balance、bonus的值,否则用户一定无法取得。基于你的意愿,CashCard类上定义了getNumber()、getBalance()、getBonus()等取值方法。取值方法的名称形式是固定的,也就是以get开头,之后接上首字母大写的单词。所以你封装了什么?封装了类私有数据,让用户无法直接存取,而必须通过你提供的操作方法,经过你定义的流程才有可能存取私有数据。封装目的主要是隐藏对象细节,将对象当作黑箱进行操作,就如前面的范例,用户会调用构造函数,但不知道构造函数的细节,用户会调用方法,但不知道方法的流程。

    二、类语法细节

    1.public权限修饰

    之前的CashCard类是定义在cc.openhome包中的,假设现在为了管理上的要求,要将其定义至cc.openhome.virtual包中,除了原始码与位码的文件夹需求必须符合包层级之外,原始码内容也要做一些修改。没有声明权限修饰的成员,只有在相同包的类程序代码中,才可以直接存取,也就是“包范围权限”。如果不同包的类程序代码中,想要直接存取,就会出现错误。如果想在其他包的类程序代码中存取某包的类或对象成员,则该类或对象成员一定是公开成员,在java中要使用public加以声明!这表示它是个公开类,可以在其它包的类中调用。没有定义任何权限关键字的时候,就是包权限。在java中其实有private、protected与public三个权限修饰。如果类上没有声明public权限关键字,类中的方法声明就算是public,也等于是包权限。

    2.关于构造函数

    在定义类时,可以使用构造函数定义对象建立的初始流程。构造函数是与类名称同名,无需声明返回类型的方法。创建对象时,数据成员就会初始化,如果没有指定初始值,则会使用默认值初始化。如果定义类时,没有撰写任何构造函数,编译程序会自动加入一个无参数、内容为空的构造函数,这叫默认构造函数,如果是自己构造的无参数且没有内容的函数,这不叫默认构造函数。

    3.构造函数与重载

    视使用情景或条件的不同,创建对象时也许希望有对应的初始流程。可以定义多个构造函数,只要参数类型或个数不同,这称为重载构造函数。定义方法时也可以进行重载,可为类似功能的方法提供统一名称,但根据参数类型或个数的不同调用对应的方法。比如以String类为例,其valueOf()方法就提供了多个版本,但根据传递的自变量类型不同,会调用对应的方法。

    4.使用this

    除了被声明为static的地方外,this关键字可以出现在类中任何地方。this()调用只能出现在构造函数的第一行。书上137页的范例中说明了这样一个道理,在java中,this()代表了调用另一个构造函数,至于调用哪个构造函数,则视调用this()时给的自变量类型与个数而定。如果撰写了对象初始区块,对象建立之后会先执行对象初始区块,接着才调用指定的构造函数。若有final int x;将x设为默认初始值0,而其他地方不能再对x设值?不对,如果对象数据成员被声明为final,但没有明确使用=指定值,那表示延迟对象成员值的指定,在构造函数执行流程中,一定要有对该数据成员指定值的动作,否则会编译错误。

    5.static类成员

    被声明为static的成员,不会让个别对象拥有,而是属于类。我们也是通过类名称与“.”运算符,就可以取得static成员。我们一直在用的System.in与System.out中的in与out都是static成员。static成员属于类所有,将类名称当作名称空间是其最常使用的方式。正是由于static成员是属于类,而非个别对象,所以在static成员中使用this会是一个语意上的错误。有些情况没有写this,但是隐含了this的意义在里面,因此也会发生编译错误。.class被JVM加载后,默认就会执行static区块。在JDK5之后,新增了import static语法,可以在使用静态成员时少打几个字。我们可以通过import来偷懒,但是别偷懒过头,要注意名称冲突问题,有些名称冲突,编译程序可通过以下顺序来解析:1.局部变量覆盖 2.成员覆盖 3.重载方法比较

    6.不定长度自变量

    在调用方法时,若方法的自变量个数事先无法决定该如何处理,在JDK5之后就可以用不定长度自变量来解决这个问题。要使用不定长度自变量,声明参数列时要在类型关键字后加上...,实际上不定长度自变量是编译程序蜜糖,反编译后明白int...声明的变量实际上展开为数组。方法上声明的不定长度参数必须是参数列最后一个,使用两个以上不定长度自变量也是不合法的。

    7.内部类

    可以在类中再定义类,这称为内部类。内部类可以定义在类区块中。要使用some中的other类,必须先建立some实例,内部类也可以使用public、protected、private声明。内部类本身可以存取外部类的成员,通常非静态内部类会声明为private,这类内部类是辅助类中某些操作而设计的,外部不用知道内部类的存在。内部类也可以声明为static。一个被声明为static的内部类,通常是将外部类当作名称空间。被声明为static的内部类,虽然将外部类当作名称空间,但算是个独立类,它可以独立存取外部类static成员,但不可存取外部类非static成员。

    8.传值调用

    有一些程序语言,像是c++之类,调用方法传递自变量给参数时,可以有传值调用或传参考调用。java中只有传值调用。书上148页的范例清楚的介绍了传值调用是如何进行的。java中的“参考”与c++中的“参考”在根本上是不同的定义,只不过刚好都叫做参考罢了。

    教材学习中的问题和解决过程

    就像我之前所说的,第四章第五章的知识较之前的知识更为复杂抽象难懂,最开始我看第四章的时候搞不懂对象的概念,觉得太抽象了,包括其中的this.color=color,我不知道左右两边的color各是什么意思。不过遇到难题,我当然不会放弃,要想办法努力克服!不懂的知识点我看了一遍看两遍,如果还不懂就上网查或翻阅参考书。最终我将所有知识点的思路都理清了。比如之前这个问题,其实左边是对象成员,右边是参数,表明color这个对象成员能够拥有color参数的个别值! 学习第四章第五章,最重要的是要有能将抽象问题具体化的能力,将其建立成一个模型,这样才能方便理解。

    代码调试中的问题和解决过程

    调试代码过程中确实遇到一点小问题,不过都是浮云,经过自己的修改,最终都能成功运行!! 以下将展示各类托管代码(只是一部分):

     

    其他(感悟、思考等,可选)

    其实感觉这周的学习量挺大的,要自学两个章节,而且都是比较陌生抽象难懂的知识,接受起来比较慢。
    从最开始的java平台概论,JDK到IDE的介绍,基础语法的运用到现在的类与对象,封装。前三章的知识其实都不是特别难。但到第四章就感觉逐渐接触java程序设计的核心知识了。于是调整了一下自己的心态,用了差不多一周晚自习的时间将第四章和第五章完完整整仔仔细细的看了三遍,每一遍都有新的体会与感悟,又用了星期六一天的时间再回过头来复习再思考再记录,不断有新的收获。真的是熟能生巧,其实现在看来,第四章与第五章的知识也不过如此,最开始觉得难是因为对知识点不熟,陌生。在经过不断的重复后,我对这两章的知识点已经掌握了,把书上的代码又都敲了一遍。世上无难事,是怕有心人。任何事情,万事开头难,但只要坚持下来了,一定会受益匪浅!!比如托管代码,最开始觉得很难,学会了后就太轻松了。

     

    学习进度条

      代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
    目标 3500行 20篇 300小时  
    第一周 120/120 1/1 14/14  
    第二周 340/460 1/2 14/28  
    第三周 200/660 1/3 14/42 学会托管代码,学会了构造模型的方法来了解类与对象这部分的知识。
    第四周        
  • 相关阅读:
    Docker 介绍
    Docker 教程
    Python 删除文件与文件夹
    Python 读文件
    Python 打开文件(File Open)
    Python 异常处理(Try...Except)
    什么是拜占庭将军问题
    智能合约语言 Solidity 教程系列7
    给代币添加高级功能-代币管理、增发、兑换、冻结等
    一步步教你创建自己的数字货币(代币)进行ICO
  • 原文地址:https://www.cnblogs.com/cxy1616/p/5297176.html
Copyright © 2020-2023  润新知