`
Mr.Zero
  • 浏览: 32958 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

thinking in java学习笔记

    博客分类:
  • java
 
阅读更多
第二章——万物皆为对象:
       一) 数据在计算机中的存放地址:
                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》这本书的读书笔记,涉及到从容器一章开始的所有后续章节的内容,只有把握我笔记中的内容我想你就差不多弄懂了&lt;thinking in java&gt;这本书的精华

    Thinking In java学习笔记

    这是我看Thinking in java 做的笔记,和大家分享下,如有不明白的的地方可与我私信,或者直接问度娘。

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

    Thinking in Java 自学笔记——第二章 一切皆对象 个人原创,不喜勿喷。

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

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

    Java学习笔记.pdf

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

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

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

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

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

    Thinking in Java

    在学习java的适合看看!有学习笔记,经过整理的。

    Thinking_in_Java(第四版_).rar

    学习笔记

    java学习资料/笔记整理(二)

    java学习资料/笔记整理,含java语言入门中文版、JDK1.4.2手册、JSP由浅入深、Think In Java(中英文)、Thinking_in_Java_chinese_version、精通swing程序设计等8个编译的HTML帮助文档....

    windows10上安装mysql详细图文教程.pdf

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

    String学习笔记

    自己写的java学习笔记,有完整的体系结构,有思维导图帮助理解和记忆

    Tomcat安装、配置和部署笔记 - 辛伯达 - 博客园.pdf

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

    java日常学习资料整理

    该资源包含了本人学习java时的笔记整理,还包含华为编程规范,以及thinking in java等多方面的学习资料,对于java从业者来说javaAPI文档以及经典书目必须要读,另外为了更具实践性还附了java实验指导书,希望对于...

    5本java学习用书

    找了5本学习java的好书和一些例子代码和大家分享,希望能够对您能有所帮助。

    thinking-in-spring:春天学习笔记

    春天思考 春天学习笔记

    java软件笔试题-MyNotebook:我大学时期的笔记本

    机器学习 C++笔记 part 4: 数据结构与算法 part 5: 笔试/面试 part 6:专业基础 输入URL到页面加载完成的过程 part 7:读书笔记 thinking in java effective java Android开发艺术探索 Android插件化开发指南

    thinking-in-spring:学春天

    春天学习笔记 Bean初始化 BeanDefinitionBuilder 新的GenericBeanDefinition Bean的命名(非强制性) BeanNameGenerator AnnotationBeanNameGenerator Bean的别名(一般XML配置) 别名 BeanDefinition的注册 ...

    java-study:JAVA示例,关于并发和缓存

    [目录]用法一个包含...Thinking in Java》一书的源代码书行动中的Java并发有效的Java(第二) Java 8实战用Java思考(第四)深度JVM Java网络编程博客笔记包和类的名称设法具有描述性,但可能违反了建议的名称样式。

Global site tag (gtag.js) - Google Analytics