No 3. 變量與數(shù)據(jù)類(lèi)型
前情回顧
在之前的文章中,我們已經(jīng)介紹了如何搭建 Java 開(kāi)發(fā)環(huán)境以及如何使用 IDEA,現(xiàn)在就開(kāi)始正式學(xué)習(xí) Java 語(yǔ)言的相關(guān)語(yǔ)法吧!??
本文內(nèi)容預(yù)告如下:
變量 數(shù)據(jù)類(lèi)型 變量作用域 常量
變量
什么是變量?
所謂變量,就是用來(lái)命名一個(gè)數(shù)據(jù)的標(biāo)識(shí)符,在 Java 中,變量又可以分為兩種:
基本類(lèi)型的變量 引用類(lèi)型的變量
// 基本類(lèi)型的變量
int id = 1;
// 引用類(lèi)型的變量
String name = "村雨遙";
其中 int 是基本數(shù)據(jù)類(lèi)型,表示這是一個(gè)整型數(shù);而 String 則是引用類(lèi)型,表示這是一個(gè)引用類(lèi)型;
id 和 name 則是標(biāo)識(shí)符,也就是我們所說(shuō)的 變量;
= 則是賦值操作符,而 1 則是基本類(lèi)型的值,村雨遙 則是引用類(lèi)型的值;
變量的特點(diǎn)
變量的最重要的一個(gè)特點(diǎn)就是可以重新賦值;
public class Main {
public static void main(String[] args) {
// 定義int類(lèi)型變量id,并賦予初始值1
int id = 1;
// 打印該變量的值,觀察是否為1
System.out.println(id);
// 重新賦值為2
id = 2;
// 打印該變量的值,觀察是否為2
System.out.println(id);
}
}
變量命名規(guī)則
變量命名也是一門(mén)學(xué)問(wèn),并不是我們想怎么命名就怎么命名,日常開(kāi)發(fā)中最常見(jiàn)的變量命名規(guī)則主要有如下幾條:
強(qiáng)制:變量命名只能使用 字母(大小寫(xiě)均可)、數(shù)字、$、_; 強(qiáng)制:變量名不能使用關(guān)鍵字(就是 Java 中內(nèi)置的一些關(guān)鍵字,如 int、for、long…);強(qiáng)制:變量第一個(gè)字符不能使用數(shù)字,只能用字母、 $、_;更多命名規(guī)則推薦參考阿里巴巴推出的《Java 開(kāi)發(fā)手冊(cè)》,下載鏈接:https://github.com/cunyu1943/amazing-books
常見(jiàn)關(guān)鍵字
這是一種事先定義好的,有特定意義的標(biāo)識(shí)符,也叫做保留字。對(duì)于 Java 編譯器有著特殊意義,用來(lái)表示一種數(shù)據(jù)類(lèi)型,或者表示程序的結(jié)構(gòu)等。此外,關(guān)鍵字不能用作變量名、方法名、類(lèi)名、包名和參數(shù)名。常見(jiàn)的關(guān)鍵字可以分為如下幾類(lèi),具體的關(guān)鍵字如下圖所示:
訪問(wèn)控制類(lèi) 類(lèi)、方法及變量修飾符類(lèi) 程序控制類(lèi) 錯(cuò)誤處理 包相關(guān) 基本類(lèi)型 變量引用 保留字

數(shù)據(jù)類(lèi)型
基本數(shù)據(jù)類(lèi)型
Java 中,共有 8 中基本數(shù)據(jù)類(lèi)型,由 Java 語(yǔ)言預(yù)定好的,每個(gè)數(shù)據(jù)類(lèi)型都屬于關(guān)鍵字,而且每種基本變量都有其對(duì)應(yīng)的封裝類(lèi),這 8 中基本數(shù)據(jù)類(lèi)型分別是:
整型(4 種) 浮點(diǎn)型(2 種) 字符型(1 種) 布爾型(1 種)
| 數(shù)據(jù)類(lèi)型 | bit | 字節(jié) | 封裝類(lèi) | 數(shù)據(jù)范圍 | 默認(rèn)值 |
|---|---|---|---|---|---|
byte | 8 | 1 | Byte | ~ | 0 |
short | 16 | 2 | Short | ~ | 0 |
char | 16 | 2 | Character | \u0000 ~ \uffff( ~ ) | u0000 |
int | 32 | 4 | Integer | ~ | 0 |
long | 64 | 8 | Long | ~ | 0L |
float | 32 | 4 | Float | ~ | 0.0f |
double | 64 | 8 | Double | ~ | 0.0D |
boolean | 1 | 不確定 | Boolean | true 或 false | false |
注意:
boolean一般用 1bit來(lái)存儲(chǔ),但是具體大小并未規(guī)定,JVM 在編譯期將boolean類(lèi)型轉(zhuǎn)換為int,此時(shí) 1 代表true,0代表false。此外,JVM 還指出boolean數(shù)組,但底層是通過(guò)byte數(shù)組來(lái)實(shí)現(xiàn);使用 long類(lèi)型時(shí),需要在后邊加上L,否則將其作為整型解析,可能會(huì)導(dǎo)致越界;浮點(diǎn)數(shù)如果沒(méi)有明確指定 float還是double,統(tǒng)一按double處理;char是用 單引號(hào)''將內(nèi)容括起來(lái),只能存放一個(gè)字符,相當(dāng)于一個(gè)整型值(ASCII 值),能夠參加表達(dá)式運(yùn)算;而String是用 雙引號(hào)""將內(nèi)容括起來(lái),代表的是一個(gè)地址值;Java 在內(nèi)存中是采用 Unicode 表示,所以無(wú)論是一個(gè)中文字符還是英文字符,都能用 char來(lái)表示;
那么如何個(gè)一個(gè)基本類(lèi)型變量賦值呢?
在 Java 中,基本數(shù)據(jù)類(lèi)型屬于 Java 的一種內(nèi)置的特殊數(shù)據(jù)類(lèi)型,不屬于任何類(lèi),所以可以直接對(duì)其進(jìn)行賦值;給基本類(lèi)型的變量賦值的方式就叫做 字面值;
float score = 89.0f;
int age = 26;
引用數(shù)據(jù)類(lèi)型
常見(jiàn)引用數(shù)據(jù)類(lèi)型
| 數(shù)據(jù)類(lèi)型 | 默認(rèn)值 |
|---|---|
| 數(shù)組 | null |
| 類(lèi) | null |
| 接口 | null |
而對(duì)于引用數(shù)據(jù)類(lèi)型,我們經(jīng)常是需要 new 關(guān)鍵字來(lái)進(jìn)行賦值,但是引用類(lèi)型中的 接口是不能被實(shí)例化的,我們需要對(duì)其進(jìn)行實(shí)現(xiàn);
// 初始化一個(gè)對(duì)象
Pet dog = new Pet();
// 初始化一個(gè)數(shù)組
int[] arr = new int[10];
String
對(duì)于引用數(shù)據(jù)類(lèi)型中的 String,我們需要特別關(guān)注。
String 不同于 char,它屬于引用類(lèi)型,而 char 屬于基本數(shù)據(jù)類(lèi)型。用雙引號(hào) "" 括起來(lái)表示字符串,一個(gè)字符串能夠保存 0 個(gè)到任意個(gè)字符,它一旦創(chuàng)建就不能被改變。
而針對(duì)字符串,如果我們要打印一些特殊的字符,比如字符串本來(lái)就包含 ",那么這個(gè)時(shí)候就需要借助于轉(zhuǎn)義字符 \,最常見(jiàn)的轉(zhuǎn)義字符主要有:
| 轉(zhuǎn)義字符 | 含義 |
|---|---|
\" | 字符 " |
\' | 字符 ' |
\\ | 字符 \ |
\n | 換行符 |
\t | 制表符 Tab |
\r | 回車(chē)符 |
那多個(gè)字符串之間或者字符串和其他類(lèi)型數(shù)據(jù)之間,該如何進(jìn)行連接呢?
Java 編譯器中,對(duì)于字符串和其他數(shù)據(jù)類(lèi)型之間,可以使用 + 進(jìn)行連接,編譯器會(huì)自動(dòng)將其他數(shù)據(jù)類(lèi)型自動(dòng)轉(zhuǎn)換為字符串,然后再進(jìn)行連接;
String既然是不可變,那有什么優(yōu)點(diǎn)呢?
用于緩存 hash值
由于 String 的 hash 值被頻繁使用,它的不可變性使得 hash 值也不可變,此時(shí)只需要進(jìn)行一次計(jì)算;
字符串常量池(String Pool)的需要
如果一個(gè) String 對(duì)象已經(jīng)被創(chuàng)建過(guò),那么就會(huì)優(yōu)先從字符串常量池中獲取其引用,其不可變性確保了不同引用指向同一 String 對(duì)象;
安全性
我們經(jīng)常用 String 作為我們方法的參數(shù),其不變性能夠保證參數(shù)不可變;
線程安全
String 的不可變性讓它天生 具備線程安全,能夠在多個(gè)線程中方便使用而不用考慮線程安全問(wèn)題。
String、StringBuilder、StringBuffer對(duì)比,該如何選擇?
| 可變性 | 線程安全 | 適用場(chǎng)景 | |
|---|---|---|---|
String | 不可變 | 安全 | 操作少量的數(shù)據(jù) |
StringBuffer | 可變 | 安全,內(nèi)部使用 synchronized 進(jìn)行同步 | 多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) |
StringBuilder | 可變 | 不安全 | 單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù),性能高于 StringBuffer |
通過(guò)
new String(“xxx”)創(chuàng)建字符串的兩種情況?
使用 new 的方式創(chuàng)建字符串對(duì)象,會(huì)有兩種不同的情況:
String Pool 中不存在 “xxx”
此時(shí)會(huì)創(chuàng)建兩個(gè)字符串對(duì)象,“xxx” 屬于字符串字面量,因此在編譯期會(huì)在 String Pool 中創(chuàng)建一個(gè)字符串對(duì)象,用于指向該字符串的字面量 “xxx”;然后 new 會(huì)在堆中創(chuàng)建一個(gè)字符串對(duì)象;

String Pool 中存在 “xxx”
此時(shí)只需要?jiǎng)?chuàng)建一個(gè)字符串對(duì)象,由于 String Pool 中已經(jīng)存在指向 “xxx” 的對(duì)象,所以直接在堆中創(chuàng)建一個(gè)字符串對(duì)象;

數(shù)據(jù)類(lèi)型轉(zhuǎn)換
對(duì)于基本數(shù)據(jù)類(lèi)型,不同類(lèi)型之間是可以相互轉(zhuǎn)換的,但是需要滿(mǎn)足一定的條件;
從小到大自動(dòng)轉(zhuǎn),從大到小強(qiáng)制轉(zhuǎn)。
即就是,對(duì)于低精度的數(shù)據(jù)類(lèi)型,如果要轉(zhuǎn)換為高精度的數(shù)據(jù)類(lèi)型,直接將低精度的值賦給高精度的值即可;
但對(duì)于高精度的數(shù)據(jù)類(lèi)型,如果想要轉(zhuǎn)換為低精度的數(shù)據(jù)類(lèi)型,則需要采用 強(qiáng)制轉(zhuǎn)換 的手段,但此時(shí)需要承擔(dān)精度丟失的風(fēng)險(xiǎn),就像從一個(gè)大杯子往一個(gè)小杯子里倒水,你要做好小杯子可能裝不下溢出的情況;
int a = 110;
long b = 113;
// 低精度轉(zhuǎn)高精度,由于 long 的范圍比 int 大,所以可以自動(dòng)轉(zhuǎn)
b = a;
// 高精度住哪低精度,由于 long 的范圍比 int 大,所以需要強(qiáng)制轉(zhuǎn)
a = (int)b;
隱式轉(zhuǎn)換(自動(dòng)類(lèi)型轉(zhuǎn)換)
當(dāng)滿(mǎn)足如下條件時(shí),如果將一種類(lèi)型的數(shù)據(jù)賦值給另一種數(shù)據(jù)類(lèi)型變量時(shí),將執(zhí)行自動(dòng)類(lèi)型轉(zhuǎn)換:
兩種數(shù)據(jù)類(lèi)型彼此兼容; 目標(biāo)數(shù)據(jù)類(lèi)型的取值范圍大于源數(shù)據(jù)類(lèi)型;
一般而言,隱式轉(zhuǎn)換的規(guī)則是從低級(jí)類(lèi)型數(shù)據(jù)轉(zhuǎn)換為高級(jí)類(lèi)型數(shù)據(jù),對(duì)應(yīng)規(guī)則如下:
數(shù)值類(lèi)型: byte -> short -> int -> long -> float -> double字符類(lèi)型轉(zhuǎn)整型: char -> int
顯式轉(zhuǎn)換(強(qiáng)制類(lèi)型轉(zhuǎn)換)
那既然滿(mǎn)足上述兩個(gè)條件時(shí)會(huì)發(fā)生隱式轉(zhuǎn)換,那不滿(mǎn)足同時(shí)我們又想進(jìn)行數(shù)據(jù)類(lèi)型轉(zhuǎn)換時(shí),我們?cè)撛趺崔k呢?
這個(gè)時(shí)候就需要我們的 顯式轉(zhuǎn)換 登場(chǎng)了,其語(yǔ)法格式如下:
(type) variableName;
我們舉個(gè) ?? 來(lái)說(shuō)下:
int num = 3;
double ans = 5.0;
// 要將 double 類(lèi)型的值賦值給 int,則需要強(qiáng)制轉(zhuǎn)換
num = (int)ans;
注意: 強(qiáng)制轉(zhuǎn)換可能會(huì)導(dǎo)致精度丟失,所以一般情況下盡量能不用就不用。
常見(jiàn)數(shù)據(jù)類(lèi)型轉(zhuǎn)換方法
字符串與其他類(lèi)型之間的轉(zhuǎn)換
其他類(lèi)型 -> 字符串
調(diào)用類(lèi)的串轉(zhuǎn)換方法: X.toString();自動(dòng)轉(zhuǎn)換: "" + 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 類(lèi)型
// 方法 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);
字符串 - > 其他類(lèi)型
調(diào)用 parseXXX方法,比如parseLong、parseFloat、parseDouble...;先調(diào)用 valueOf(),方法,然后再調(diào)用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 之間的轉(zhuǎn)換
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;
變量作用域
我們已經(jīng)學(xué)會(huì)了如何定義變量,也知道了使用各種數(shù)據(jù)類(lèi)型來(lái)定義變量。但是還有一點(diǎn)不知道大家有沒(méi)有注意到,如果我們的定義變量在不同的位置,其作用是不是相同的呢?
這就涉及到變量的作用域,一般根據(jù)其作用域的不同,可以分為:
成員變量:定義在方法體和語(yǔ)句塊外,不屬于任何一個(gè)方法,能在整個(gè)類(lèi)中起作用; 局部變量:定義在方法或方法體中的變量,作用域是其所在的代碼塊;
成員變量
成員變量又可以分為 全局變量(又叫實(shí)例變量) 和 靜態(tài)變量(也叫類(lèi)變量),兩者的區(qū)別如下:
| 名稱(chēng) | 修飾符 | 訪問(wèn)方式 | 生命周期 |
|---|---|---|---|
| 全局變量 | 無(wú) | 對(duì)象名.變量名 | 一旦對(duì)象被引用,則實(shí)例變量就存在 |
| 靜態(tài)變量 | static | 類(lèi)名.變量名 | 同類(lèi)共生死,只有當(dāng)類(lèi)被 GC 回收時(shí)才會(huì)被銷(xiāo)毀 |
public class Person {
// 成員變量,全局變量
String name;
// 成員變量,全局變量
int age;
// 成員變量,靜態(tài)變量
public static final String wechatPublic = "公眾號(hào):村雨遙";
// 成員變量,靜態(tài)變量
public static final String website = "http://cunyu1943.site";
}
局部變量
成員變量指定義在方法或方法體中的變量,作用域是其所在的代碼塊,可以分為如下三種:
形參
public class Main {
// 方法中的參數(shù)
public static void func(int num) {
System.out.println("num = " + num);
}
public static void main(String[] args) {
func(3);
}
}
方法內(nèi)定義
public class Main {
public static void main(String[] args) {
int num = 10;
if (num > 5) {
// 聲明一個(gè) int 類(lèi)型的局部變量
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) { // 異常處理塊,參數(shù)為 Exception 類(lèi)型
e.printStackTrace();
}
}
public static void main(String[] args) {
func();
}
}
常量
簡(jiǎn)介
既然有變量,那就有與之相對(duì)的常量(也就是值是固定的,不能再變)。
常量又叫做字面常量,是通過(guò)數(shù)據(jù)直接來(lái)表示的,在程序運(yùn)行過(guò)程中不能發(fā)生改變。通常我們把 Java 中用 final 關(guān)鍵字所修飾的成員變量叫做常量,它的值一旦給定就無(wú)法再進(jìn)行改變!
分類(lèi)
Java 中使用 final 關(guān)鍵字來(lái)聲明常量,其語(yǔ)法格式如下:
final 數(shù)據(jù)類(lèi)型 常量名 = 常量初始值;
public class Main{
public static void main(String[] args){
// 聲明一個(gè)常量并賦值
final int num = 1024;
// 再次賦值,將導(dǎo)致編譯錯(cuò)誤
num = 1943;
// 聲明一個(gè)常量但不賦值
final int id;
// 因?yàn)槁暶鲿r(shí)未賦值,所以可以進(jìn)程初次賦值
id = 1;
// 常量已經(jīng)賦值過(guò)了,再次賦值將導(dǎo)致編譯錯(cuò)誤
id = 2;
}
}
常量可以分為如下 3 種類(lèi)型:
靜態(tài)常量: final之前用public staic修飾,表示該常量的作用域是全局的,我們不用創(chuàng)建對(duì)象就能夠訪問(wèn)它。成員常量:類(lèi)似于成員變量,但是最大的不同在于它不能被修改。 局部常量:作用類(lèi)似于局部變量,不同之處也在于不能修改。
public class Main{
// 靜態(tài)變量
public static final dobule PI = 3.14;
// 成員常量
final int num = 1024;
public static void main(String[] args){
// 局部變量
final long count = 1000;
}
}
PS:final 修飾變量后,該變量則變?yōu)槌A?。?final 也還可以用來(lái)修飾類(lèi)和方法,修飾方法時(shí),表示這個(gè)方法不能被重寫(xiě)(但可以重載);修飾類(lèi)時(shí),則表明該類(lèi)無(wú)法被繼承。這些東西這時(shí)候你可能會(huì)覺(jué)得很陌生,不過(guò)等我們后續(xù)學(xué)習(xí)了面向?qū)ο笾?,你就?huì)發(fā)現(xiàn)其實(shí)很簡(jiǎn)單。
總結(jié)
碼字不易,如果覺(jué)得對(duì)您有所幫助,可以點(diǎn)贊關(guān)注一波哦!??
博主水平有限,對(duì)于文中可能出現(xiàn)的錯(cuò)誤,還請(qǐng)各位批評(píng)指正,來(lái)評(píng)論區(qū)一起聊天吧!



