《Head First Java》读书笔记(1)

“head first java”的图片搜索结果
《Head First Java》(点击查看详情

1、写在前面的话

这本书的知识点说实话感觉有点散乱,但是贵在其将文字转换成了生动和更容易接受的图片,大量的比喻让人感受到了知识点的有趣之处,让学习不再那么枯燥无奈。

掌握了Java的一些基础之后,现在回过头来再看这本书,依然觉得收获颇丰,于是便把那些让人印象深刻的地方记录下来,总结、思考和分享,出于精力和效率,这里就不再细致地去罗列和整理每个知识点了(作为强迫症不得不说真的有过这样的想法,可是想着未来还有好多书要看,每本都流水一样地写,我得把自己弄疯掉)。

2、类与对象

类和对象到底有什么区别?类,其实就是用来创建对象的模型女娲造人,只需要知道是有胳膊有腿的人类就好了(类),至于捏出来的是帅哥还是美女,高大还是矮小,那又是另一个概念了(对象)。

3、认识变量

Java中的变量有两种类型:primitive主数据类型(即我们常说的基本数据类型)和引用(引用数据类型)。不论是哪种数据类型,在Java面前都要求严格遵守它的管理规则,不允许类型之间的胡乱转换,比如是绝不会允许把长颈鹿类型变量放进兔子类型变量中去。接下来,我们就来分别认识这两种数据类型,和他们之间的一些变换规则。

3.1 主数据类型(基本数据类型)

变量就像杯子,不同的数据类型,往往代表了它们杯子不同的大小容量。这个大概是我目前认识到的最有意思又贴切的比喻了,因为这生动地让我明白了类型之间的转换意义。

我们都知道,基本数据类型之间的运算是存在类型转换的,特别是自动转换,其实在运算时有以下规则(由低到高转换):
  • 所有的byte、short、char型的值将被提升为int型; 
  • 如果有一个操作数是long型,计算结果是long型; 
  • 如果有一个操作数是float型,计算结果是float型; 
  • 如果有一个操作数是double型,计算结果是double型。

顺便来看道题吧:
//下列代码片段中,存在编辑错误的语句是? 
byte b1=1,b2=2,b3,b6,b8;
final byte b4=4,b5=6,b7;
b3=(b1+b2);  /*语句1*/
b6=b4+b5;    /*语句2*/
b8=(b1+b4);  /*语句3*/
b7=(b2+b5);  /*语句4*/
System.out.println(b3+b6);
答案是语句1、3、4(更多请戳链接

就像书中所说的一样,编译器是为了确保变量能存下所保存的值就像你小杯的茶叶和大杯的茶叶倒进另外一个杯子里,那么为了避免溢出来,自然这另一个杯子要选择大的


3.2 对象引用(引用数据类型)

Dog dog = new Dog();
如上,我们都知道基本数据类型的变量,而实际上,是没有对象变量这种说法的,只有引用到对象的变量。也就是说,这里的dog,并不是对象的容器,而是类似指向对象的指针,或者说是地址(如果你还不明白,你可以想象真正的对象是一个宾馆房间,而这里的变量就是对应的房间号门卡)

之前我们比喻说,基本数据类型是大小不同的杯子,而这里,实际上是没有超巨大的被子来装载对象的,对象只会存在于可回收垃圾的堆上。

 
虽然没有杯子可以承载直接的对象,但是还是可以用来放“遥控器”的,你要记住的是,对象本身并没有放进变量中,而是放入了可以远程控制对象的遥控器


所以,当我们使用数组,它自身就是非基本数据类型,而当里面存入的是我们口中的其他“对象”时,它实际上是这样的:
引用指向了一个对象,这个对象中装满了引用们,这些引用们再最终会指向真正的对象。

好的,那么说到这里,既然我们只是存放了引用,那么那些真正的对象,假如没有对它的引用,会怎么样呢?
事实上,对于没有引用的对象,最终会被标记为垃圾,因为没有引用意味着我们不再会去使用它了,所以在一定时候它就会被Java虚拟机回收清理掉。

3.3 实例变量与局部变量

需要注意的是:
  • 实例变量有默认值(不论你赋值与否):e.g. booleans --> false; references --> null; integers --> 0
  • 局部变量没有默认值,如果在初始化之前就想使用,编译器就会报错

4、方法的使用

Java中的方法参数是通过值传递的,也就是说是通过拷贝传递
值得注意的是,我们之前提到的所谓”对象变量“实际是引用,是遥控器,所以如果传入参数是对象,实际上也就是拷贝了引用,所以对于对象引用作为参数来说,往往我们在方法中的操作会改变真正对象的值,而基础数据类型则不会。

看看下面这个题目,最终会输出什么?

public class Test {
    //属性
    int a = 11;
    char[] ch = {'n', 'b'};

    //方法
    public void change(int a,char ch[]) {
        a = 99;
        ch[0] = 's';
    }

    //测试
    public static void main(String args[]) {
        Test test = new Test();
        test.change(test.a, test.ch);
        System.out.println("test.a = " + test.a);
        System.out.println("test.ch = " + test.ch[0] + test.ch[1]);
    }
}

对于基本数据类型,拷贝过去对原来的属性没有影响,最终还是11;
对于引用数据类型,传递的是复制的遥控器,在方法中远程更改了真正的对象,所以输出不是nb,而是sb
 

5、数据封装

为了更好地隐藏我们的数据,我们往往要在实例变量的修饰符使用private,这意味着外界的其他类无法使用例如dog.size = 9;的方法进行控制和篡改。我们需要建立setter,强制要求所有方法通过setter来设定变量而不是直接存取,这样我们就可以进行一些条件限制,比如身高我们在setter中可以限制其不能为负数,但是如果是public int height,那就难以控制了。

但是众所周知,我们常见的private类型的变量,实际上在getter和setter中并没有设定什么特殊的动作,就是说,感觉像是多此一举,只是把变量传给了值而已。可是,它的真正的好处在于,万一某天你发现这个变量需要检查,你只需要更改一下getter或setter,并不影响其他的代码。想象一下你使用public的方式伺候了一大堆变量,突然因为需求变更要求该变量必须在一定的范围内,你岂不是要修改成吨的代码?可怕。 



原文地址:https://www.cnblogs.com/deng-cc/p/6507528.html