0%

Java 複習1 - Basic

近期準備轉換跑道,即使是資料工程師的職缺也不全然都是用Python的,也有用Java或是用C/C++的企業。因此,想說趁著空窗期的這段時間稍微回顧一下Java的資料型態和一些邏輯。

變數

相較於Python的動態型別,Java是強型別的語言,所有變數都必須在宣告時指定型態。

1
2
3
4
# 這是 Python
this_is_name = "Bob"
this_is_int = 10
this_is_float = 20.0
1
2
3
4
5
6
// 這是 Java
int num1;
int num2 = 5;

char name1;
char name2 = 'Bob';

記憶體區間

在Java程式執行期間,記憶體可以分為三個部分:Global、Stack、Heap。

Global

用來放全域變數、靜態變數。

Stack

Stack是由作業系統自動化管理的記憶體區塊。為了讓系統能夠清楚且有效地管理這些資源,Stack中所存放的資訊,通常在編譯的時候就能預先計算好它們的生命週期。也因為這樣,Stack主要用來存放以下這些能夠明確掌控生命週期的資料:

  • 區域變數 Local Variables
  • 方法的參數 Method Parameters
  • 方法的回傳位址 Method Return Address

這些資料會隨著方法的執行而進入Stack,方法執行完畢後,對應的記憶體就會直接被回收,過程完全由系統自動處理,開發者不需要手動管理。

然而,Stack空間是有限的。如果一次塞入太多資料,像是遞迴沒寫好導致無限呼叫,或是方法堆疊過深,就會造成StackOverflowError,這表示Stack的記憶體被用光光啦!

Heap

能夠被預測生命週期的資料,就會放在Stack;反過來,無法預測生命週期或大小的資料,就會被放進Heap。在Java裡,只要是透過new關鍵字產生的物件,基本上都會被存進Heap裡。不過,Heap跟Stack最大的不同點在於:Heap裡的記憶體不會自動回收。換句話說,資料放進Heap之後,系統不會幫你決定什麼時候把這塊記憶體清掉,如果一直放著不用,記憶體就會越佔越多,最後可能導致系統記憶體耗盡。

幸好,Java幫我們設計了一個「垃圾回收機制(Garbage Collection, GC)」。這套機制會在程式執行過程中自動檢查:哪些物件已經不再被使用,然後主動把它們佔用的記憶體釋放出來。這樣一來,Java開發者就不用自己負責手動釋放記憶體,程式設計的負擔也少很多。

不過要注意,Heap還是有上限的。如果產生太多物件、或記憶體被撐爆,最終遇到OutOfMemoryError,告訴你Heap空間不夠用了。

小提醒:這不是資料結構裡的Heap(堆積樹)喔!

資料型態

Java 的資料型態種類有兩種:

  • 基本資料型態 Primitive type
  • 參考資料型態 Reference type

基本資料型態

Java 有以下八種預先定義好的資料型態:boolean, char, byte, short, int, long, float, double。

名稱 位元數
boolean true / false
char 16 ‘\u0000’ to ‘\uFFFF’
byte 8 -128 ~ +127
short 16 -32768 ~ +32767
int 32 -2147483648 ~ +2147483647
long 64 -9223372036854775808 ~ +9223372036854775807
float 32 -3.40292347E+38 ~ +3.40292347E+38
double 64 -1.7976931348623157E+308 ~ +1.7976931348623157E+308

參考資料型態

在Java中,所有非基本資料型態的類型都屬於參考資料型態。例如:字串String、自定義的class、陣列Array、介面Interface、列舉enum…

Overload 溢位

從上表中可以看到,每個基本資料型態都有他的數值範圍,如果運算過程中超出了他可以表示的範圍,就會發生溢位。

1
2
3
4
5
6
7
8
9
10
11
int intmax=java.lang.Integer.MAX_VALUE;

System.out.println("Max value of int : "+intmax);

int sum;

sum = intmax +1;
System.out.println("intmax +1= "+sum); //印出 intmax +1 的值

sum = intmax +100;
System.out.println("intmax +100= "+sum); //印出 intmax +100 的值

執行結果:

1
2
3
Max value of int : 2147483647
intmax +1= -2147483648
intmax +100= -2147483549

溢位是容易發生的程式錯誤,我們必須要清楚自己所處理的資料可能會到多少數值範圍,而選用適當的資料型態,或是加上檢查數值範圍的功能。

基本與參考資料型態之差異

運算子

這應該不用特別紀錄XD,這是程式設計的基礎中的基礎,下面單純做一個紀錄。

一元運算子

一元運算子只需要一個運算元

一元運算子 含義
+ 正號
- 負號
! NOT 否定
~ 取 1 補數

算數運算子

算數運算子 含義
+ 加法
- 減法
* 乘法
/ 取商數
% 取餘數

關係運算子

關係運算子 含義
> 大於
< 小於
>= 大於等於
<= 小於等於
== 相等
!= 不等於

遞增與遞減運算子

遞增與遞減運算子 含義
++ 遞增,變數加1
遞減,變數減1

邏輯運算子

邏輯運算子 含義
&& AND
  • &&: 兩者都為真,結果才會為真。
  • ||: 只要其中一個為真,結果就會為真。

三元運算子

三元,就是要放入三個東西。

1
判斷式 ? 若判斷為真執行區塊 : 若判斷為假執行區塊

範例如下:

1
2
3
4
5
6
7
8
9
10
11
int a = 100;
int b = 20;
int c = 10;

boolean flag = true;
c = flag ? a : b;
System.out.println(c);

flag = false;
c = flag ? a : b;
System.out.println(c);

執行結果:

1
2
100
20

仔細搞懂就會發現,他其實就是 if else 的縮寫!

1
2
3
4
5
if(flag){
c = a
}else{
c = b
}

型態比對運算子

在寫程式的時候,有時會需要檢查某個物件是否屬於指定的類別(class)、子類別(subclass)或介面(interface)。登登登!這時候我們就需要instanceof來做判斷,他會回傳boolean。

1
2
3
4
5
6
7
8
9
10
11
12
public class App {
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println(a instanceof A);
System.out.println(a instanceof B);
System.out.println(b instanceof B);
System.out.println(b instanceof A);
}
}
class A { }
class B extends A { }

執行結果:

1
2
3
4
true  // a是A物件
false // a不是B物件
true // b是B物件
true // B繼承A,b是A的子類別,所以為true

參考:https://yubin551.gitbook.io/java-note/basic_java_programming/datatype/primitive_reference_difference