`

thinking in java学习笔记

阅读更多
2009年8月13日 星期四 14时11分

第二章——万物皆为对象:
       一) 数据在计算机中的存放地址:
                1.寄存器(register):是处在处理器中,所以它的处理速度是最快的,但是也是数量也是很有限的,由编译器分配。
                2.栈(stack):位于常规内存区(general random-access memory area).处理器通过栈指针(stack point)来对他进行直接访问。通过指针的上下移动来分配或销毁内存。是在效率和速度上仅次于寄存器。因为他的生命周期和大小是已知的。所以有一定的局限性。故java中一般不会把对象存放在这个内存区域,更多是引用。references存放在这个区域。先进后出原则
                3.堆(heap):是一块多用途内存区(general -purpose pool of memory).基本上所有的java对象都是存放在这个区域。优点是分配空间时,编译器不关心分配多大的空间,何时销毁。速度上要慢些。(RAM)
                4.静态存储(static storage):静态存储的数据在整个运行期间都能访问到,你可以把某个对象的属性定义为静态,但是java对象不能存放到static storgae
                5.固定存储(constant storage):常量存放的地址。在嵌入式开发中,就可以考虑是否把常量放在ROM内存中。
                6.非内存的存储(NON-RAM menmory):对于一些可以保存在程序运行之外的。即程序失去了对数据的控制,但是这些数据还是存在。简单的说就是把对象进行持久化。根据持久化方式的不同,我们可以分为:
                   6.1:流对象(streamed object):即把对象转化为字节流,存放到另一台机子上。
                   6.2:持久化对象(persistent object):即将对象按照某种方式序列化到存储设备中,如磁盘,DB等。
       
        二) primitive (原始类型):在java体系中存在两种类型。一就是原始类型(primitive)&&对象类型。原始类型就是基本数据类型int,long 等。对于这些简单的数据类型,因为是非引用类型,所以在java中把它们存放在栈中。以提高效率。所有的基本类型都是有符号,没有unsigned符号。

        三) Java中的数组
                在C,C++中,数组就是一块内存。在数据未被初始化,或访问数组之外的内存,那么就会引起很多麻烦。在java中,规定了数组一定需要被初始化来限制。这样在访问数组之外的内存已经是不可能了。并另加一些内存来进行数组的边界检查。
                当你在创建数组的时候就是在创建一个引用reference.该引用会自己初始化为一个特殊的值:null.Java当看到这个null值的时候就知道这个reference没有指向任何对象。当你在对这个null进行操作的时候,就会抛出一个异常来进行处理。
       
        四)其他:
                 默认值:只有变量作为对象的类的成员时,才会有默认的初始值。
                 传递的问题:其实和C++中一样,我们在方法的传递时,如果传递的是一个primitive变量,那么传递仅仅是一个值,在return 的时候不会返回变化后的值。在C++中,为了解决这个问题,才方法中定义传参时,一般定义为指针,或者是引用。这个通java一样,在Java中传递一个基本类型,也是不变化的。通过传递一个对象(也就是一个对象的引用)来实现值变化的返回。对象就是C++中的指针或者引用。不过是进行封装,安全的指针。

第三章——控制程序流程
        一) Java运算符:基本上所有的运算符号都是作用与primitive的,但是有些是例外:如 = == += !=
                1.1 赋值:对于primitive类型的赋值就是在内存地址上进行赋值。
                        int a = 1; 建立一个a的指向栈中代表“1”地址
                        int b ;    建立一个默认指向0地址的引用。
                        int b = a  拷贝一份a的内容到b引用指向的地址。修改b,不会影响a的值。
                        简单的说:primitive之间的赋值就是内容的拷贝,对象之间的赋值就是引用的拷贝。
        二) 数据类型转化:
                        比int 小的数据类型会被提升到int,再进行运算,所以结果仍然是int.向下转化时,必须加类型转化,而且会丢失数据。
                        总之:运算过程中最大的类型,决定结果的类型。如 long && double result is double .
        三) 其他:
                        在for循环中可以这样使用逗号运算符,也是唯一用到的地方
                        for (int i =0 , int j = 1; i< 10 && j < 20 ;i++,j++){
                                //todo
                        }
                        在一些多层的循环的时候,可以使用标签来实现break , continue
                        for ()
                        {
                            label 1:
                                for ()
                                {
                                     break label1;        //这样可以实现一定范围的跳转
                                     }
                        }
                        虽然保留这goto 但是没有使用。
                       
第四章:初始化及清理
       一)构造函数的由来,为了初始化一些东西,但是又为了希望被调用,不被遗忘。C++ JAVA中都定义了这种方式。
       二)方法的重载:有构造函数的重载以及方法的重载。overLoad的最大区别是参数的不同。因为只有这个才能区分。
        例如返回参数的不同,在系统调用的时候,并不知道调的是哪个。所以返回类型不同不能成为overload的区分方式。
        方法的范围范围不同,如设置为private public .亦不能成为overload的区别,在同一个类中,调用这个方法编译器也不能区分调用的是哪个方法。
       三)每一个类都存在一个默认的构造函数。
       四)常见关键字
         4.1 this 关键字:对象本身的引用。
                在我们定义了两个相同类的对象。使用  a.f1(1)  b.f1(1).在底层为了区分到底是哪个调用了f1()方法,其实把该对象的引用也作为一个参数传递过去了。那两个方法的调用实际上是以 banana.f1(1,a) banana.f1(1,b).
             用途: 1.明确使用类内部自身对象。它代表就是类本身reference
                    2.在一个构造函数中调用另一个构造函数。
                    3.在传入参数与类自身属性相同时,用来区分是实参还是形参。this.a = a
         4.2 static关键字:简单的说static 修饰过的方法里面没有this,是一个类变量,类函数。在static 方法里面只能调用static 方法。因为是一个类函数或类变量,公用。故不能调用属于该类其他任何的非static函数或变量。非static 意味着可能被生成多个对象。
         4.3 finalize:释放内存时调用的方法。简单的说:
                        4.3.1.对象不一定会被垃圾回收
                        4.3.2.垃圾回收不析构函数
                        4.3.3 垃圾回收只与内存有关。只有在内存耗尽的时候才会取调用。一般不会耗费资源去调用
                调用方式:system.gc()
       五)成员的初始化
                对于类成员变量,会默认的初始值,但是对于局部变量则需要自己取初始化。
                1. 指定初始化,在定义变量的时候就进行初始化
                2. 在构造函数中进行初始化
        初始化的顺序:
                在一个函数的初始化函数中,包含new其他类,那么无论是在什么位置new这个类,都必先会先调用这个类的构造函数,然后才调用自己的构造函数。
                例如如下:一个类在加载的时候会先加载属性,然后才加载构造函数        


第五章 隐藏实现
        一些常见的接口方法

                                
第六章 类的复用
       
        合成:在新的类里面使用旧的类,例如在A类中使用B类
        继承:直接继承另一个类,来复用父类的代码
       
初始化一般有三种形式:
        1.直接在定义的属性的时候初始化 int a = 9
        2.在构造期里面开始构造
        3.lazy initial 就是需要进行判断后再初始化
                if (null == a ) a = 9;
        基类的初始化:
                子类在初始化的时候会先调用基类的初始化函数
                子类在调用父类的初始化构造函数时,调用父类的构造函数必须在最前面。这样做是为了防止:在调用父类的过程中抛出异常,可以首先知道。而不必取构造子类。
               
        合成还是继承:
                面向对象最简单的使用就是把数据和方法封装成一个类,然后再使用这个类的对象。
                是否用继承的时候,判断这个类是否能够上传,即子类是否可以当做父类来使用。少用继承,多用合成。
        final 关键字:
                可以修饰属性:使得这个属性不能指向另一个引用
                        方法:为使这个方法不能在子类中被覆盖
                        类  :为使这个类不能被继承。比如说JDK中的String类等

第七章:多态性
        抽象类的出现。就是你不想实例化这个抽象类,但是提供一些公共的接口让子类来实现
        有抽象方法的一定是抽象类。抽象类以一定有抽象方法.
        比如说你想创建一个类,但是该类又不想被实例化,那么就可以采用这种方法。

   第八章: 接口与内部类
                
        接口:是进一步的强化了abstract的概念,接口中所有的方法都是abstract和static且final的。故需要进行初始化
              接口中也可以嵌套接口
        内部类:在一个类中嵌套另一个类。将逻辑上相互从属的类组织起来,并控制它的访问权限。
                内部类的访问方式:
                outer.inner c = new outer.inner()//这个是显示内部类的用法。
        内部类的优点:每个内部类都可以独立的实现某个接口,因此内部类不会受“宿主类是否已经继承了别的实现”的约束。
                简单的说接口是部分解决了多继承的问题,那么内部类完全解决了多继承的问题。
       
第九章:用异常来处理错误
        9.1 Java的基本哲学:糟糕的代码根本就得不到执行
        9.2 异常的优点:让错误代码处理显的更有条理。即集中在一个地方对异常进行处理。还是应该坚持自己的意见,对于程序流程的跳转。可以利用异常来控制。
        9.3 对于异常有两种处理模式
                1. 中止模式:temination.即抛出异常,中止程序继续执行
                2. 继续模式:resumption.即跳过这个异常,继续执行。我们所用的操作系统一般采用的就是这种方式。
                对于程序中,我们可以自己定义自己的异常。来控制程序的走向。
        9.4 调试的时候我们可以采用 system.err来输出错误信息。采用system.out的话有可能会被重定向。就是在catch{}里面
                catch(Exception e)
                {
                        system.err.println("exception has happened");
                    }
        9.5 异常链:即在捕捉到一个异常后,再抛出一个其他类型的异常。JDK1.4以后提供了一个cause的构造函数来处理这个事件。
                initCause();具体使用的时候可以再仔细研究下。
        9.7 标准的JAVA异常
                throwable  : 是error :编译时候错误或者是系统错误。对于这类错误我们一般是无能为力的。也不需要我们取扑捉。
                               exception :java标准的类库方法及自定义的异常方法,这类方法需要我们来处理。
                finally块中的代码是一定会被程序执行的。所以在其中进行一些清理工作。对于一些内存以外的东西设置到原来状态的时候,如关闭一些输入流等

                使用finally块的时候有可能造成异常的丢失。如下所表示:
                        public class ExceptionsTest
{
    public void f() throws MyTestException
    {
        throw new MyTestException();
    }
   
   
    public void disPlay() throws MyTestException2
    {
        throw new MyTestException2();
    }
   
    public static void main(String[] args) throws MyTestException, MyTestException2
    {
        ExceptionsTest eTest = new ExceptionsTest();
        try
        {
            eTest.f();
        }finally
        {
            eTest.disPlay();
        }
    }
}

        9.8 在构造函数中抛出异常
               
         异常处理原则:
                不知道如何处理的时候就不要捕捉它


        1. 在何时的地方处理异常
        2. 把问题解决了,然后重新调用那个引起问题的方法
        3. 修正那个方法,然后绕过那个方法再继续下去
        4. 把当前环节能做的事情全部做完,然后把异常抛到更高层
        5  把当前环节能做的事情全部做完,然后抛另一个异常到更高层
        6. 中止程序
        7. 简化
        8. 把类库和程序做的更安全
       
第十章:检测类型
                RTTI:run-time type identification 运行时类别识别。
        10.1在运行时候的类型信息是由class文件来确定的。JVM在创建一个对象的时候会检查是否加载了这个类的class对象,如果没有则取加载.class文件。
               对象的产生: 一旦内存加载了这个CLASS对象,所有该类的对象都是由该对象来产生的。所以对于判断是否是一个对象的时候也可以采用这种方式来进行。
            对象之间的检测:
                1 利用对象类型的强转
                2.利用 instanceof, isInstance() 两种方式 后者为动态判断是否为同一个类型,前者写法较丑陋。
        CLASS提供了很多有用的方法:
                类名.class.isInstance()
                 类名.class.isInstance()
                 SubEqual.class.isArray();
                SubEqual.class.isInterface();
                SubEqual.class.isPrimitive();
                SubEqual.class.isLocalClass();

        instanceof 与 class之间都可以用于比较对象之间的类型。但是有一个区别       
                  class之间的比较只能是由通一个 类名.class文件产生的对象 才是true
                  instanceof如果是其本类或者是子类 返回的都是true

        获得class的reference的两种方式 一种是class.forName() 这样就不需要取new一个这个类型的对象。
                                       另一种是通过已经生成的对象 getClass()方法来获得class的引用。
       
总结:RTTI一般不常用,因为它只是多态的底层实现。只有在我们在多态的过程中,某个子类的反映特别的慢,可以考虑用RTTI来替代多态。这个属于程序的优化。       
        软件编程的习惯是:首先让程序跑起来,然后才考虑的是优化的问题。
       
第十一章:对象的集合
        如果程序的对象数目是有限,且数目是可知的,那么这个程序是相当的简单
       
        数组:
                数组跟其他容器的最大区别在于:效率,类型识别,可以持有primitives.在随即存储和访问references的效率中是最高的。只是一个简单的序列。
                但是缺点一样明显,在创建后,数目是固定的。后来JDK提供了一个ArrayList,但是在速度上慢了很多。
                与C++中的数组相比较,效率上差点,因为JAVA中的数组还要一定的开销做数组的下表越界。C++就没,所以容易出错。
                数组是第一流的对象
                因为容器只能只能存放对象的reference。数组两者兼可,而且效率更高。
        ARRAYS里面有几个有用的方法:
                Equals:数目,每个元素都要相等
                sort,fill,
                binarySearch:一种效率很高的查询方式,对于未排序的数组使用这个方法没有什么意义。

                system.arraycopy()方法能够更快的执行数组的拷贝。
       
                 三目运算符的双重用法:
                        public int compareTo(String arg0)
                    {
                        int j = Integer.valueOf(arg0);
       
                        return this.i < j ? -1 : ( this.i == j ? 0 : 1);//这里用的就是双重的三目,看起来很爽
                    }

                为了使的数组或容器中能够进行排序,那么就需要实现comparator接口。

        数组总结:arrays这个类主要是为数组服务的。collections主要是为容器服务的。

        容器:对于list还有一个更技巧的迭代器:ListIterator  可以沿两边来查看集合。     
        容器的结构图:
               

主要部分已经用黑色框表示:
        其中的abstratXX主要是用了适配器模式,如果我们要写自己的类话,那就不需要实现对应的接口,只需要继承抽象类就可以了。不要实现接口,并实现接口所有的类。

容器简介LIST
        List:以一定顺序保存数据,,允许重复。可以制造ListIterator,对集合进行两边的访问。
        ArrayList :用数组实现的LIST,能够进行快速的随即访问,但是在中间插入或删除数据比较慢。ListIterator只能用在反向遍历集合中,不要用来插入或删除数据,相比较LinkedList,在ArrayList中使用ListIterator的系统开销比LinkedLIST大。
        LinkedList:对顺序访问进行了优化,插入删除数据的代价也不高,但是随即访问能力较慢能当做栈,队列,双向队列来使用,在一般情况下不推荐是这个。建议使用ArrayList。
SET :多态的完美实现。无序,不允许重复的。对于加入的object对象,需要覆盖equals方法。
HASHSET:为优化查询速度而设计的SET,放入的object必须实现hasshCode方法。底层就是hashMap来实现的。
TREESET:有血的SET,放入的对象必须实现compable接口,或者有一个比较器compartor
LINKEDHASHSET:内部是在链表实现的SET,即有HASHSET的速度,又能保存元素加入的顺序,用iterator遍历的时候是按照插入顺序来遍历的。

MAP:底层用hash算法实现,在容器中的查询速度比arrayList还快。



  散列算法和hash算法。
HASHMAP的底层实现:
        其实在底层就是一个数组,每个数组的位置叫做BUCKET,没一个bucket其实就是一个linkedList,插入的时候,首先根据KEY值算的hashcode,让后对数组的大小进行去模,如果得到的这个bucket位上没有任何数据,就new一个linkedList,并放入到其中,若是已经有,则比遍历真个list看是否存在相等,若是相等的就返回原来的值,并把新值存放在位置上,若是没有相等的,那么就把值加到linkedList的最后。
影响其性能的因素:
        1.bucket数目,即数组的大小。
        2.initial bucket数目:初始化大小,可以通过初始化构造函数来设定。默认情况是16个,
        3.当前hash表的数目
        4.load factor:加载因子,即在什么时候对这个数组进行扩展。如果你设定的比较大的话,可以考虑把load factor设定的大点,免得需要多次reflash。默认的加载因子是0.75.也就是75%。
       
hashcode的产生原则:就是一个对象放入和取出计算的hashcode值要求是一样的,不能因为对象某个值得改变而导致取出的值不一样。


LIST的选择:
       

上表是对于四种容器的性能测试:
        GET:随即访问        ITERATOR:顺序访问        INSERT:插入        REMOVE:删除
从上表可以看出数组在随即访问速度是最快的,在数据的插入和删除最慢。但是奇怪的是ArrayList的顺序访问速度比数组要快。
ArrayList的优势在于性能的平衡性,随即访问和插入的速度都可以,可怕的是删除速度,毕竟底层实现还是数组。
LinkedList 的优势在于删除和插入,
Vector是线程安全的,可以不用考虑。

SET的选择:
       

总体来说:HashSet的性能要比treeSet好,尤其是在查询和插入时,TreeSet存在的意义在于维护一个有序序列。
LinkedHashSet的插入要比HashSet稍微慢点,那是因为它要维护链表和Hash容器的双重代价。也因为底层是链表的缘故,所以它的遍历是最快的。
在容量不是很大的情况下个人建议还是使用LinkedHashSet,比较好,在插入的时候代价并不是很高,但是遍历的速度确实很快。

MAP选择:

       
一般情况下使用hashmap就可以了.treeMap需要维护一个有序列表,所以要慢些。

总结:
       


       
               
       
分享到:
评论

相关推荐

    Thinking In java学习笔记

    ### Thinking In Java 学习笔记知识点总结 #### 面向对象编程(OOP)的重要性及其影响 面向对象编程(OOP)在软件开发领域产生了深远的影响。它不仅提高了开发效率和降低了维护成本,还简化了设计流程,使得编程任务...

    Thinking in java学习笔记

    《Thinking in Java》是一本深度解析Java编程语言的经典著作,其深入浅出的讲解和丰富的实例使得读者能够全面理解Java的精髓。以下是对书中部分关键知识点的总结: 1. **Java 泛型**:泛型是Java SE 5.0引入的重要...

    Thinking in Java 自学笔记——第二章 一切皆对象

    ### Thinking in Java 自学笔记——第二章 一切皆对象 #### 重要概念解析 ##### 2.1 用引用操纵对象 在Java中,一切都被视为对象,这意味着无论是字符串、数字还是其他数据类型都可以被视为对象来进行操作。当...

    Thinking in Java读书笔记

    ### Thinking in Java 读书笔记知识点总结 #### 一、万事万物皆对象 1. **对象存储位置** - **寄存器**:程序无法直接控制。 - **栈(Stack)**:存储基本类型数据和对象引用,但对象本身不在此处。 - **堆(Heap)...

    Thinking in Java 自学笔记——第一章 对象导论

    该标签表明本章节的主要内容是关于 Java 编程语言的学习笔记。 部分内容: 1.1 抽象过程 抽象是编程语言的基本机制,它允许开发者定义和使用抽象类型,隐藏实现细节,提高代码的可维护性和可重用性。 1.2 每个...

    王者归来之Thinking in java读书笔记

    《王者归来之Thinking in Java读书笔记》是对Bruce Eckel的经典之作《Thinking in Java》第四版的深度学习与总结。这本书是Java程序员的必备参考书,它深入浅出地阐述了Java语言的核心概念和技术,旨在帮助读者理解...

    java基础补足和thinking In Java学习.rar

    JAVA学习日记---Thinking in Java学习笔记 第5章总结 第五章 初始化与清理 5.1 用构造器确保初始化 1.构造器命名必须与类名相同 2.构造器也是方法,满足方法的各种特征,无参数的构造器称为默认构造器,默认构造...

    thinking in java 读书笔记(五)

    《Thinking in Java》是Bruce Eckel的经典之作,它深入浅出地讲解了Java语言的核心概念和技术,对于初学者和有经验的开发者来说都是极好的学习资源。这篇读书笔记主要聚焦在第五部分的内容,可能涵盖了类、对象、...

    Thinking in java读书笔记.docx

    这些只是《Thinking in Java》中的一部分内容,全书还包括类、接口、多态性、异常处理、集合框架、并发编程等多个主题,是Java学习者的宝贵资源。理解和掌握这些基础知识是成为一名熟练Java程序员的关键步骤。

    Thinking In Java的笔记_第一章

    通过以上概述,《Thinking In Java》第一章深入浅出地讲解了Java的基础概念,涵盖了面向对象编程的核心原则、数据的存储与管理、基本类型与包装类的使用,以及高精度数字的处理技巧,为初学者和进阶学习者提供了宝贵...

    Java学习笔记.pdf

    我的学习笔记的书本课程来自于:《Thinking in Java》和《Head First Java》 视频课程主要来自于:廖雪峰老师《Java 基础课程》 如涉及版权侵犯请联系我更正。 初来乍到,文笔稚嫩,学识浅薄,请多指教。

    包括JAVA夜未眠,thinkingJAVA和学习笔记

    在IT领域,特别是Java编程的学习过程中,"JAVA夜未眠,thinkingJAVA和学习笔记"这一主题涵盖了许多核心概念和实践技巧。以下是对这些资源的详细解释: 首先,"Java夜未眠"可能指的是一个深入探讨Java编程的书籍或...

    中文版Thinking in Java 4th编程思想(笔记)

    《中文版Thinking in Java 4th编程思想》是学习Java编程的重要参考资料,它深入浅出地介绍了面向对象编程的核心概念。下面将详细解读其中的主要知识点。 1. **对象导论** - **万物皆对象**:Java编程的核心是对象...

    《Thinking+in+Java》读书笔记共38页.pd

    总之,《Thinking in Java》的读书笔记结合了广泛的Java知识和实践应用,从基础知识到高级主题,从理论到实践,为学习和提升Java编程技能提供了全面的资源。无论是对初学者还是经验丰富的开发者,这都是一个宝贵的...

    用于存放java源码和Thinking of Java的资源

    其次,"Thinking in Java"的资源可能包括了课后练习、习题解答、代码注释或者其他辅助学习材料。这些资源对于自学Java的人来说极其宝贵,它们可以帮助检验学习效果,解决遇到的问题,并提供额外的实践机会。通过完成...

    Java JDK 6.0 学习笔记.pdf

    **Java JDK 6.0 学习笔记** Java JDK(Java Development Kit)是Java编程语言的核心组件,包含Java运行环境、编译器、类库以及各种工具,是开发者进行Java程序开发的基础。Java JDK 6.0是Oracle公司发布的一个重要...

    恒生电子JAVA笔试试题-Thinking-In-Java-Notes:ThinkinginJava学习笔记

    Java》学习笔记 [TOC] 阅读计划 章节列表 对象导论 一切都是对象 操作符 控制执行流程 初始化与清理 访问权限控制 复用类 多态 接口 内部类 持有对象 通过异常处理错误 字符串 类型信息 泛型 数组 容器深入研究 Java...

    19个JAVA学习的资料,包括电子书,练习题!

    6. **Java学习笔记.doc**: 这可能是个人或教师的教学笔记,可能包含学习心得、重点难点解析,对学习者来说是宝贵的参考资料。 7. **2011最新整理Java练习题.doc**: 提供了最新的练习题目,反映了当时Java技术的发展...

Global site tag (gtag.js) - Google Analytics