`

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需要维护一个有序列表,所以要慢些。

总结:
       


       
               
       
分享到:
评论

相关推荐

    白色大气风格的旅游酒店企业网站模板.zip

    白色大气风格的旅游酒店企业网站模板.zip

    python实现用户注册

    python实现用户注册

    【图像压缩】基于matlab GUI Haar小波变换图像压缩(含PSNR)【含Matlab源码 9979期】.zip

    Matlab领域上传的视频均有对应的完整代码,皆可运行,亲测可用,适合小白; 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    (177354822)java小鸟游戏.zip

    内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    VB+access学生管理系统(论文+系统)(2024am).7z

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;

    数学计算中的平方表与圆周率π的应用

    内容概要:文档名为《平方表,派表集合.docx》,主要内容是1至1000的平方值以及1至1000与π的乘积结果。每个数字从1开始,逐步增加至1000,对应地计算了平方值和乘以π后的值。所有计算均通过Python脚本完成,并在文档中列出了详细的计算结果。 适合人群:需要进行数学计算或程序验证的学生、教师和研究人员。 使用场景及目标:用于快速查找特定数字的平方值或其与π的乘积,适用于教学、科研及程序测试等场景。 阅读建议:可以直接查阅所需的具体数值,无需从头到尾逐行阅读。建议在使用时配合相应的计算工具,以验证和拓展数据的应用范围。

    VB+SQL光盘信息管理系统(源代码+系统+答辩PPT)(20244m).7z

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;

    白色大气风格的健身私人教练模板下载.zip

    白色大气风格的健身私人教练模板下载.zip

    白色简洁风的商务网站模板下载.zip

    白色简洁风的商务网站模板下载.zip

    白色大气风格的前端设计案例展示模板.zip

    白色大气风格的前端设计案例展示模板.zip

    圣诞树项目中的硬件和MATLAB实现指南

    内容概要:本文介绍了两个有趣的圣诞树项目方向:一是使用Arduino或Raspberry Pi开发可编程的圣诞树灯光控制系统;二是基于MATLAB开发一个圣诞树模拟器。前者通过硬件连接、编写Arduino/Raspberry Pi程序、MATLAB控制程序来实现LED灯带的闪烁;后者则通过创建圣诞树图形、添加动画效果、用户交互功能来实现虚拟的圣诞树效果。 适合人群:具备基本电子工程和编程基础的爱好者和学生。 使用场景及目标:①通过硬件和MATLAB的结合,实现实际的圣诞树灯光控制系统;②通过MATLAB模拟器,实现一个有趣的圣诞树动画展示。 阅读建议:读者可以根据自己的兴趣选择合适的项目方向,并按照步骤进行动手实践,加深对硬件编程和MATLAB编程的理解。

    白色扁平风格的温室大棚公司企业网站源码下载.zip

    白色扁平风格的温室大棚公司企业网站源码下载.zip

    Navicat.zip

    Navicat.zip

    Scikit-learn库中主成分分析(PCA)技术的Python实现教程

    内容概要:本文详细介绍了主成分分析(PCA)技术的原理及其在Scikit-learn库中的Python实现。首先讲解了PCA的基本概念和作用,接着通过具体示例展示了如何使用Scikit-learn进行PCA降维。内容涵盖了数据准备、模型训练、数据降维、逆转换数据等步骤,并通过可视化和实际应用案例展示了PCA的效果。最后讨论了PCA的局限性和参数调整方法。 适合人群:数据科学家、机器学习工程师、数据分析从业者及科研人员。 使用场景及目标:适用于高维数据处理,特别是在需要降维以简化数据结构、提高模型性能的场景中。具体目标包括减少计算复杂度、提高数据可视化效果和改进模型训练速度。 其他说明:本文不仅提供了详细的代码示例,还讨论了PCA在手写数字识别和机器学习模型中的应用。通过比较原始数据和降维后数据的模型性能,读者可以更好地理解PCA的影响。

    (175846434)目标检测-将VOC格式的数据集一键转化为COCO和YOLO格式

    VOC格式的数据集转COCO格式数据集 VOC格式的数据集转YOLO格式数据集。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    数字信号处理课程设计.doc

    数字信号处理课程设计.doc

    白色扁平化风格的灯饰灯具销售企业网站模板.zip

    白色扁平化风格的灯饰灯具销售企业网站模板.zip

    华豫佰佳组合促销视图.sql

    华豫佰佳组合促销视图.sql

    白色大气风格的商务团队公司模板下载.zip

    白色大气风格的商务团队公司模板下载.zip

    白色大气风格的VPS销售网站模板.zip

    白色大气风格的VPS销售网站模板.zip

Global site tag (gtag.js) - Google Analytics