重拾java系列一java基础(2)

时间:2021-12-22 08:20:49

1.分支流程控制

if(布尔表达式/分支条件){
  //语句块
}

if(布尔表达式/分支条件){
  //语句块1
}else{
  //语句块2
}

if(条件1){
  //语句块1
}else if(条件2){
  //语句块2
}else if(条件3){
  //语句块3
}

1) 尽量使用肯定条件,可以减少逻辑思考错误
 2) 减少使用else
 3) 减少嵌套层次,一般不要超过2层
 4) 语句块不要超过一个屏幕!
 5) 严格遵守缩进规则!
 
switch(整数条件){
  case 常量:   (break;)
  case 常量:
  default:
}

2.循环流程控制

for  while   do...while
 
 1)for 经典用法: 与次数,连续变化的数列有关的循环
    for(初始化;循环条件;递增){
     循环体
    }
 
 2)for可以替代任何循环
  2.1) 死循环
   for(;;){
   }
  
   for(;true;){
   }
 
  2.2)
   for(;循环条件;){
   }
 
 
 for while do...while 比较
 1) for 常用,“经典使用方式”与固定次数有关循环处理
 22) for 可以替代其它两种循环
   2.1) for(;循环条件;){} 替代 while(循环条件){}
   2.2) 死循环 for(;;){} 替代  while(true){}
   2.3) for(;;){ if(循环条件) break; } 替代
      do...while(循环条件);
 3) while 循环用于在循环体开始时候判断循环条件
 4) do ... while 循环用于在循环体结束时候判断循环条件
 5) 在其他情况下使用 死循环!在适当的条件时候使用break

穿插小demo:

 /**
 *
 * 案例:判断一个数是否是“水仙花数”
 *    水仙花数:3位自幂数,是一个3位并且各个数字的3次方的和
 *    与这个数相等
 *    153 = 1*1*1 + 5*5*5 + 3*3*3
 *        = 1 + 125 + 27
 *        = 153
 */
 public class Daffodil {
     public static void main(String[] args) {
         for(int n=100; n<=999; n++){
             //int n = 153;// n = 100 101 ... 999
             int num = n;
             int sum = 0;
             while(num!=0){
                 int last = num%10;
                 sum += last * last * last;
                 num /= 10;
             }
             if(sum == n){
                 System.out.println(n+"是水仙花数!");
             }
         }
     }
 }

斐波那契数列:

 /**
  * 菲波纳且
  * 数列
  *        1  1  2  3  5  8  13  21  ...
  *  列数:1  2  3  4  5  6  7   8   ...
  *
  *  f(n)/f(n+1) = 0.618
  *
  * 计算 第n项
  * 1) 功能:计算菲波纳切数列的n项
  * 2) 功能实现: n项 是 前两项的和 推理 从第一项加到n项
  * 功能分析:
  *     1  1  2  3  5  8  13  21  ...
  *     1  2  3  4  5  6  7   8   ...
  *                           n
  *    f1+f2=fn
  *       f1+f2=fn
  */
 public class Demo02 {
     public static void main(String[] args) {
         System.out.println(f(8));
         System.out.println((double)f(50)/f(51));
     }
     public static long f(int n){
         long f1 = 1;long f2 = 1;long fn = 1;
         for(int i=3; i<=n; i++){
             fn = f1+f2;    f1 = f2; f2 = fn;
         }
         return fn;
     }
 }

递归算法:

 public static long f1(long n) {
         if (n == 1 || n == 2) {
             return 1;
         }
         return f1(n - 1) + f1(n - 2);
     }

3.Arrays工具类(专门针对数组的工具类,未特殊说明,参数均为数组):

(1)Arrays.toString(Object[] a) 将数组的元素连接为一个字符串.

 public static void main(String[] args) {
         String[] names = { "susu", "Andy", "John", "Jerry" };
         System.out.println(Arrays.toString(names));
         //运行结果:[susu, Andy, John, Jerry]
     }

下面让我们看一下为什么运行结果是上面的字符串?我们看一下Arrays.toString()   API

 public static String toString(Object[] a) {
         if (a == null)
             return "null";
         int iMax = a.length - 1;
         if (iMax == -1)
             return "[]";

         StringBuilder b = new StringBuilder();
         b.append('[');
         for (int i = 0;; i++) {
             b.append(String.valueOf(a[i]));
             if (i == iMax)
                 return b.append(']').toString();
             b.append(", ");
         }
     }

一目了然,这便是底层代码的java实现,此时不如我们再扩展一下,直接输出System.out.println(names);发现返回的是[Ljava.lang.String;@3fbefab0咋一看这是什么玩意,由于任何类都是Object类的子类(后面部分会讲解到),而Object中定义的toString()方法api 如下:

  public String toString() {
     return getClass().getName() + "@" + Integer.toHexString(hashCode());
     }

由此我们可以看到,Object类的toString()方法返回的是类名+hashcode值 (hashcode后面再讲),所以如果想要返回自定义的格式,就要像Arrays类一样,,重写(后面讲)Object的toString()即可。

(2)Arrays.equals(obj1,obj2) ,此方法用来比较两个数组是否相等,底层api很简单,如下:

 public static boolean equals(char[] a, char[] a2) {
         if (a==a2)
             return true;
         if (a==null || a2==null)
             return false;

         int length = a.length;
         if (a2.length != length)
             return false;

         for (int i=0; i<length; i++)
             if (a[i] != a2[i])
                 return false;

         return true;
     }

(3)Arrays.sort(names);//顾名思义,排序,我们先来看一下例子效果:

 public static void main(String[] args) {
         int[] a = {101,3,88,76,34,22};
         String[] names = {"Tom","Andy","John","Jerry"};
         Arrays.sort(names);
         Arrays.sort(a);
         System.out.println(Arrays.toString(names));
         System.out.println(Arrays.toString(a));
         //运行结果:[Andy, Jerry, John, Tom]  [3, 22, 34, 76, 88, 101]
     }

我们再来看一下底层api到底发生了什么:

  /**
      *
      * @param a the array to be sorted
      * @throws  ClassCastException if the array contains elements that are not
      *        <i>mutually comparable</i> (for example, strings and integers).
      */
     public static void sort(Object[] a) {
         Object[] aux = (Object[]) a.clone();// 首先调用了clone()方法,以后会有专题来讲解clone()方法
         //下面排序中主要针对克隆后的数组进行排序,排好序后再copy回待排序的数组,destnation
         mergeSort(aux, a, 0, a.length, 0);// 调用归并排序方法
     }

     /**
      * Tuning parameter: list size at or below which insertion sort will be used
      * in preference to mergesort or quicksort.
      * 调优参数:列表大小达到或者低于插入排序将优先使用归并排序和快速排序。
      */
     private static final int INSERTIONSORT_THRESHOLD = 7;

     /**
      * Src is the source array that starts at index 0 //克隆后的数组
      * Dest is the (possibly larger) array destination with a possible offset //待排序的数组
      * low is the index in dest to start sorting //待排序的数组中开始排序的的起始索引,从0开始 ,排序时会发生变化
      * high is the end index in dest to end sorting //待排序的数组的的截止索引,排序时会发生变化
      * off is the offset to generate corresponding low, high in src//偏移量,位移
      */
     private static void mergeSort(Object[] src, Object[] dest, int low,
             int high, int off) {
         int length = high - low;//待排序的数组长度

         // Insertion sort on smallest arrays
         // 数组长度比较小时使用插入排序,java底层的优化,设置插入排序的阀值为7,此时直接对待排序的数组进行排序
         if (length < INSERTIONSORT_THRESHOLD) {
             for (int i = low; i < high; i++)
                 for (int j = i; j > low
                         && ((Comparable) dest[j - 1]).compareTo(dest[j]) > 0; j--)
                     //dest[j-1]至少从dest[0]开始,即起始元素开始,和下一个作比较,按照字典顺序,自然顺序,具体规则后面重点剖析,不等于0时,交换两者位置
                     swap(dest, j, j - 1);//交换位置
             return;
         }

         // Recursively sort halves of dest into src
         //递归排序
         int destLow = low;
         int destHigh = high;
         low += off;
         high += off;
         int mid = (low + high) >>> 1;
         mergeSort(dest, src, low, mid, -off);
         mergeSort(dest, src, mid, high, -off);

         // If list is already sorted, just copy from src to dest. This is an
         // optimization that results in faster sorts for nearly ordered lists.
         //如果列表已经被排好序,只需从src复制到dest,这是种优化的选择,结果是使用快速排序
         if (((Comparable) src[mid - 1]).compareTo(src[mid]) <= 0) {
             System.arraycopy(src, low, dest, destLow, length);
             return;
         }

         // Merge sorted halves (now in src) into dest
         // 归并
         for (int i = destLow, p = low, q = mid; i < destHigh; i++) {
             if (q >= high || p < mid
                     && ((Comparable) src[p]).compareTo(src[q]) <= 0)
                 dest[i] = src[p++];
             else
                 dest[i] = src[q++];
         }
     }

     /**
      * Swaps x[a] with x[b].//交换数组x中a,b对应位置的两个元素
      */
     private static void swap(Object[] x, int a, int b) {
         Object t = x[a];
         x[a] = x[b];
         x[b] = t;
     }

由此可见,实际上java只不过封装了对应的排序方法,我们调用即可,关于以上里面的算法,我会单独拿出篇幅来分析

(4)Arrays.binarySeacher(Object[]a , obj1)//利用二分查找方法找出给定元素在给定数组中首次出现的位置,从0开始

 public static void main(String[] args) {
         String[] names = {"bss", "Tom", "Andy", "Jerry",
                 "John","yuuuuy", "Wang"};
         int index;
         index = Arrays.binarySearch(names,    "Jerry");
         System.out.println(index);
         index = Arrays.binarySearch(names,    "Tom");
         System.out.println(index);//负数
 //        //以上的查找结果不确定!
         Arrays.sort(names);
         index = binarySearch(names,    "John");
         System.out.println(index);//2
         //以上查找是稳定的结果
     }

同样我们通过api分析:

 public static int binarySearch(Object[] a, Object key) {
         return binarySearch0(a, 0, a.length, key);
     }

     private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
             Object key) {
         //初始化低位和高位索引
         int low = fromIndex;//带查找范围的最低索引,可变
         int high = toIndex - 1;//带查找范围的最高索引,可变

         while (low <= high) {
             int mid = (low + high) >>> 1;// 无符号右移,前面补0,后面舍去,先把数组分成两个阵营,
             //先比较中间元素是否为所找元素,若是,则返回中对应index,
             //若不是,则根据中间元素与待查元素的字典顺序判断是在前面查找还是后面查找了,以此类推
             Comparable midVal = (Comparable) a[mid];// 之所以可以强转成Comparable,是因为该类(字符串)实现了Comparable接口,
             int cmp = midVal.compareTo(key);

             if (cmp < 0)// 按字典顺序,midVal比key排在前面,则返回负数
                 low = mid + 1;//从中间mid位置开始往后寻找目标,相当于新的起始位置,即新的low到最后中查找
             else if (cmp > 0)// 按字典顺序,midVal排在key后面,则返回正数
                 high = mid - 1;//从中间mid位置开始往前寻找目标,相当于新的终止位置,即在0~新的high中查找
             else
                 return mid; // key found
         }
         return -(low + 1); // key not found.
     }

可以看出二分查找的方法,但要注意以下几点:
1) 在未排序的数组上使用二分查找结果不稳定.
2) 必须在排序的数组上使用二分查找!
3) 二分查找结果是元素的位置, 如果返回负数表示没有找到

(5)关于数组的复制:

public static void main(String[] args) {
        int[] ary1 = {5,6,7};
        int[] ary2 = ary1;
        System.out.println(ary1==ary2);// true
        System.out.println(Arrays.equals(ary1, ary2));// true
        ary1[0] = 10;//对其中一个修改
        ary1[1] = 20;//对另一个修改
        System.out.println(Arrays.toString(ary1));//[10, 20, 7]
        System.out.println(Arrays.toString(ary2));//[10, 20, 7]
        //出现以上的结果是两者数组变量共同引用同一个对象
        //复制数组 复制ary1引用的数组,比较笨拙的方法
        int[] ary3 = new int[ary1.length];
        for(int i=0; i<ary1.length; i++){
            ary3[i] = ary1[i];
        }

        //Java 提供了复制数组的API, 可以简化复制,提高性能
        int[] ary4 = new int[ary1.length];
        //               源, 源位置,目标,目标位置, 数量
        System.arraycopy(ary1, 0, ary4, 0, ary1.length);
        System.out.println(Arrays.toString(ary4));
        System.out.println(ary4==ary1);//false
        System.out.println(ary4.equals(ary1));//false
        //Arrays.copyOf() 方法更加便捷的复制数组, since Java 6
        //底层调用的还是System.arraycopy()
        int[] ary5 = Arrays.copyOf(ary1, ary1.length);
        System.out.println(Arrays.toString(ary5));
        System.out.println(ary1.equals(ary5));//false
    }

而代码中最后的输出为false,是因为Arrays.copyOf()方法也是新new 了一个数组,参看api:

  public static int[] copyOf(int[] original, int newLength) {
                  System.arraycopy(original, 0, copy, 0,
                          Math.min(original.length, newLength));
         7      return copy;
     }