Thinking in Java 笔记

Thinking in Java 笔记

1.oop:Object Oriented Programming 面向对象的程序设计

2.每个对象在内存中都有唯一的地址

3.类描述了具有相同特性(属性)和行为(方法)的对象集合

4.程序员的目的,创建(或者最好实在现有代码库(Github)中寻找)能够提供理想的服务来解决问题的一系列对象

5.如何分析一个对象:例如,加入你正在创建一个薄记系统,那么可以想象,系统应该具有某些包括了预定义的薄记输入屏幕的对象,一个执行薄记计算的对象集合,以及一个处理在不同的打印机上打印支票和开发票的对象。也许上述对象中的某些已经存在了,但是对于那些并不存在的对象,他们看起来像上面样子?他们能够提供那些服务?他们需要那些对象才能旅行他们的义务?

6.提高对象的高内聚性:例如,在检查打印模式的模块中,你可以这样设计对象,一个对象可以是所有可能的支票排版的目录,可以查询如何打印一张支票的信息;另一个对象可以是通用的打印接口,知道有关所有不同类型的打印机信息(可能是github有的接口了);第三个对象通过调用另外两个对象来完成打印任务。–就像这样,不仅允许通过购买获得对象那个,还可以创建能够在别处服用的新对象。

7.Java封装性的意义在于隐藏实现细节,隐藏的部分通常是程序内部脆弱的部分,很容易被粗心的不知情的程序员破坏,因此隐藏起来可以减少程序bug。

8.多态的好处:把一个对象不当做它所属的特定类型对待,而是当做是父类(基类),这样添加新的子类可以轻松拓展设计的能力,降低软件维护的代价。

9.对象(电视 new Tv())在堆上创建;对象的引用(遥控器 Tv tvController)在栈上创建;基本类型是直接将变量值存储在栈中

10.Java的容器(List,Map,Set):①不同容器提供了不同类型的接口和行为,某些容器提供的解决方案比其他容器灵活多了。②不同容器的某些操作有不同的效率。ArrayList和Linklist都是有相同的接口和外部行为的简单序列,但Arraylist随机访问元素是花费固定时间的操作,而Linklist随机取元素需要在列表移动,代价高,访问越尾的元素花费时间越长;而如果想在序列中间插入一个元素,Linklist开销比Arraylist小,因为Linklist只要改后一个元素的指定地址就能插入元素,而Arraylist要把插入位置后面的元素全部移项,花费高。我们可以一开始用Linklist构建程序,而在优化系统性能改用Arraylist。

11.泛型是为了解决向下转型(父类转子类)时转了错误的类型,而出现的运行时错误而设计的。

12.当一个对象存入容器的时候,他们会向上转型为Object类存入,但传出的时候,编译器是无法知道他传进来的时候是什么类型哦。(解决方法,加入泛型)

ArrayList<Shape> shapes = new ArrayList<Shape>();

13.对象的创建和生命周期(p13)–为什么选择Java?

14.必须由你创建所有对象(p22讨论 堆栈 堆 寄存器 等等概念)

15.BigInteger和BigDecimal用于处理高精度大数,牺牲速度换精度。

16.在花括号内定义的对象引用和对象,对象引用的作用于在花括号内,但对象会继续存在,需要通过垃圾回收期清理。

17.全局和静态的基本成员有初始值,局部变量可能是任意值,如果不赋值,有编译错。

18.Java参数的传递是值传递。

我们把对象传给方法里的形参,实际上我们相当于执行了copy()给新的引用,两个引用都指向了同一个地址,在方法中我们改变形参的值,实际上我们再次把形参指向新的地址,现在,这个地址发生的改变,不会影响到原来地址吧。如果你网上看到有人举了一个“引用传递”的例子,而且看起来“正确”,你可以从内存的角度,考虑一下为什么正确,正确了真的会影响到值传递这个事实吗?其实不然~

19.基本类型的初始值如int为0,boolean为false,而包装类型的初始值为null

20.有了基本类型为什么还要有包装类型呢?

我们知道Java是一个面相对象的编程语言,基本类型并不具有对象的性质,为了让基本类型也具有对象的特征,就出现了包装类型(如我们在使用集合类型Collection时就一定要使用包装类型而非基本类型),它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

另外,当需要往ArrayList,HashMap中放东西时,像int,double这种基本类型是放不进去的,因为容器都是装object的,这是就需要这些基本类型的包装器类了。

21.静态方法其实与它的类无关。

22.static关键字,为了使被它修饰的事物,脱离于其任何对象实例存在,所以不需要创建对象就可以调用静态方法。

23."+"意味着''字符串连接'',如果必要,还有''字符串转换''

24.equals不适用与基本类型,因为是Object的方法,基本类型没有父类。

public void test4() {
        Integer a = new Integer(47);
        Integer b = new Integer(47);
        System.out.println(a == b);//地址不相等,false
        System.out.println(a.equals(b));//equals被重写了,值相等,true
    }

25.java不支持goto,但仍然是保留字。

26.父子初始化速度比较:父类静态代码块>子类静态代码块>父类构造方法>子类构造方法(构造器默认其实是静态方法)

27.区分重载:参数 顺序or数量or类型 的不同(顺序一般不用,会让代码难以维护)

28.返回当前对象的引用

Person walk(){
    return this;
}

28.垃圾回收器只会回收new分配的内存,而其他内存它不知道如何处理。java允许类中定义一个名为finalize()的方法,在垃圾回收准备释放对象占用的储存空间前,先调用finalize()方法,并在下次垃圾回收动作时,才真正回收对象占用的内存。

对象可能不被垃圾回收
垃圾回收并不等于"析构"("析构"是c++的概念)
垃圾回收至于内存有关

29.如果一直到程序执行结束,垃圾回收器都没有释放任何对象的储存空间,则随着程序的退出,那些资源也会全部交还给操作系统,因为垃圾回收本身也要开销,不使用,就不用支付这部分开销。

30.finalize()不是进行普通清理工作的合适场所

finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。
finalize()与C++中的析构函数不是对应的。C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性
不建议用finalize方法完成“非内存资源”的清理工作,但建议用于:① 清理本地对象(通过JNI创建的对象);② 作为确保某些非内存资源(如Socket、文件等)释放的一个补充:在finalize方法中显式调用其他资源释放方法。其原因可见下文[finalize的问题]

31.无论是"垃圾回收"还是"终结"都不保证一定发生,如果Java虚拟机并未面临内存耗尽的情形,他是不会浪费时间去执行垃圾回收以回复内存的。

32.静态数据初始化

public class StaticInitialization {
    /**
     * 
     * @Title: 静态数据的初始化   
     * @Description: TODO(复杂的跳转初始化)       
     * @return: 
     * 结论1:按顺序初始化 static 变量/对象 -> 执行主(static)方法 
     * 结论2:用构造函数new一个对象时 -> 先初始化改对象所在类的 static 变量/对象 -> 再执行构造(staitc)方法
     * 结论3:static 变量/对象 只会初始化一次(首次生成这个类的对象时,或者首次访问属于那个类的静态数据成员时)
     */
    public static void main(String[] args) {
        System.out.println("Create new Cupboard() in main");//11
        new Cupboard();//12
        System.out.println("Creating new Cupboard() in main");//16
        new Cupboard();//17
        table.f2(1);//21
        cupboard.f3(1);//22
    }
    static Table table = new Table();//0
    static Cupboard cupboard = new Cupboard();//5
}
class Bowl{
    Bowl(int marker) {
        System.out.println("Bow("+marker+")");
    }
    void f1(int marker) {
        System.out.println("f1("+marker+")");
    }
}
class Table{
    static Bowl bowl1 = new Bowl(1);//1
    Table(){
        System.out.println("Table()");//3
        bowl2.f1(1);//4
    }
    void f2(int marker) {
        System.out.println("f2("+marker+")");
    }
    static Bowl bowl2 = new Bowl(2);//2
}
class Cupboard{
    Bowl bowl3 = new Bowl(3);//8,13,18
    static Bowl bowl4 = new Bowl(4);//6
    Cupboard() {
        System.out.println("Cupboard");//9,14,19
        bowl4.f1(2);//10,15,20
    }
    void f3(int marker) {
        System.out.println("f3("+marker+")");
    }
    static Bowl bowl5 = new Bowl(5);//7
}

33.构造器的出现,保证了正确的初始化和清理,有了完全的控制,也就安全了。

34.package关键字的出现,是为了让编译器知道我们跟其他包的位置差异,这样public/protect/private才能限制访问权限。

35.package语句必须是文件中的第一行非注释程序代码。(不一定要在line1哦)

36.当编译器遇到import语句时,会在CLASSPATH里面找import后面的包名,然后从已编译的文件中找出名称相符者。

37.如果你import的两个包邮同名的class,这就存在潜在的冲突,但只要你不写那些导致冲突的程序代码,就没有问题。

//比如Vector.class冲突了,编译器不知道你new Vector是创建那个,就得下面这样写。
java.util,Vector v = new java.util.Vector();

38.private,默认,protected,public

//private:同类
//默认:同类,同包
//protected:同类/子类/同包,注意的是,不同包的子类去访问这样写:super.protected_Attr;(用super)
//public:同类,同包,不同包(所有..)

39.代理模式,可以隐藏真实者代理者选择性提供真实者的方法,避免真实者的所有方法暴露给使用者。

40.在继承里,子类的构造方法,默认第一行调用super(),除非你手动调用super(…)(父类其它构造方法),因为编译器肯定要你先初始化父类的,无论什么形式。如果你父类没有默认的构造方法,而是重写了带参数的构造方法,子类构造方法必须显式调用super(…),否则编译时错误。

41判断是否需要使用继承:问一下自己是否需要 从新类向基类进行向上转型(子类变父类),如果必须向上转型,则继承是必须的;但如果不需要,则好好考虑使用组合(依赖注入)还是使用继承

42.final修饰词

//一个永不改变的编译时变量(必须是基本类型,减轻运行时负担)
//一个在运行时被初始化的值,而你不希望它被改变
//对于基本类型,final使数值恒定不变;而使用对象引用,final使引用恒定不变。(一旦引用被初始化执向一个对象,就无法再把它指向另一个对象。然而对象自身是可以被修改的,java并未提供使任何对象恒定不变的途径;数组,字符串都是对象!!)
//貌似,使引用成为final,没有使常量成为final用处大

43.定义为static,强调只有一份,定义为final,强调是常量。

44.空白final(final修饰的变量使用前必须初始化,空白final让初始化延迟且更加灵活,可以根据对象而有所不同)

class Test2 extends Day3{ 

    private final String name;

    public Test2(String name) {
        super(name);
        this.name = name;
    }

    public static void main(String[] args) {
        Test2 tt= new Test2("suguowen");
        System.out.println(tt.name);
        //tt.test1();
    }
    public void test1() {
        Day3 d = new Day3();
        /*System.out.println(super.private_Num);
        System.out.println(super.default_Num);*/
        System.out.println(super.protected_Num);
        System.out.println(super.public_Num);
    }
}

45.final修饰方法,把方法锁定,防止继承类修改它的定义;确保继承中使方法行为保持不变,并且不被覆盖。

46.所有private方法都隐式地指定了final,但因为private是隐式的,所以子类可以“覆盖”这个方法,但其实,子类不知道父类有这个方法,所以也就不存在覆盖一说

47.一个类的代码在初次使用时才会加载

48.多态:指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。

  
//假设data和getData()父子类都有
Super sup = new Sub();
sup.data;//将会调用父类的data
sup.getData;//将会调用子类的getData
//假设data和getData()父子类都有
Super sup = new Sub();
sup.data;//将会调用父类的data
sup.getData;//将会调用子类的getData

49.初始化一个对象的时候,先初始化静态代码块,再初始化全局变量,再初始化构造函数。

50.抽象类无法创建对象。

51.在interface中没有任何方法被声明为public,但是他们自动就是public。

51.策略模式,ABC都继承于X,使用者调用方法时将对象参数(A,B,C)和普通参数传入s方法(s是父类X的抽象方法),在s方法中,重新调用参数对象(A,B,C)的s方法(跟代理者模式有点像),从而实现策略。跟代理模式有什么不同呢,代理模式注重把一个真实者的全部方法都给代理者代理(代理者其实调用耦合了真实者,调用真实者的方法),进而隐藏真实者的存在;策略模式注重策略,同一个方法来调用不同的实现,只有在使用的时候,才决定用哪个策略。(策略也是提前写的,废话哦)

52.适配器模式,接口A,BCD都是他的实现类,s方法需要对象参数A即可策略的调用BCD方法了;这时候出现了以E为父类的一系列超好用的GHI子类;我们希望s方法可以把GHI也纳入为策略(但s方法只接受接口A为参数),那怎么办呢?我们可以创建一个Adapter类来实现A接口,Adapter耦合E(E是GHI的父类哦),初始化Adapter的时候,传入E的子类,用工厂模式实例化E,然后Adapter实现A接口的方法,把方法里的实现换成E的实现(代理模式)。虽然看上去用到了很多模式,但其实是我这个例子写的复杂了,适配器模式的思想其实是,你在用A接口来做事件S,但突然你老板叫你用B来做事件S,这时候S和B没有任何关系,你需要一个适配器Adapter来实现A,并且把B注入进去;这样你的A就包含了B,你就可以用B来做事件S了。

53.接口的域默认是public

54.内部类的作用,允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性

55.内部类最出色的地方在于,每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的、可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。接口解决了部分多重继承的问题,而内部类有效的实现了多重继承。

56.理解什么时候使用多态,什么时候使用接口、抽象类、内部类。(p215)

第十一章

1.数组一旦生产能,其容量就不能改变 ;Collection和map添加更多元素的时候,自动调整尺寸。

2.数组和List都是排序好的容器。

3.如果要进行大量的随机访问,就是用ArrayList,如果经常从表中间插入或删除数据,则应该用LinkedList。

4.各种Queue以及栈的行为,由LinkedList提供支持。

5.HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序的状态,所以没有HashMap快。LinkedHashMap保持元素的插入顺序但是也通过散列提供了快速访问的能力。

6.Set不接受重复元素。HashSet提供最快的查询速度,而TreeSet保持元素处于排序状态。LinkedHashSet以插入顺序保存元素。

7.Vector、Hashtable、Stack都过时了,不应该使用。

 

第十二章

1.当抛出异常时,将在堆上创建异常对象,当前执行路径被终止,异常处理机制接管程序,并用异常处理程序让

程序从错误状态恢复,让程序换一种方式运行或继续运行下去。

2.无论异常是否抛出,finally字句总是被执行。

 

第十三章

1.String对象不可变,String类中每一个看齐俩会修改String值的方法,实际上都是创建了一个全新的String对象。每当把String独享作为方法的参数时,都会复制一份引用,而该引用所指的对象其实一直待在单一的物理位置上,从未动过。

2.对于一个方法而言,参数是为该方法提供信息的,而不是想让该方法改变自己的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值