您的位置:首页 > 编程语言 > Java开发

《Java程序设计》第四章-认识对象

2016-02-22 16:36 447 查看

20145221《Java程序设计》第四章-认识对象 总结

教材学习内容总结

类与对象

定义:对象是Java语言中重要的组成部分,之前学过的C语言是面向过程的,而Java主要是面向对象的。Java中变量有2种类型,一个是基本类型,另一个则是类类型。使用Java撰写程序几乎都是在使用对象,要产生对象必须先定义类,类是对象的设计图,对象是类的实例。

特点:

有别于C语言的程序编写,在用Java编写中,如果需要什么功能,我们就可去找一个对象,而这个对象就包含这个功能,然后通过new建立对象,通过“.”来调用该类的一些功能。

其中要能理解对象的含义,例如
Clothes c1 = new Clothes();
,其中c1是在栈内存中产生,而对象c1则是产生在堆内存中,c1可以近似看成指向堆内存中的指针。

书上提供了一个很好的方法正确理解其中的本质,那就是画图,形象又直观,所以在涉及对对象的理解时,一是可以画图,二是可以把相关代码贴在电脑上运行一下。还有一些常用的标准类Scanner,BigDecimal等都大大方便了我们编程过程。

注意:对象相等性,首先要明白对于类类型的变量来说==和基本类型中的==有本质上的区别,因为是类类型,所以==表示的是这个类产生的2个对象是否是同一个对象,如果是同一个对象,那么==的返回值才是true,否则为false;如果想要比较2个对象的内含值,应该要用
a.equals(b);
。其实理解其最好的方法就是画图,例如课本P89页中的代码,以及后面相关知识的介绍,都是通过画图来理解的。

基本类型打包器

概述:在上一章已经学习了基本类型的变量,但是对于Java程序语言来说,基本类型的变量效率往往不高效,Java的特点在于面向对象,所以我们也可以把这些基本类型的变量打包成对象之中,这样我们就可以像操作对象那样操作这些原本是“基本类型”的变量了。

特点:

开始在学习这一节内容的时候,不能理解,明明是基本类型了,为什么还要把大费周章地又打包成类类型。在最后编写本章的操作题时,我就明白了,编写Java时一定要把固有的“面向过程”的思想转化为“面向对象”,对象可以提供我们许多功能,简化我们的编程,这在后续学习中会更加明白。

除了打包,J2SE 5.0之后,还能自动装箱、自动拆箱,在我的理解看来,就是不需要严格的像一般建立对象那样,可以简便一些(自动装箱与拆箱的功能事实是编译程序蜜糖),例如:

Integer wrapper = 10;    // 自动装箱
int foo = wrapper;       // 自动拆箱


注意:既然打包为了对象,当然也要满足对象的特点,尤其是判断“相等”。作为编程者,一定要弄明白我们的目的。在建立对象之后,如果是想比较这2个对象的内含值,则一定一定要使用
a.equals(b);
这种形式的比较方式,只要把握了这一点,就可以避免课本P97这样的错误。

数组对象

概述:数组在Java中就是对象,牢牢把握这个概念。

特点:对象的一些特点性质都可以在数组中使用。定义数组的方法,如果知道是哪些具体的数,则可以如课本P95一样,不知道具体的数可以像P98一样。在定义二维数组时,也可以仿照一维数组进行定义,总之,数组就是对象,这是数组最大的特点。

注意:

既然数组是对象,那么对象需要注意的性质,数组都要注意。对于数组本身来说,不能超过其索引范围,不然会报错:ArrayIndexOutOfBoundsException(编译时不会报,运行时会报错)。

注意各种类型的数组初值情况(课本P98)。

再就是要理解二维数组的本质,二维数组,其实是在数组的基础上对于每个元素,再建立一个数组(对象),只是在很多编程实例中体现出了“二维”、“矩阵”等形式,本质还是在数组的每个元素上再建立数组。认识到这一点,加上课本的图4.5、4.6、4.7、4.8理解起来就容易多了。

数组的复制,首先由2个方法可以用System.arraycopy()Arrays.copyof(),可以通过这些类快速复制一个数组,不过在调用时要注意括号中参变量的含义,类型内容都要一致。在使用了上述方法后,要明白一点我们进行的都是“浅层复制”,是没有连同对象一起复制的。如果想要深层复制,则需自己操作,敲代码完成自行复制元素,如课本P106。

字符串对象

概述:字符串本质是打包字符数组的对象,是java.lang.String类的实例。

特点:既然是对象,当然也会有很多功能,length(),charAt(),toUpperCase()等。通过一些方法Byte.parseByte(number)等还可以将字符串剖析为基本类型。

注意:

字符串池:如果直接将一串字符指定给2个字符串变量,则这2个字符串变量会参考到同一对象。因为在Java中,为了效率考虑,只要""包括的字符串内容相同,无论在程序代码中出现多少次,JVM都只会建立一个String实例,并在字符串池中维护。

不可变动字符串:必须知道的是:在Java中,字符串对象一旦建立,就无法更改对象中的任何内容,对象上没有任何一个方法可以更改字符串内容。使用+字符可以达到这样的效果,不过根据反编译的过程,可以发现,实际上是产生了新的字符串对象。而大量的产生新对象又是不希望看到的,所以我们可以用StringBuilder来改善,它的特点在于每次调用完后都会返回原有的StringBuilder对象,这样可以避免产生多个对象。

查询Java API文件

概述:从本章的实际操作题和课本上的范例程序中,都会发现每个程序几乎都使用了不同的类,如java.util.Scanner、java.math.BigDecimal、基本类型打包器等等。在以后的编程中,如果我们想用某一个类的某一功能,但不知道如何调用,或者想了解一下某一个类具体有哪种功能等内容,就必须要通过查询Java API文件了。

方法:

通过Java官方网站

直接通过搜索引擎搜索相应的类,就会显示对应的文件说明了;

以上2种方法都是在线查询Java API文件,还可以离线查询。在Windows下可以下载CHM格式的Java API。如图,这样会更加的方便。



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

其实这一章内容开始不是很好理解,因为之前对对象没有一个概念。所以学的有点慢,但是按照老师说的方法,一个是认真看课本,另一个就是学编程必须要养成的习惯,勤敲代码。可能开始对书上给的一些代码,还不能理解,面对书上画的图,也不能透彻明白。但是好记性不如烂笔头,编程也一样,只要把这些代码敲一遍,编译运行一编,看看结果,这样印象可能会深一点,对于代码的领悟可能更也更好一些。

在最开始接触对象时,有一种感觉就是感觉“类”有点似曾相识,感觉和C语言中的结构体很像。不过我知道C语言是面向过程的,Java是面向对象的,所以我认为结构体和类还是应该有本质区别的。翻开原来的C语言书,发现结构体好像只是把不同类型的变量打包在了一个“新的类型变量中”,并不能在结构中定义功能,而类中还可以构造函数。类的功能应该更强大更灵活。

按照老师的指导,对书中P112的效率进行了测试:

(1). 代码(只展示第一种,后两种只是将“测试代码段”用课本上的填充进去):

public class TestJavaClass{
public static void main(String[] args){
//获取开始时间
long startTime = System.currentTimeMillis();
//测试代码段
for(int i=1; i<101; i++){
System.out.print(i);
if(i != 100){
System.out.print('+');
}
}
System.out.println();
//获取结束时间
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
}
}

(2). 运行结果:

第一种:



第二种:



第三种:



(3). 结论:通过上述操作,确实可以发现第三种的效率最高。

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

课后操作题

Fibonacci数列:

代码:

import java.util.Scanner;

public class Fibonacci{
public static void main(String[] args){
System.out.printf("求几个费氏数?");
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
if(n == 1)
System.out.print(0);
else{
int[] fiboNums = new int
;
fiboNums[1] = 1;
System.out.print(0 + " " + 1);
for(int i=2; i<n; i++){
fiboNums[i] = fiboNums[i-2] + fiboNums[i-1];
System.out.print(" " + fiboNums[i]);
}
}
System.out.println();
/*
fiboNums[1] = 1;
for(int i=2; i<n; i++){
fiboNums[i] = fiboNums[i-2] + fiboNums[i-1];
}
for(int fiboNum : fiboNums){
System.out.print(fiboNum + " ");
}
System.out.println();
*/
}
}


运行结果:



结论:第一次编译该程序的时候出现了乱码,可能跟我这个代码要打印汉字有关吧。经过查找了相关资料,只要在编译时输入
-encoding utf-8
即可解决。斐波那契数列不算难,不断迭代就可解决。程序中被注释的代码是最开始编的,最后想到也可以用一个for循环解决,不过感觉2个for循环看起来结构更清楚一些,可读性更强一些。

洗牌:

代码:

public class Shuffle{
public static void main(String[] args){
String[] pokers = {
"梅1","梅2","梅3","梅4","梅5","梅6","梅7","梅8","梅9","梅10","梅J","梅Q","梅K",
"砖1","砖2","砖3","砖4","砖5","砖6","砖7","砖8","砖9","砖10","砖J","砖Q","砖K",
"桃1","桃2","桃3","桃4","桃5","桃6","桃7","桃8","桃9","桃10","桃J","桃Q","桃K",
"心1","心2","心3","心4","心5","心6","心7","心8","心9","心10","心J","心Q","心K"
};
//定义一个0-51的随机数(不重复)数组。
int[] numbers = new int[pokers.length];
//赋初值,简化判断是否有重复随机数的循环次数。
for(int i=0; i<pokers.length; i++){
numbers[i] = -1;
}
int num;
boolean flag;
for(int i=0; i<pokers.length; i++){
//产生随机数。
while(true){
flag = true;
num = (int) (Math.random() * pokers.length);
//凡是搜索到了-1就表示已经搜索完毕。
for(int j=0; numbers[j]!=-1 ;j++){
if(numbers[j] == num){
flag = false;
break;
}
}
//不重复,就向随机数数组中赋值。
if(flag){
numbers[i] = num;
break;
}
}
}
/*
调代码时用到,用以判断是否成功生成了0-51的不重复随机数。
for(int number : numbers){
System.out.print(number + " ");
}
System.out.println();
*/
for(int i=0; i<pokers.length; i++){
System.out.printf("%-4s",pokers[numbers[i]]);
if((i+1)%13 == 0)
System.out.println();
}
}
}


运行结果:



结论:拿到这个题目,想了一会,考虑怎样才能让52张扑克牌随机输出。最后想到了可以用随机数产生的方法,0-51个随机数对应的其实就是“扑克牌数组”的角标,因为角标的随机,实现了出牌的随机。当然因为编写不熟悉,输出的扑克牌有重复的,为了能更加看清楚随机数(不重复)是否成功产生,打印了52个随机数(代码中被注释的片段)。最后发现过然是随机数产生有问题,逆推回去,发现了第二个for循环中判断的条件原来写的是“numbers[j]!=0”,当时的想法是如果碰到0了,说明已经搜索完了(int型数组默认赋初值为0),不用往后搜了,但是忽略了一点,产生的随机数也含有0,如果采取这样的方法判断,就会出现重复的情况。所以在前面加了一句,将数组中的元素赋初值为1。最后打印时发现,“梅10”“心10”等这4张牌多占一个字符的宽度,所以为了打印美观,将输出格式控制为%-4s

排序:

代码:

import java.util.Arrays;

public class BubbleSort{
public static void main(String[] args){
int[] number = {70, 80, 31, 37, 10, 1, 48, 60, 33, 80};
/*
冒泡排序代码:
int temp;
for(int j=0; j < number.length-1; j++){
for(int i=0; i < number.length-1-j; i++){
if(number[i] > number[i+1]){
temp = number[i];
number[i] = number[i+1];
number[i+1] = temp;
}
}
}
*/
Arrays.sort(number);
for(int num : number){
System.out.printf("%3d",num);
}
System.out.println();
}
}


运行结果:



结论:排序题其实在C语言中也接触了不少,代码中被注释的片段用到的就是冒泡排序,可以说比较简单高效。但因为Java面向对象的特性,可以用
Arrays.sort(number);
,一句代码,直接将原来的数组从小到大排列,更加简单。既然再学Java,就要多使用对象,这样可以提高编程技能和效率。

查询:

代码:

(1)产品代码:

import java.util.Scanner;

public class Search{
public static void main(String[] args){
int[] number = {1, 10, 31, 33, 37, 48, 60, 70, 80};
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
System.out.println(binary(number,num));
}
public static int binary(int[] array, int value){
int low = 0;
int high = array.length - 1;
int middle;
while(low <= high){
middle = (low + high) / 2;
if(value == array[middle])
return middle;
if(value > array[middle])
low = middle + 1;
if(value < array[middle])
high = middle - 1;
//  System.out.println(middle);
}
return -1;
}
}

(2)测试代码:

public class SearchTest{
public static void main(String[] args){
int[] number = {1, 10, 31, 33, 37, 48, 60, 70, 80};
if(Search.binary(number,1) != 0)
System.out.println("test failed 1!");
else if(Search.binary(number,10) != 1)
System.out.println("test failed 2!");
else if(Search.binary(number,31) != 2)
System.out.println("test failed 3!");
else if(Search.binary(number,33) != 3)
System.out.println("test failed 4!");
else if(Search.binary(number,37) != 4)
System.out.println("test failed 5!");
else if(Search.binary(number,48) != 5)
System.out.println("test failed 6!");
else if(Search.binary(number,60) != 6)
System.out.println("test failed 7!");
else if(Search.binary(number,70) != 7)
System.out.println("test failed 8!");
else if(Search.binary(number,80) != 8)
System.out.println("test failed 9!");
else if(Search.binary(number,0) != -1)
System.out.println("test failed 10!");
else if(Search.binary(number,40) != -1)
System.out.println("test failed 11!");
else if(Search.binary(number,100) != -1)
System.out.println("test failed 12!");
else
System.out.println("test passed!");
}
}


运行(测试)结果:



结论:二分法之前也接触过,这次将其运用到了Java程序中。根据毕老师的视频,学到了自定义函数的一些皮毛,就尝试着用函数的功能编写了一个可以查找数组中某个数的方法。其实这一点跟C语言中的知识比较类似,同一个类中,最多只允许一个main函数,它是代码的入口,执行代码先找main函数,先执行main函数;自定义的函数也和原来学的差不多,注意形参的类型个数,注意函数类型、有无返回值等情况。

其他

之前就听说过面向过程、面向对象,但不知道具体指的是什么。经过这一章的学习,要把面向对象这个观念牢记心中,这是区别C语言等其它面向过程语言的不二法宝。

对于对象的理解还要更加加深理解,要在平时的编程练习中巩固加强。熟能生出百巧来,只有熟练了,才能提高自己的编程技术,理清自己的编程思路,升华自己的编程思想。

参考资料

《Java JDK8 学习笔记》 2015年3月第1版 ——林信良

《Java学习笔记(第8版)》学习指导

中文编码转换——6种编码30个方向的转换

实验二 Java面向对象程序设计
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: