java 基础知识几要点

来源:互联网 发布:影响力 知乎 编辑:程序博客网 时间:2024/05/19 17:57
编写递归代码有三点要注意:
   1. 递归总有一个最简单的情况---方法的第一个语句总是包含return的条件语句
       2. 递归调用总是去解决一个规模更小的问题
       3. 递归调用的父问题和尝试解决的子问题之间不应该有交集



比如二分查找:
    public static int BinarySearch(int key,int a[])
          {
               return BinarySearch(key,a,0,a.length);   
   }


               private static int BinarySearch(int key,int a[],int low,int high)
               {
                        if(low>high)
                             return -1;
                       int middle = low +(low-high)/2;
                       if(a[middle]>key) return BinarySearch(key,a,low,middle-1);
                      else if(a[middle]<key) return BinarySearch(key,a,middle+1,high);
                      return middle;
               }





数据抽象的作用:
     如果只有java的原始数据类型,我们的程序会在很大程度上被限制在算数计算上,但有了引用类型,我们就能编写操作字符串、图像、声音以及java的标准库中或者书上的数百种抽象类型的程序。
     
     抽象数据类型(ADT)是一种能够对使用者隐藏数据表示的类型。抽象数据类型的主要不同之处在于它将数据和函数的实现关联,并将数据的表示方式隐藏起来。在使用抽象数据类型时,我们的注意力集中在API描述的操作上而不会去关心数据的表示;在实现抽象数据类型时,我们的注意力集中在数据本身并将实现对该数据的各种操作。





设计数据抽象时:

     1.定义一份API: API的作用是使用和实现分离,以实现模块化编程。我们制定一份API的目标有二:第一,我们希望用例代码清晰而正确,事实上,在最终确定API之前就编写一些用例代码来确保所设计的数据类型操作正是用例所需要的很好的主意;第二,我们希望能够实现这些操作,定义一些无法实现的操作是没意义的。
     2.用一个java类实现API的定义:首先我们选择适当的实例变量,然后再编写构造函数和实例方法。
     3.实现多个测试用例来验证前两步做出的设计决定。



API的设计问题:
     1.API可能会难以实现:实现的开发非常困难,甚至不可能。
    2.API可能会难以使用:用例代码甚至比没有API时更复杂。
    3.API的范围可能太窄:缺少用例所需的方法。
    4.API的范围可能太宽:包含许多不会被用到的方法。这种缺陷是最常见的,并且也是最难以避免的。API的大小一般会随着时间而增长,因为向已有的API中添加新方法很简单
      ,但在不破坏已有的用例程序的前提下从中删除方法却很困难。
    5.API可能会太粗略:无法提供有效的抽象。
    6.API可能太详细:抽象过于细致或是发散而无法使用。
    7.API可能会过于依赖某种特定的数据表示:用例代码可能会因此无法从数据表示的细节中解脱出来。要避免这种缺陷也是很困难的,因为数据表示显然是数据抽象实现的核心


    这些考虑有时又被总结为另一句格言:只为用例提供它们所需要的,仅此而已。





接口继承:

    java语言为定义对象之间的关系提供了支持,称为接口。它允许我们通过指定一个含有一组公共方法的接口为两个本来并没有关系的类建立一种联系。接口继承使得我们的
    程序能够通过调用接口中的方法操作实现该接口的任意类型的对象。在某些情况下java的习惯用法鼓励我们使用接口:我们用它们进行比较和迭代。


实现继承:
    java支持另一种继承机制,被称为子类。这种非常强大的技术是程序员不需要重写整个类就能改变它的行为或者为它添加新的功能。它的主要思想是定义一个新类来继承另一个类
    (父类)的所用实例方法和实例变量。子类继承被系统程序员广泛用于编写所谓的可扩展的库---任何一个程序员都能为另一个程序员创建的添加方法。
    
    子类继承阻碍模块化编程原因有两点。
    
    第一,父类的任何改动都会影响它的子类。子类的开发不能和父类无关。事实上,子类是完全依赖于父类的。这种问题被称为脆弱的基类问题。
    
    第二:子类代码可以访问所有的实例变量,因此它们可能会扭曲父类代码的意图。例如,用于选票统计系统的Counter类的设计者可能会尽最大的努力保证Counter每次只能将计数器加1.但它的子类可以完全访问这个实例变量,因此可以将它改变为任意值。




不可变性:
   不可变数据类型,例如Date,指的是该类型的对象中值在创建之后就无法再被改变。与此相反,可变数据类型,例如Counter或Accumulator,能够操作并改变对象中的值。java语言通过   final修饰符来强制保证不可变性。当你将一个变量声明为final时,也就保证了只会对它赋值一次,也可以用构造函数。数据类型是否可变是一个重要的设计决策,它取决于当前的应用场景对于类似于Date的数据类型抽象的目的是封装不变的值,以便和原始数据类型一样用于赋值语句、作为函数参数或返回值(而不必担心它们的只会被改变)。程序员在使用Date时可能会写出操作两个Date类型的变量的代码 d = d0,就像操作double或者int一样。但如果Date类型是可变的且d的值在d = d0 之后可以被改变,那么d0的值也会被改变。从另一方面来说,对于类   似于Counter和Accumulator的数据类型,抽象的目的是封装变化中的值。作为用例程序员,你在使用java数组(可变)和java的String(不可变) 时就已经遇到了这种区别。
   但有时也存在我们希望使用可变字符串(这就是java的StringBuilder类存在的目的)和不可变数组(这就是Vector类存在的目的)的情况。
   不可变数据类型比可变数据类型使用更容易,误用更困难。
   不可变数据类型的缺点在于我们需要为每个值创建一个新对象。这种开销一般是可以接受的,因为java的垃圾回收器通常都为此进行了优化。不可变性的另一个缺点在于,final非常不幸地只能用来保证原始数据类型的不可变性,而无法用于引用类型的变量。





 java类:
        静态方法  
       不可变的抽象数据类型
       可变的抽象数据类型
       具有I/O副作用的抽象数据类型