java核心技术(第十版卷一)笔记

java核心技术(第十版卷一)笔记

这是我读过的第三本关于java基础的书.第一本<<java从入门到精通>>这本书让我灵识初开.第二本<<java敏捷开发>>这本书则是一次被一位师傅批评基础太差时读的.今日一位我向一位前辈请教应该怎样在进步一些.前辈推荐我读<<Java核心技术>>并告诉我,先读了这两本查漏补缺,然后在给我推荐进阶的书.工具书这种东西,每一本都不可能相同,比如我们的数学书,同样是小学的,两个地区的书可能就不同.

一下为这本java核心技术中所积累的知识,仅为记录笔记

--------------------------------------------------------------------------------------------------------

自动类型转换
两个数值.如果有double,则转换成double.否则有float,转换成float.否则有long,转换long.否则都转换成int

类之间的关系
依赖(uses-a):A类依赖B类.A类需要调用B类
聚合(has-a):A类包含B类.
继承(is-a):A类继承自B类.A类包含B类的属性行为,以及有自己的属性和行为

对于方法参数
其实是有一个隐藏的参数,就是this.表示当前的调用对象,而静态方法中,则不存在this.因为静态方法不依赖实例对象

final修饰类的原则
如果一个类的内部,没有提供可修改类本身状态的方法.则可将该类设为final(被final修饰的类不可以被继承,如果你继承了一个final类,则代表你可以自定义方法修改final类的属性,其破坏了封装性.这个坑在某个面试中,被坑了....)

java的参数统一是按照值传递的.基本数据类型传递的值的副本.所以方法内部对参数进行的修改,不会影响实参.
public class Person {
    public int age = 1;
}
public class Test {
    public static void main(String[] args) {
        int y = 1;
        change(1);
        System.out.println(y);//1
        Person p = new Person();
        change(p);
        System.out.println(p.age);//2
        change2(p);
        System.out.println(p.age);//2
    }

    public static void change(int x) {
        x = 2;
    }

    public static void change(Person p) {
        p.age = 2;
    }

    public static void change2(Person p) {
        p = new Person();
        p.age = 3;
    }
}

以上例子可以看出当我们传递一个基本数据类型参数,方法中的改变不会更改原有的值.这个对于上边的法则是能对于的.但是我们传递一个引用类型得到实参,则有了令人产生歧义的结果.实际上,这个结果是很迷惑人的(起码在一段长的时间,我也没有真正搞懂上边规则的真正意思.)我们先来看change2()这个方法,这个方法内部,对传入的实参重新new了一个对象,也就是说,当前方法中的p已经被重新实例化了.所以,当你把新的实例化的对象中的属性域修改了值,那么根据以上的法则,当然不会影响main()方法的实参.再来看,change1()的内部构造,他直接将实参对象的一个属性域的值修改了,结果竟然映射到了,main()方法中.这岂不是有悖于以上法则?其实不然,我们可以追溯到基本数据类型,当一个int i = 1;被创建则 1  已经被分配了内存空间.我们我们将 i = 2 那么  i 只是换了一个应用值2,实际的1还是存在的(这里我们暂且不考虑垃圾回收)话题回来,我们在change()中修改了实参的一个属性,那么这个实参的实际存储地址变了吗?没有的.而change2()则是直接新建了一个对象,新开辟了一片内存,你在新的地址里更改自己的属性,当然也不会影响实参的属性.(ps关于这类的问题,我曾经看过很多形参,实参,传值,传址之类的博客,其实看得越多,越迷糊.如果你看到以上我的描述,觉得没有茅塞顿开那么就请忘掉他.避免对你造成更大的困扰)

关于构造函数

在一个类中,如果有成员 int i; 而改成员没有值.则会在new出该对象实例时,赋值为0;这个动作原来是在构造函数执行的.数值类型被默认为0,Boolean被默认为false,引用类型被默认为null.

关于final

如果一个class被声明为final,那么其所有的方法也默认被设置为final,而字段则不在final中.被final修饰的类主要目的还是阻止其他类通过成为其子类的方式而修改本身类的行为.

equals特性

1 自反性: 对于任何非空引用x,x.equals(x);应当返回true.

2 对称性: 对于任何引用x和y,当且仅当y.equals(x);返回true,x.equals(y);也应当返回true.

3 传递性: 对于任何引用x,y,z如果x.equals(y)返回true; y.equals(z)返回true;那么x.equals(z);应当返回true

4 一致性: 如果x和y的引用对象没有发生变化,返回调用x.equals(y);应当返回同样的结果.

5 对于任意非空引用 x,x.equals(null);应当返回false.

关于包装类型Integer

对于包装类型我们大家都熟悉.对于以下操作我们则是使用了包装类型的特性:自动装箱.自动拆箱

public static void main(String[] args) {
        Integer i = 100;
        i = i + 1;
        System.out.println(i);
    }

这里有个对于自动装箱有个值得思考的问题,如果两个相同的数值用==判断,如果数值相同,则返回true.那么如果将这两个数值装箱为Integer还能用==判断吗?

    public static void main(String[] args) {
        Integer i = 1000;
        Integer x = 1000;
        System.out.println(i == x);//false

        Integer z = 100;
        Integer y = 100;
        System.out.println(z == y);//true
    }

i 和 x 的==判断是我们意料之中的.两个对象 == 如果地址不同肯定是false嘛!那么 z 和 y呢?

书中的解释

自动装箱规范要求 booleanbytechar 127, 介于 -128 ~ 127 之间的 shortint 被包装到固定的对象中。

但是需要注意的如果我们显式的创建两个Integer可不会有这个特性.

  public static void main(String[] args) {
        Integer i = 127;
        Integer x = 127;
        System.out.println(i == x);//true

        Integer z = new Integer(127);
        Integer y = new Integer(127);
        System.out.println(z == y);//false
    }

另外这里还有一点.之前我们说,当向一个方法传递引用类型的实参时,我们是有可能修改这个实参的属性的.那么我们来看这个

 public static void main(String[] args) {
        Integer i = new Integer(1);
        change(i);
        System.out.println(i);//1
    }

    public static void change(Integer i) {
       i = i.valueOf(2);
       i = 3;
    }

白日做梦~~~~怎么可能会让你修改一个基本类型的值呢.~~~~~