天天看點

瘋狂Java學習筆記(008)回顧作業:對象一、參數傳遞的原則:值傳遞二、面向對象的概念:

回顧

一、數組

1.數組的概念:

  同種資料類型若幹個數值的組合.稱為數組.

  實際上就是多個記憶體空間(變量)的組合.

  數組的元素值可以在資料類型的表數範圍内發生變化!!! 

2.數組的元素:

  element:數組中的數值就稱為數組的元素!

3.數組的長度:

  length:就是數組中元素的個數.

4.元素的索引:

  index:數組中元素的編号.從0開始.最大值是數組的長度-1.

5.數組的初始化方式:

  初始化指的是數組中的元素第一次指派,以後再指派就不是初始化.

  1.> 動态初始化:隻指定數組的長度.由系統賦預設初始值(0/0.0/false/null).

    int[] arr = new int[5];

    在堆空間中開辟5個能存放int型資料的空間,賦予預設的初始值,并把位址值傳回給變量arr.

  2.靜态初始化:在定義數組時指定數組的初始化值.此時不能指定數組的長度!(靜态和動态不能同時使用!!)

    int[] arr = new int[]{1,2,3};

    //在堆空間中開辟3個存放int型資料的空間,把1,2,3放進去,然後把記憶體位址值傳回給變量arr.

    簡化寫法:

    int[] arr = {1,2,3};

5. 數組類型的變量直接列印的結果:

  以int型數組為例:

  [I@xxxx

  [ :指的是變量中儲存的記憶體空間是數組類型

  I :指的是數組的類型是int型(也就是數組元素的類型)

  @ :固定的分隔符

  xxxx :一串字元串,十六進制.由記憶體位址計算而來的.

  用途:比較兩個數組是否是同一個數組!!(記憶體位址值相同,肯定是同一個數組)

二、jvm記憶體結構:

1.棧:

    凡是方法中定義的變量(包括方法的形參)都是在棧中.

    棧中的變量沒有初始化值,使用之前必須手動指派.

    方法執行,變量就存在,方法執行完,變量所占用的空間自動釋放!

2.堆:

    凡是使用new關鍵字建立出來的對象都是在堆中!

    堆中的變量都有初始化值:(0/0.0/false/null)

    堆中的變量随着對象的存在而存在.當對象沒有任何引用指向它時,它所占用的空間由垃圾回收器負責回收. 

3.方法區:

    .class位元組碼檔案和方法定義

    System

    Scanner

    Math

4.本地方法棧:

5.程式計數器:

三、數組的周遊:traversal

  依次通路數組中每個元素的一種機制!

  使用循環(循環的是元素的索引)就可以周遊每個元素!

  循環的順序:從前往後,從後往前.

  ***數組操作的兩個常見異常:

  1.ArrayIndexOutOfBoundsException

    索引超出了正常值[0,數組的長度-1]範圍:

  2.NullPointerException

    一個數組變量,被賦予了null值,使用它去通路數組中的元素,發生空指針異常.

作業:

1.數組初始化的兩種格式:

2.什麼是數組的周遊?

3.jvm虛拟機的記憶體劃分成幾個區域,各個區域中的變量都有什麼特點?

4.定義一個方法,用于将一個int數組的偶數索引的元素抽取(extract)出來.

/*

    定義一個方法,用于将一個int數組的偶數索引的元素抽取出來.
    計算偶數索引元素的個數,建立新的數組,
    周遊源數組,判斷符合條件的,指派給新數組
    
*/
public class ExtractEvenIndexDemo{
    public static void main(String[] args){
        int[] arr = {1,2,3,4,5,6,7,8,9,0};
        int[] dest = extractEvenIndex(arr);
        printArray(dest);
    }
    
    public static void printArray(int[] arr){
        for(int i = 0;i<arr.length;i++){
            System.out.print(arr[i]);
            if(i != arr.length - 1){
                System.out.print(",");
            }
        }
        System.out.println();
    }
    
    
    //傳回值類型:int[]
    //形參清單:int[]
    public static int[] extractEvenIndex(int[] arr){
        //計算偶數索引的個數
        int[] dest = new int[(arr.length + 1) / 2];
        //周遊源數組,判斷
        int index = 0;
        for(int i = 0;i<arr.length;i++){
            if(i % 2 == 0){
                dest[index++] = arr[i];
            }
        }
        return dest;
    }
    
}      

5.定義一個方法,用于将一個數組逆序.注意方法的傳回值類型?即:逆序是否是産生了新的數組?

/*
    5.定義一個方法,用于将一個數組逆序.注意方法的傳回值類型?即:逆序是否是産生了新的數組?
    思路:
        并沒有産生新的數組,而是把源數組中的元素逆序了!!
    重點:有多少次兩兩交換??
        4 -> 2
        5 -> 2
        6 -> 3
        7 -> 3
        ...
        
*/
public class ReverseArrayDemo{
    public static void main(String[] args){
        int[] arr = {1,2,3,4,5,6,7};
        reverse(arr);
        printArray(arr);
        
    }
    
    public static void printArray(int[] arr){
        for(int i = 0;i<arr.length;i++){
            System.out.print(arr[i]);
            if(i != arr.length - 1){
                System.out.print(",");
            }
        }
        System.out.println();
    }
    //沒有傳回值:void
    //形參清單:int[]
    public static void reverse(int[] arr){
        //計算兩兩交換的次數
        int count = arr.length / 2 ;
        //循環交換兩個元素
        for(int i = 0;i<count;i++){
            //交換兩個元素
            int temp = arr[i];
            arr[i] = arr[arr.length - 1 - i];
            arr[arr.length - 1 - i] = temp;
        }
        
    }
}      

6.定義一個方法,用于将一個數組的所有元素變成它原來的元素和它前一個元素的和,(第一個元素除外!)

    即:若原數組為:[1,2,3,4,5]

    則方法執行後,數組變為:[1,3,5,7,9]

    注意:方法中不能建立新的數組!!!

/*
    1.從前往後周遊:用臨時變量儲存目前要修改的元素的值,更改後面元素的時候,就可以使用原來元素的值.
    2.從後往前周遊!用元素的值和它前一個元素的和替換目前元素!
*/
public class Demo1{
    public static void main(String[] args){
       int[] arr = {1,2,3,4,5};
       printArray(arr);
       // change1(arr);
       change2(arr);
       printArray(arr);
    }
    public static void printArray(int[] arr){
       for(int i = 0;i<arr.length;i++){
           System.out.print(arr[i]);
           if(i != arr.length - 1){
              System.out.print(",");
           }
       }
       System.out.println();
    }
   
    //第二種方式:從後往前周遊
    public static void change2(int[] arr){
       //
       for(int i = arr.length - 1;i>0;i--){
           arr[i] = arr[i] + arr[i - 1];
       }
    }
   
    //第一種方式:使用臨時變量儲存上一次被覆寫的元素的值
    public static void change1(int[] arr){
       //定義一個變量,初始值為第一個元素的值.
       int temp = arr[0];
       for(int i = 1;i<arr.length;i++){
           //先把目前元素的值保留下來.
           int x = arr[i];
           //替換目前元素的值
           arr[i] = arr[i] + temp;
           //把目前元素原來的值,指派給temp
           temp = x;
       }
    }
}      

7.定義一個方法,用于模拟裁判打分的程式:一共有5個裁判打分,去掉一個最高分,去掉一個最低分.

取剩餘分數的平均值為最終的得分!!!注意:分數的資料類型!!!

重點:自定義方法之間的互相調用!!!

/*
定義一個方法,用于模拟裁判打分的程式:一共有5個裁判打分,去掉一個最高分,去掉一個最低分.
取剩餘分數的平均值為最終的得分!!!注意:分數的資料類型!!!
 
方法之間是互相調用的關系:
    自定義方法中可以使用jdk提供好的方法(比如列印方法),也可以調用自定義方法!!!
*/
public class MarkDemo{
    public static void main(String[] args){
       int[] scores = {10,20,10,15,25};
       System.out.println("最終得分是: " + mark(scores));
    }
   
    //double
    //int[] scores
    public static double mark(int[] scores){
       //計算分數之和
       // System.out.println("abc");//自定義方法中調用jdk提供的方法
       int sum = getSum(scores);//自定義方法中調用自定義方法!!
      
       //減去最高分,最低分
       //求平均分傳回
       return (sum - getMax(scores) - getMin(scores)) / 3.0;
    }
   
    //最高分(最大值)
    public static int getMax(int[] scores){
       int max = scores[0];
       for(int i = 1;i<scores.length;i++){
           if(scores[i] > max){
              max = scores[i];
           }
       }
       return max;
    }
   
    //最低分(最小值)
    public static int getMin(int[] scores){
       int min = scores[0];
       for(int i = 1;i<scores.length;i++){
           if(scores[i] < min){
              min = scores[i];
           }
       }
       return min;
    }
   
    //求數組所有元素之和
    public static int getSum(int[] scores){
       //定義變量,初始值為0
       int sum = 0;
       for(int i = 0;i<scores.length;i++){
           sum += scores[i];
       }
       return sum;
    }
}      

8.定義一個方法,用于取出一個數組中所有偶數元素組成的數組!

/*
    定義一個方法,用于取出一個數組中所有偶數元素組成的數組!
    首先計算偶數元素的個數,用個數建立一個新的數組,
    周遊源數組,把符合條件的元素指派給新數組
   
    兩次周遊:
       1.求偶數元素的個數
       2.指派
*/
public class ExtractEvenElementDemo{
    public static void main(String[] args){
       int[] src = {1,2,3,4,5,6,67,7,8};
       printArray(src);
      
       int[] dest = extractEvenElement(src);
      
       printArray(dest);
    }
    public static void printArray(int[] arr){
       for(int i = 0;i<arr.length;i++){
           System.out.print(arr[i]);
           if(i != arr.length - 1){
              System.out.print(",");
           }
       }
       System.out.println();
    }
   
    //傳回值類型:int[]
    //形參清單:int[] src
    public static int[] extractEvenElement(int[] src){
       //第一次周遊,求偶數元素的個數
       int len = 0;
       for(int i = 0;i<src.length;i++){
           if(src[i] % 2 == 0){
              len++;
           }
        }
      
       //建立新數組
       int[] dest = new int[len];
       //第一次周遊,求偶數元素的個數
       int index = 0;
       for(int i = 0;i<src.length;i++){
           if(src[i] % 2 == 0){
              dest[index++] = src[i];
           }
       }
       return dest;
    }
}
       

9.定義一個方法,用于取出一個數組中指定索引範圍的元素組成的數組!!

    例如:可以取出一個數組第2個到第5個索引組成的數組!

/*
定義一個方法,用于取出一個數組中指定索引範圍的元素組成的數組!!
    例如:可以取出一個數組第2個到第5個索引組成的數組!
思路:
    根據傳遞進來的兩個數,确定要截取的範圍:
    用這個範圍的長度去建立一個新數組,
    周遊源數組,指派!
   
*/
public class GetArrayDemo{
    public static void main(String[] args){
       int[] arr = {1,2,3,4,5,6,7,8,9,0};
       int[] dest = getArray(arr,2,5);
       printArray(dest);
    }
   
    public static void printArray(int[] arr){
       for(int i = 0;i<arr.length;i++){
           System.out.print(arr[i]);
           if(i != arr.length - 1){
              System.out.print(",");
           }
       }
       System.out.println();
    }
   
    //int[]
    //int[] arr,int start,int end
    public static int[] getArray(int[] arr,int start,int end){
       //計算目标元素的個數
       int len = end - start + 1;
       //建立新數組
       int[] dest = new int[len];
       //周遊源數組指派
       int index = 0;
       for(int i = start;i<=end;i++){
           dest[index++] = arr[i];
       }
       //
       return dest;
    }
}
 
       

選作題:

用數組實作:産生一個有5個範圍在(1-100)之間的随機數元素的數組,要求元素不能重複!!!

/*
選作題:
用數組實作:産生一個有5個範圍在(1-100)之間的随機數元素的數組,要求元素不能重複!!!
思路:
    先産生一個有預設值的數組,
    周遊,每次都産生一個随機數,拿這個随機數到數組中判斷
       如果已經存在,就再次産生一個随機數,再次進行判斷
       如果不存在,就直接給目前的元素指派!
*/
public class GetRandomArrayDemo{
    public static void main(String[] args){
       int[] arr = new int[5];//0
      
       //周遊數組,産生随機數,判斷,符合條件再對元素指派
       for(int i = 0;i<arr.length;i++){
           int r = (int)(Math.random() * 100);
           //判斷是否已經在數組中!
           /*
           while(exists(arr,r)){ //true ,表明已經存在,再次産生一個新的随機值!
              r = (int)(Math.random() * 100) + 1;
           }
           */
           //優化後的方法,需要三個參數,第二個參數表明比較的範圍
           while(exists2(arr,i,r)){ //true ,表明已經存在,再次産生一個新的随機值!
              r = (int)(Math.random() * 100);
           }
          
           //false意味着數組中不存在這個随機值,那就直接指派
           arr[i] = r;
       }
       //檢視
       printArray(arr);
    }
   
    public static void printArray(int[] arr){
       for(int i = 0;i<arr.length;i++){
           System.out.print(arr[i]);
           if(i != arr.length - 1){
              System.out.print(",");
           }
       }
       System.out.println();
    }
   
    //優化後的方法:第二個參數表示比較的範圍:隻比較目前數組中已經指派的元素!!!
    //優點:1.減少了比較的次數.2.避免了初始值是0值的問題!!!
    public static boolean exists2(int[] arr,int count,int value){
       //周遊數組,比較count之前的值是否和value相等
       for(int i = 0;i<count;i++){
           if(arr[i] == value){
              return true;
           }
       }
       //程式走到這裡,說明for循環中沒有碰到相同的數(即:value在數組中不存在)
       return false;
    }
   
    //boolean
    //int[] arr,int value
    public static boolean exists(int[] arr,int value){
       //周遊數組,如果遇到相同的值,就傳回true,否則傳回false
       for(int i = 0;i<arr.length;i++){
           if(arr[i] == value){
              return true;
           }
       }
       //程式走到這裡,說明for循環中沒有碰到相同的數(即:value在數組中不存在)
       return false;
    }
}
       

 -----------------------------------------------------------------------new-----------------------------------------------------------------

對象

一、參數傳遞的原則:值傳遞

  Java中,方法調用時,不論形參是基本資料類型還是引用資料類型,

  實際上都是實參的副本傳遞給方法的形參!!

  數組類型的參數,在方法體外能看到方法體中對數組元素的更改!!

  基本資料類型,在方法體外,看不到方法體中對資料的更改!!

二、面向對象的概念:

  1.面向對象程式設計:  

  OOP:object oriented programming,也就是在程式中,直接操作的是對象,而不是一個個的函數!

  

  和此相對應的思想是:面向過程程式設計思想:procedual(過程化)

  要實作一個功能,每一步的操作都必須自己實作.都是通過一個個的函數調用實作!

  (C語言就是典型的過程化語言!)

  面向對象程式設計,考慮的是誰有我想要實作的功能:

  舉例:

    組裝電腦:

    喝咖啡:

    建造汽車:

  2.面向對象思想的好處:

    1> 讓程式員從執行者變成了指揮者

    2> 更符合人類思維的程式設計思想!

    3> 将複雜的事情簡單化!

  面向對象開發,實際上就是維護對象之間的關系:

  例如:張三會開鎖,李四會撬門,王五會開叉車.

if(張三.開鎖() == ok){
    王五.開叉車();
}else if(李四.撬門() == ok){
    王五.開叉車();
}else{
    撤退!!!
}
      

  3.面向對象的三大特點:

    封裝,繼承,多态  -- 後面詳講!!!

三、類和對象:

  1.類:是對現實世界中事物的一種抽象表示!

  2.現實世界中事物的描述方法:

    1>靜态的屬性資訊:顔色,價格,尺寸大小...

    2>功能或者行為:run,eat...

  3.Java中使用類來描述事物:

      電腦:          Java類:

      屬性資訊    ->  成員變量:

      功能或者行為->  成員方法:

例如:

public class Computer{
    //成員變量
    String color = "black";
    double price = 2000.0;
    int size = 16;
    //成員方法
    public void playMusic(){...}
    public void playMovie(){...}
}      

4.類是一類事物的抽象形式:

  如何來的?

  應該是現實真實存在的一類事物,或者是腦海中的一個概念!

  将它們共同的屬性和行為抽取出來就是類!!

  類一般情況下,都不能直接使用.

必須建立對象!!

從類到具體的對象.稱為執行個體化過程(建立).

Person類定義的過程:

Dog類定義的過程:

四、類成員的寫法:

  1.成員變量:

      和之前定義變量的規則一樣

      寫在類中,成員方法的外邊

  2.成員方法:

      和之前定義方法的規則一樣

      暫時去掉static

NoteBook.java

/*
    NoteBook類的定義:
    一個類一般是不能直接使用的,我們使用的是類所建立的對象.
    使用new關鍵字,就可以建立一個類的對象(執行個體化的過程).
   
    一般情況下是在main方法中建立對象.
    main方法可以寫在普通類中,或者是一個單獨的測試類中.
   
    建立對象的文法:
       類名 對象名 = new 類名();
   
    對象的使用:
       通路對象的成員變量
       調用對象的成員方法
   
    main方法和普通類沒有所屬關系,一般都會單獨的放到一個專門的測試類中.
    這個測試類主要目的就是為了放main方法.!!!
   
*/
public class NoteBook{
    //成員變量
    String brand = "ASUS";
    int memory = 8;
    int price = 6000;
    String owner = "張三";
   
    //成員方法
    public void type(String content){
       System.out.println("正在列印: " + content);
    }
    //
    public void playMusic(String name){
       System.out.println("播放歌曲: " + name);
    }
   
    //顯示自己的屬性資訊
    public void showInfo(){
       System.out.println("brand : " + brand + ", memory : " + memory + ", price : " + price + ", owner : " + owner);
    }
   
    /*
    //在普通類中寫main方法
    public static void main(String[] args){
       //在這裡建立對象
       NoteBook book1 = new NoteBook();
      
       //通路book1 的成員變量
       System.out.println("book1.brand : "+ book1.brand);
       System.out.println("book1.price: " + book1.price);
       System.out.println("book1.memory: " + book1.memory);
       System.out.println("book1.owner : " + book1.owner);
      
       //調用book1的成員方法
       book1.type("hello world");
       book1.playMusic("<<我站在草原望北京>>");
       book1.showInfo();
      
    }
    */
}      

五、對象的建立

格式:

類名 對象名 = new 類名();

NoteBookDemo.java

/*
    NoteBook類的測試類:
    如果在源檔案中出現了沒有經過編譯的源檔案,那就一起編譯!!!
   
*/
public class NoteBookDemo{
    public static void main (String[] args){
       //建立對象
       NoteBook book1 = new NoteBook();
      
       //通路book1 的成員變量
       System.out.println("book1.brand : "+ book1.brand);
       System.out.println("book1.price: " + book1.price);
       System.out.println("book1.memory: " + book1.memory);
       System.out.println("book1.owner : " + book1.owner);
      
       //調用book1的成員方法
       book1.type("hello world");
       book1.playMusic("<<我站在草原望北京>>");
       book1.showInfo();
      
    }
}      

對象的使用:

  目前,對象基本上就是兩個方面可供使用:

    > 成員變量的通路(access)

    > 成員方法的調用(invoke/call)

  

  •   成員之間是可以互相使用的!
  •   成員變量可以使用成員方法的傳回值
  •   成員方法可以使用成員變量的值!

六、一個對象的記憶體圖解:

重點:

方法區的概念

成員變量的初始化

方法區:用于存放.class位元組碼檔案和方法定義的空間(方法并不是每個執行個體對象都儲存一份,隻是引用了方法定義的位址而已!!方法區又稱為共享區!!!)

成員變量的初始化:系統的預設初始化之後,才進行顯式的初始化!

七、兩個對象的記憶體圖解:

.class位元組碼檔案隻是第一次使用時加載,以後再次使用,不會多次加載!!!

不同對象有自己不同的成員變量值,但是方法都是引用方法區中的位址!!!

八、兩個變量指向同一個對象圖解:

重點:

多個對象名對執行個體對象成員變量的更改,通過其它對象名也是可以看到的.

重點:

1.方法區中存放的是程式中使用到的.class位元組碼檔案,同一個位元組碼檔案會在第一次使用時加載,不會多次加載.

2.不同對象中并不會儲存方法的代碼,隻是儲存了方法的位址引用而已.也就是說:方法區中的東西都是被不同的對象所共享的.方法區也稱為共享區!

3.在對象的建立時,對象的成員變量首先進行預設的初始化,然後是顯式的初始化(在類定義時對成員變量的指派!).

在對象建立後,可以通過對象名.成員變量名的方式對成員變量進行更改!

Dog d = new Dog();

d.name = "abc";//如果沒有顯式初始化的話,name這個變量被指派了兩次:

第一次是jvm預設初始化,第二此時用對象名.變量名的方式指派!

=============

main方法一般是單獨放到一個源檔案中,

為了查找類友善.合二為一啦!

把普通類定義和含main方法的測試類放到一個源檔案中!!

/*
    對Phone類的測試類
    
*/

/*
    自定義手機類
    
*/
class Phone{
    //成員變量
    String brand; //null
    int price = 2000;
    
    //成員方法
    public void call(String name){
        System.out.println("給 " + name + " 打電話");
    }
    //
}

public class PhoneDemo{

    public static void main(String[] args){
        //建立對象
        Phone p = new Phone();
        
        //先對成員變量指派
        p.brand = "iphone";
        p.price = 8000;
        System.out.println("品牌: " + p.brand + ",價格: " + p.price);
        
        //調用成員方法
        p.call("Obama");
    }
    
}      

題目:以Phone p = new Phone();這條語句為例,簡述在記憶體中都發生了什麼樣的變化!

  1. 在Phone對象的建立時,對象的成員變量首先進行預設的初始化,然後是顯式的初始化(在類定義時對成員變量的指派!)
  2. 在堆空間中開辟一片空間,把成員變量指派(預設的初始化值,顯示初始化),
  3. 把對象把對象的記憶體的空間位址值指派給變量p
  4. main方法一般單獨放到一個原檔案當中,為了查找友善,把普通類定義和含main方法的測試類放到一個源檔案當中