前情回顧
- No 1. 搭建 Java 開發環境
- No 2. 玩轉 IDEA
在之前的文章中,我們已經介紹瞭如何搭建 Java 開發環境以及如何使用 IDEA,現在就開始正式學習 Java 語言的相關語法吧!😎
本文內容預告如下:
- 變量
- 數據類型
- 變量作用域
- 常量
變量
什麼是變量?
所謂變量,就是用來命名一個數據的標識符,在 Java 中,變量又可以分為兩種:
- 基本類型的變量
- 引用類型的變量
// 基本類型的變量
int id = 1;
// 引用類型的變量
String name = "村雨遙";
其中 int 是基本數據類型,表示這是一個整型數;而 String 則是引用類型,表示這是一個引用類型;
id 和 name 則是標識符,也就是我們所説的 變量;
= 則是賦值操作符,而 1 則是基本類型的值,村雨遙 則是引用類型的值;
變量的特點
變量的最重要的一個特點就是可以重新賦值;
public class Main {
public static void main(String[] args) {
// 定義int類型變量id,並賦予初始值1
int id = 1;
// 打印該變量的值,觀察是否為1
System.out.println(id);
// 重新賦值為2
id = 2;
// 打印該變量的值,觀察是否為2
System.out.println(id);
}
}
變量命名規則
變量命名也是一門學問,並不是我們想怎麼命名就怎麼命名,日常開發中最常見的變量命名規則主要有如下幾條:
- 強制:變量命名只能使用 字母(大小寫均可)、數字、$、_;
- 強制:變量名不能使用關鍵字(就是 Java 中內置的一些關鍵字,如
int、for、long…); - 強制:變量第一個字符不能使用數字,只能用字母、
$、_; - 更多命名規則推薦參考阿里巴巴推出的《Java 開發手冊》,下載鏈接:https://github.com/cunyu1943/...
常見關鍵字
這是一種事先定義好的,有特定意義的標識符,也叫做保留字。對於 Java 編譯器有着特殊意義,用來表示一種數據類型,或者表示程序的結構等。此外,關鍵字不能用作變量名、方法名、類名、包名和參數名。常見的關鍵字可以分為如下幾類,具體的關鍵字如下圖所示:
- 訪問控制類
- 類、方法及變量修飾符類
- 程序控制類
- 錯誤處理
- 包相關
- 基本類型
- 變量引用
- 保留字
數據類型
基本數據類型
Java 中,共有 8 中基本數據類型,由 Java 語言預定好的,每個數據類型都屬於關鍵字,而且每種基本變量都有其對應的封裝類,這 8 中基本數據類型分別是:
- 整型(4 種)
- 浮點型(2 種)
- 字符型(1 種)
- 布爾型(1 種)
| 數據類型 | bit | 字節 | 封裝類 | 數據範圍 | 默認值 |
|---|---|---|---|---|---|
byte |
8 | 1 | Byte |
$-2^7$ ~ $2^7-1$ | 0 |
short |
16 | 2 | Short |
$-2^{15}$ ~ $2^{15}-1$ | 0 |
char |
16 | 2 | Character |
\u0000 ~ \uffff($0$ ~ $65535$) |
u0000 |
int |
32 | 4 | Integer |
$-2^{31}$ ~ $2^{31}-1$ | 0 |
long |
64 | 8 | Long |
$-2^{63}$ ~ $2^{63}-1$ | 0L |
float |
32 | 4 | Float |
$3.4e^{-45}$ ~ $1.4e^{38}$ | 0.0f |
double |
64 | 8 | Double |
$4.9e^{-324}$ ~ $1.8e^{308}$ | 0.0D |
boolean |
1 | 不確定 | Boolean |
true 或 false |
false |
注意:
boolean一般用 1bit來存儲,但是具體大小並未規定,JVM 在編譯期將boolean類型轉換為int,此時 1 代表true,0代表false。此外,JVM 還指出boolean數組,但底層是通過byte數組來實現;- 使用
long類型時,需要在後邊加上L,否則將其作為整型解析,可能會導致越界; - 浮點數如果沒有明確指定
float還是double,統一按double處理; char是用 單引號''將內容括起來,只能存放一個字符,相當於一個整型值(ASCII 值),能夠參加表達式運算;而String是用 雙引號""將內容括起來,代表的是一個地址值;- Java 在內存中是採用 Unicode 表示,所以無論是一箇中文字符還是英文字符,都能用
char來表示;
那麼如何個一個基本類型變量賦值呢?
在 Java 中,基本數據類型屬於 Java 的一種內置的特殊數據類型,不屬於任何類,所以可以直接對其進行賦值;給基本類型的變量賦值的方式就叫做 字面值;
float score = 89.0f;
int age = 26;
引用數據類型
常見引用數據類型
| 數據類型 | 默認值 |
|---|---|
| 數組 | null |
| 類 | null |
| 接口 | null |
而對於引用數據類型,我們經常是需要 new 關鍵字來進行賦值,但是引用類型中的 接口是不能被實例化的,我們需要對其進行實現;
// 初始化一個對象
Pet dog = new Pet();
// 初始化一個數組
int[] arr = new int[10];
String
對於引用數據類型中的 String,我們需要特別關注。
String 不同於 char,它屬於引用類型,而 char 屬於基本數據類型。用雙引號 "" 括起來表示字符串,一個字符串能夠保存 0 個到任意個字符,它一旦創建就不能被改變。
而針對字符串,如果我們要打印一些特殊的字符,比如字符串本來就包含 ",那麼這個時候就需要藉助於轉義字符 \,最常見的轉義字符主要有:
| 轉義字符 | 含義 |
|---|---|
\" |
字符 " |
\' |
字符 ' |
\\ |
字符 \ |
\n |
換行符 |
\t |
製表符 Tab |
\r |
回車符 |
那多個字符串之間或者字符串和其他類型數據之間,該如何進行連接呢?
Java 編譯器中,對於字符串和其他數據類型之間,可以使用 + 進行連接,編譯器會自動將其他數據類型自動轉換為字符串,然後再進行連接;
String 既然是不可變,那有什麼優點呢?
- 用於緩存
hash值
由於 String 的 hash 值被頻繁使用,它的不可變性使得 hash 值也不可變,此時只需要進行一次計算;
- 字符串常量池(String Pool)的需要
如果一個 String 對象已經被創建過,那麼就會優先從字符串常量池中獲取其引用,其不可變性確保了不同引用指向同一 String 對象;
- 安全性
我們經常用 String 作為我們方法的參數,其不變性能夠保證參數不可變;
- 線程安全
String 的不可變性讓它天生 具備線程安全,能夠在多個線程中方便使用而不用考慮線程安全問題。
String、StringBuilder、StringBuffer 對比,該如何選擇?
| 可變性 | 線程安全 | 適用場景 | |
|---|---|---|---|
String |
不可變 | 安全 | 操作少量的數據 |
StringBuffer |
可變 | 安全,內部使用 synchronized 進行同步 |
多線程操作字符串緩衝區下操作大量數據 |
StringBuilder |
可變 | 不安全 | 單線程操作字符串緩衝區下操作大量數據,性能高於 StringBuffer |
通過 new String(“xxx”) 創建字符串的兩種情況?
使用 new 的方式創建字符串對象,會有兩種不同的情況:
- String Pool 中不存在 “xxx”
此時會創建兩個字符串對象,“xxx” 屬於字符串字面量,因此在編譯期會在 String Pool 中創建一個字符串對象,用於指向該字符串的字面量 “xxx”;然後 new 會在堆中創建一個字符串對象;
- String Pool 中存在 “xxx”
此時只需要創建一個字符串對象,由於 String Pool 中已經存在指向 “xxx” 的對象,所以直接在堆中創建一個字符串對象;
數據類型轉換
對於基本數據類型,不同類型之間是可以相互轉換的,但是需要滿足一定的條件;
從小到大自動轉,從大到小強制轉。
即就是,對於低精度的數據類型,如果要轉換為高精度的數據類型,直接將低精度的值賦給高精度的值即可;
但對於高精度的數據類型,如果想要轉換為低精度的數據類型,則需要採用 強制轉換 的手段,但此時需要承擔精度丟失的風險,就像從一個大杯子往一個小杯子裏倒水,你要做好小杯子可能裝不下溢出的情況;
int a = 110;
long b = 113;
// 低精度轉高精度,由於 long 的範圍比 int 大,所以可以自動轉
b = a;
// 高精度住哪低精度,由於 long 的範圍比 int 大,所以需要強制轉
a = (int)b;
隱式轉換(自動類型轉換)
當滿足如下條件時,如果將一種類型的數據賦值給另一種數據類型變量時,將執行自動類型轉換:
- 兩種數據類型彼此兼容;
- 目標數據類型的取值範圍大於源數據類型;
一般而言,隱式轉換的規則是從低級類型數據轉換為高級類型數據,對應規則如下:
- 數值類型:
byte -> short -> int -> long -> float -> double- 字符類型轉整型:
char -> int
顯式轉換(強制類型轉換)
那既然滿足上述兩個條件時會發生隱式轉換,那不滿足同時我們又想進行數據類型轉換時,我們該怎麼辦呢?
這個時候就需要我們的 顯式轉換 登場了,其語法格式如下:
(type) variableName;
我們舉個 🌰 來説下:
int num = 3;
double ans = 5.0;
// 要將 double 類型的值賦值給 int,則需要強制轉換
num = (int)ans;
注意:強制轉換可能會導致精度丟失,所以一般情況下儘量能不用就不用。
常見數據類型轉換方法
- 字符串與其他類型之間的轉換
- 其他類型 -> 字符串
- 調用類的串轉換方法:
X.toString();- 自動轉換:
"" + X;- 利用
String的方法:String.valueOf(X);
// 方法 1
String str1 = Integer.toString(int num);
String str2 = Long.toString(long num);
String str3 = Float.toString(flaot num);
String str4 = Double.toString(double num);
// 方法 2
String str = "" + num ; // num 是 int、long、float、double 類型
// 方法 3
String str1 = String.valueOf(int num);
String str2 = String.valueOf(long num);
String str3 = String.valueOf(float num);
String str4 = String.valueOf(double num);
- 字符串 - > 其他類型
- 調用
parseXXX方法,比如parseLong、parseFloat、parseDouble...; - 先調用
valueOf(),方法,然後再調用xxxValue()方法;
// 方法 1
int num1 = Integer.parseInt(String str);
Long num2 = Long.parseLong(String str);
Float num3 = Float.parseFloat(String str);
Double num4 = Double.parseDouble(String str);
// 方法 2
int num1 = Integer.valueOf(String str).intValue();
Long num2 = Long.valueOf(String str).longValue();
Float num1 = Float.valueOf(String str).floatValue();
Double num1 = Double.valueOf(String str).doubleValue();
- int、float、double 之間的轉換
float -> double
float num = 1.0f;
Float num1 = new Float(num);
double num2 = num1.doubleValue();
double -> float
double num = 100.0;
float num1 = (float)num;
double -> int
double num = 100.0;
Double num1 = new Double(num);
int num2 = num1.intValue();
int -> double
int num = 200;
double num1 = num;
變量作用域
我們已經學會了如何定義變量,也知道了使用各種數據類型來定義變量。但是還有一點不知道大家有沒有注意到,如果我們的定義變量在不同的位置,其作用是不是相同的呢?
這就涉及到變量的作用域,一般根據其作用域的不同,可以分為:
- 成員變量:定義在方法體和語句塊外,不屬於任何一個方法,能在整個類中起作用;
- 局部變量:定義在方法或方法體中的變量,作用域是其所在的代碼塊;
成員變量
成員變量又可以分為 全局變量(又叫實例變量) 和 靜態變量(也叫類變量),兩者的區別如下:
| 名稱 | 修飾符 | 訪問方式 | 生命週期 |
|---|---|---|---|
| 全局變量 | 無 | 對象名.變量名 | 一旦對象被引用,則實例變量就存在 |
| 靜態變量 | static |
類名.變量名 | 同類共生死,只有當類被 GC 回收時才會被銷燬 |
public class Person {
// 成員變量,全局變量
String name;
// 成員變量,全局變量
int age;
// 成員變量,靜態變量
public static final String wechatPublic = "公眾號:村雨遙";
// 成員變量,靜態變量
public static final String website = "http://cunyu1943.site";
}
局部變量
成員變量指定義在方法或方法體中的變量,作用域是其所在的代碼塊,可以分為如下三種:
- 形參
public class Main {
// 方法中的參數
public static void func(int num) {
System.out.println("num = " + num);
}
public static void main(String[] args) {
func(3);
}
}
- 方法內定義
public class Main {
public static void main(String[] args) {
int num = 10;
if (num > 5) {
// 聲明一個 int 類型的局部變量
int tmp = 5;
System.out.println("tmp = " + tmp);
System.out.println("num = " + num);
}
System.out.println("num = " + num);
}
}
- 代碼塊定義
public class Main {
public static void func() {
try {
System.out.println("Hello!Exception!");
} catch (Exception e) { // 異常處理塊,參數為 Exception 類型
e.printStackTrace();
}
}
public static void main(String[] args) {
func();
}
}
常量
簡介
既然有變量,那就有與之相對的常量(也就是值是固定的,不能再變)。
常量又叫做字面常量,是通過數據直接來表示的,在程序運行過程中不能發生改變。通常我們把 Java 中用 final 關鍵字所修飾的成員變量叫做常量,它的值一旦給定就無法再進行改變!
分類
Java 中使用 final 關鍵字來聲明常量,其語法格式如下:
final 數據類型 常量名 = 常量初始值;
public class Main{
public static void main(String[] args){
// 聲明一個常量並賦值
final int num = 1024;
// 再次賦值,將導致編譯錯誤
num = 1943;
// 聲明一個常量但不賦值
final int id;
// 因為聲明時未賦值,所以可以進程初次賦值
id = 1;
// 常量已經賦值過了,再次賦值將導致編譯錯誤
id = 2;
}
}
常量可以分為如下 3 種類型:
- 靜態常量:
final之前用public staic修飾,表示該常量的作用域是全局的,我們不用創建對象就能夠訪問它。 - 成員常量:類似於成員變量,但是最大的不同在於它不能被修改。
- 局部常量:作用類似於局部變量,不同之處也在於不能修改。
public class Main{
// 靜態變量
public static final dobule PI = 3.14;
// 成員常量
final int num = 1024;
public static void main(String[] args){
// 局部變量
final long count = 1000;
}
}
PS:final 修飾變量後,該變量則變為常量。而 final 也還可以用來修飾類和方法,修飾方法時,表示這個方法不能被重寫(但可以重載);修飾類時,則表明該類無法被繼承。這些東西這時候你可能會覺得很陌生,不過等我們後續學習了面向對象之後,你就會發現其實很簡單。
總結
碼字不易,如果覺得對您有所幫助,可以點贊關注一波哦!🙏
博主水平有限,對於文中可能出現的錯誤,還請各位批評指正,來評論區一起聊天吧!