回顧
一、數組
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();這條語句為例,簡述在記憶體中都發生了什麼樣的變化!
- 在Phone對象的建立時,對象的成員變量首先進行預設的初始化,然後是顯式的初始化(在類定義時對成員變量的指派!)
- 在堆空間中開辟一片空間,把成員變量指派(預設的初始化值,顯示初始化),
- 把對象把對象的記憶體的空間位址值指派給變量p
- main方法一般單獨放到一個原檔案當中,為了查找友善,把普通類定義和含main方法的測試類放到一個源檔案當中