目錄
1.概念
1.1.java的特定有哪些?
1.2.java有哪些優勢哪些劣勢?
1.3.java為什么可以跨平臺?
1.4JVM,JDK,JRE它們有什么區別?
1.5.編譯型語言與解釋型語言的區別?
2.數據類型
2.1.long與int類型可以互轉嗎?
2.2.數據類型轉變形式有哪些?
2.3.類型轉換會出現哪些問題?
2.4.為什么用bigDecimal 不用double?
2.5.裝箱與拆箱會出現什么問題?
2.6.Integer為什么會存在一個緩存池?
3.面向對象
3.1.怎么理解面向對象?
3.2.說一下封裝繼承多態?
3.3.多態體現在哪幾個方面?
3.4.重寫與重載的區別?
3.5.抽象類與普通類的區別?
3.6.抽象類與接口的區別?
3.7.抽象類可以加final關鍵字嗎?
3.8.解釋一下靜態變量與靜態方法?
3.9.為什么靜態不能調用非靜態?
3.10.為什么非靜態內部類可以訪問外部類?
4.關鍵字
4.1.final
1.概念
1.1.java的特定有哪些?
- 平臺無關性:"一次編譯終身運行",就是說java編譯器會將源代碼先編譯成字節碼(不同機器上只要源代碼相同,那么就字節碼一定相同),然后JVM會將字節碼翻譯成對應的機器碼(JVM有不同系統的版本,JVM會根據你的環境進行翻譯),總的來說就是字節碼保證編譯一致,然后根據不同的JVM翻譯對應機器碼
- 面向對象:java是一個面向對象的語言,更方便代碼的維護和使用
- 內存管理:java擁有垃圾回收機制,開發人員不需要自己手動刪除內存(不需要考慮這么多),由垃圾回收機制來自動實現內存釋放
1.2.java有哪些優勢哪些劣勢?
優勢:(特定那里)
- 跨平臺:java有平臺無關性
- 內存管理:擁有垃圾回收機制
- 面向對象:使代碼更好維護和使用
- 強大的生態系統:如Spring全家桶,其他的工具包等等
- 穩定性:支持企業長期使用,版本向后兼容
劣勢:
- 內存消耗大:JVM虛擬機本身就需要一定的內存
- 啟動時間長:由于需要JVM將字節碼翻譯成機器碼
- 代碼復雜:由于java過于面向對象,一個簡單的程序的代碼復雜(麻煩)
1.3.java為什么可以跨平臺?
java在編譯時,java編譯器會直接將源代碼編寫成字節碼文件,等到你需要運行時,會根據你的JVM虛擬機版本不同,然后通過不同的JVM將字節碼翻譯成機器碼(讓機器識別)
1.4JVM,JDK,JRE它們有什么區別?
JVM:JVM是java虛擬機,是java程序運行的環境
JDK:JDK是java的一個開發工具包(各種類,工具)
JRE:JRE是java運行的環境,是java程序所需的最小環境
1.5.編譯型語言與解釋型語言的區別?
編譯型:在運行之前需要編譯,將源代碼編寫成字節碼或者機器碼(C++),如果它編寫成機器碼,在本機上可以直接識別機器碼,從而它的運行速度快,跨平臺性差
解釋性:不需要編譯,它會在運行時逐行解釋代碼,因運行速度慢,跨平臺性好
2.數據類型
2.1.long與int類型可以互轉嗎?
可以:但是你需要考慮數據的溢出與丟失
比如:你將long類型轉成int類型,如果你的long類型的數很大,大到int無法全部接收,那么就會出現數據的丟失
比如:你將int類型轉成long類型,如果你的int類型的數很小,那么用long接收,由于long精度大,其他位將用0填充,出現數據溢出
public class TypeConversion {public static void main(String[] args) {long bigLong = 2147483648L; // 超出 int 最大值(2147483647)int intValue = (int) bigLong; // 強制轉換System.out.println("原始 long 值: " + bigLong); // 輸出 2147483648System.out.println("轉換后的 int 值: " + intValue); // 輸出 -2147483648(溢出)}
}
2.2.數據類型轉變形式有哪些?
自動類型轉換(隱式轉換):假如:你使用long類型與int類型進行相加,它會默認將int類型隱式轉換成long,再進行運算
public class AutoConversion {public static void main(String[] args) {int a = 10;long b = 20L;long result = a + b; // int 自動提升為 longSystem.out.println(result); // 輸出 30}
}
強制類型轉換(顯示轉換):假如:你使用long類型與int類型進行相加,那么最后的結果只能用long類型接收,如果你想要使用int類型接收,那么需要強制類型轉換
public class ForceConversion {public static void main(String[] args) {long a = 2147483648L; // 超過 int 最大值(2147483647)int b = (int) a; // 強制轉換System.out.println(b); // 輸出 -2147483648(高位截斷)}
}
字符串轉換:使用包裝類里面的方法進行轉換,比如:你將char類型轉換成int,那么它會根據ASCII碼對應表轉成對應數
public class StringConversion {public static void main(String[] args) {// 1. 字符串 → 數值類型(需處理異常)String str = "123";int num = Integer.parseInt(str); // 字符串轉 intdouble d = Double.parseDouble(str); // 字符串轉 double// 2. 數值類型 → 字符串String s1 = Integer.toString(num); // 方法1String s2 = String.valueOf(d); // 方法2String s3 = "" + num; // 方法3(隱式轉換)// 3. char → int(ASCII 碼轉換)char c = 'A';int ascii = c; // 直接賦值,輸出 65int numericValue = Character.getNumericValue('9'); // 輸出 9}
}
2.3.類型轉換會出現哪些問題?
數據丟失:小類型轉大類型(精度不同,造成數據丟失)
數據溢出:大類型轉小類型(高位全用0填充)
精度不同:float是單精度,double是雙精度,兩者轉換精度會出現丟失
類型不同:不同類型的轉換會出現編譯錯誤
2.4.為什么用bigDecimal 不用double?
舉例:你能使用十進制表示1/3嗎?無法表示,一直在循環,而double是進行二進制運算的,比如:0.1你能使用二進制進行表示嗎?也是一直循環,而double是有精度的,到達它的精度限度后,它不會在循環下去,因此會出現精度丟失問題
解決:使用bigDecimal(注意:如果你還是使用浮點數賦值給它,還是會出現該問題(默認浮點數就是double類型),因此使用字符串賦值)
System.out.println(0.1 + 0.2); // 輸出 0.30000000000000004(精度丟失)
import java.math.BigDecimal;public class BadExample {public static void main(String[] args) {BigDecimal a = new BigDecimal(0.1); // 用 double 初始化(錯誤!)BigDecimal b = new BigDecimal(0.2);BigDecimal result = a.add(b);System.out.println(result); // 輸出 0.3000000000000000166533453694...}
}
import java.math.BigDecimal;public class GoodExample {public static void main(String[] args) {BigDecimal a = new BigDecimal("0.1"); // 用字符串初始化(正確!)BigDecimal b = new BigDecimal("0.2");BigDecimal result = a.add(b);System.out.println(result); // 輸出 0.3}
}
2.5.裝箱與拆箱會出現什么問題?
裝箱:就是將基本類型包裝成包裝類
拆箱:就是將包裝類拆成基本類型
問題:由于java可以實現自動裝箱與拆箱,如果你定義一個Integer類型,但是沒有給它賦值,它會默認null,然后將它拆箱,但是null值是無法拆箱的,因此會出現空指針異常
2.6.Integer為什么會存在一個緩存池?
由于我們需要使用對應的包裝類,但是每次都需要重新創建對象(消耗內存),并且進行一個運算就會創建一個對象(無關內存),因此為了節省內存,java將我們常使用的-128到127的對象已經創建好了,放在靜態緩存池中,你使用.valueInt()這個方法進行賦值,它就會去復用池中對象(地址相同)
Integer a = Integer.valueOf(100); // 從緩存池獲取(地址相同)
Integer b = 100; // 隱式調用 valueOf(),復用緩存
Integer c = new Integer(100); // 強制創建新對象(地址不同)System.out.println(a == b); // true(同一對象)
System.out.println(a == c); // false(不同對象)
3.面向對象
3.1.怎么理解面向對象?
面向對象就是將現實生活中的各個事務抽象成對象
3.2.說一下封裝繼承多態?
封裝:就是將共性的屬性與方法封裝到類中,隱藏類中的細節,僅暴露出你想要暴露的接口來與外界交互,增加了代碼的安全性和擴展性
繼承:子類共享父類的屬性與方法,是代碼實現復用,建立了類與類之間的聯系,是類之間的結構更加清晰
多態:不同類對應不同消息的不同操作方式,是代碼更加靈活
3.3.多態體現在哪幾個方面?
方法重載:同一個類可以有多個方法名相同的方法(參數不同)
方法重寫:子類重寫父類的方法
接口實現:不同的類實現同一個接口,那么創建對象時,可以使用接口創建,調用方式一致
向上與向下轉型:向上:父類轉子類? ?向下:子類轉父類
3.4.重寫與重載的區別?
重寫:子類重寫父類方法,需要與父類方法名,返回類型,參數保持一致,只能修改其內部的代碼
重載:在同一個類中你可以重載多個方法名相同的方法,但是區別在于參數不同(1.參數類型不同,2.參數數量不同,3.參數順序不同),滿足一個即可
3.5.抽象類與普通類的區別?
實例化:抽象類不可以實例化,普通類可以
-----
方法實現:抽象類方法可以實現可以只定義,而普通類需要具體的方法實現
3.6.抽象類與接口的區別?
實現方式:抽象類需要繼承extends,接口需要實現implements
-----
訪問修飾符不同:兩者的屬性與方法默認修飾符不同
-----
方法實現不同:抽象類方法可以定義可以實現,接口只能定義
-----
變量:抽象類可以有實例變量和靜態變量,而接口只有靜態變量
-----
特點:接口是定義類的功能或行為,抽象類是描述類的共性和行為的
3.7.抽象類可以加final關鍵字嗎?
不可以,抽象類本身就是一個基類就是讓其他類繼承的,而類加上final會讓該類無法被繼承
因此兩者互斥
3.8.解釋一下靜態變量與靜態方法?
靜態的東西只有當類加載完后,它就會加載,只會在內存中加載一次
3.9.為什么靜態不能調用非靜態?
靜態只有當類加載完就會加載,因此靜態會優先于非靜態加載(需要實例化),你一個沒加載的怎么能被調用呢?
比如:靜態方法里面調用非靜態方法,我靜態方法都已經加載完了,而你非靜態方法必須要實例化才能加載,沒有實例化不加載,那么我怎么調用你呢?(不能確定非靜態是否加載)
比如:反過來,就可以解釋為什么非靜態可以調用靜態,因為非靜態加載慢,它加載完就一定有靜態加載完,因此可以調用
public class Example {static int staticVar = 10; // 類加載時初始化int instanceVar = 20; // 對象實例化時初始化
}
public class Example {static void staticMethod() {instanceMethod(); // 編譯錯誤:無法調用非靜態方法System.out.println(instanceVar); // 編譯錯誤:無法訪問非靜態變量}void instanceMethod() {System.out.println("非靜態方法");}
}
public class Example {static int staticVar = 10;void instanceMethod() {System.out.println(staticVar); // 合法:靜態成員已加載staticMethod(); // 合法:靜態方法已加載}static void staticMethod() {System.out.println("靜態方法");}
}
3.10.為什么非靜態內部類可以訪問外部類?
就是當外部類實例化后,會將外部類的實例化地址(引用)當作參數傳給非靜態內部類,因此它可以根據引用來訪問
4.關鍵字
4.1.final
修飾類 | 代表類不能被繼承 |
修飾方法 | 代表方法不能被重寫 |
修飾變量 | 如果是基本類型,值不能被修改,是引用類型,值可以被修改,地址不能修改 |