最近閑暇時間看到網上的一些面試題,抽空整理了一下,寫了一些自己的見解。其中有錯漏之處,還望指正。
1 java語言特點
簡單性:Java沒有像C++那樣的指針,運算符重載,類的多繼承。並且實現了垃圾的自動回收,簡化了程序開發者對於內存管理的工作
面向對象:對象是指封裝數據和操作方法的程序實體。Java提供了簡單的類機制以及動態接口。表現形式是封裝 繼承 多態
跨平台: Java語言開發的軟件在Windows/ mac/ Linux 系統下都能運行, 只需要在操作系統上安裝虛擬機 (Java Virtual Machine --- JVM )即可
移植性: 如果Java直接編譯成系統能識的二進制碼,可能一個標識在windows下是1100,而Linux 下是1001,這樣java在windows下編譯后無法在Linux 運行。所以java先編譯成字節碼(中間碼),由JVM(java虛擬機來解釋執行),而這個JVM對於主流的操作系統都有相應的版本,目的就是將統一的中間碼編譯成對應操作系統識的二進制碼,然后執行。所以不論你在什么系統中編譯的java,得到的都是統一的字節碼(中間碼)
2 Java的基本數據類型有哪些, 各占幾個字節
整數型 byte short int long 浮點型 float double 字符型 char 布爾型 boolean
基本數據類型 | byte | short | int | long | float | double | boolean | cahr |
---|---|---|---|---|---|---|---|---|
占用字節數 | 1 | 2 | 4 | 8 | 4 | 8 | 占一位,而不是字節 | 2 |
擴展:
引用數據類型:
字符串、數組、類、接口、Lambda等 注意事項:
-
字符串不是基本類型,而是引用類型。
-
浮點型可能只是一個近似值,並非精確的值(所以不要用來比較)。
-
數據范圍與字節數不一定相關,例如float數據范圍比long更加廣泛(long只能表示整數,而float表示的是小數),但是float是4字節,long是8字節。
-
浮點數當中默認類型是double。如果一定要使用float類型,需要加上一個后綴F。 如果是整數,默認為int類型,如果一定要使用long類型,需要加上一個后綴L。推薦使用大寫字母后綴。
3 long(8)與float(4)的取值范圍誰大誰小?
float的取值范圍更大。雖然 long 是 8個字節, float 是 4個字節, 但是 float 的取值范圍比 long 的取值范圍大,因為 float 的算法與 long 的不一樣。long只能表示整數,而float表示的是小數。舉個例子:1到10之間的整數只有那么幾個,那么1到10之間的小數有多少個呢?
4 Java語言中的字符 char可以存儲一個中文漢字嗎? 為什么呢?
可以,因為java默認使用Unicode編碼,而在Unicode編碼中一個中文漢字占兩位,所以char可以存儲一個中文漢字。
5 看下面的程序是否有問題,如果有問題,請指出並說明理由。
short s=1; s = s+1; // 報錯
short s=1; s += 1; // 編譯通過
這里涉及到+=與 + 的區別。
第一行報錯:報錯是因為第一行先進行了s+1的操作,然后賦值給s。等號右邊short 類型數據 跟 默認的 int 類型的數據相加時, 會自動轉化成 int 類型數據,而s是short類型的,造成了數據類型不匹配,所以編譯會報錯。
第二行可以編譯通過:因為+=實際上對后面的值進行了強制類型轉換,這里相當於s=(short)s+1;
擴展一下吧:
再舉一個上面提到的例子分析一下:
public static void main(String[] args){
byte s = 1;
s+=1;
System.out.println(s);
}
分析: s += 1 邏輯上看作是 s = s + 1 計算結果被提升為int類型,再向byte類型賦值時發生錯誤,因為不能將取值范圍大的類型賦值到取值范圍小的類型。但是, s=s+1進行了兩次運算 ,而 += 是一個運算符,只運算一次,並帶有強制轉換的特點, 也就是說 s += 1 就是 s = (byte)(s + 1) ,因此程序沒有問題編譯通過,運行結果是2.接着看一下下面這個程序:
public static void main(String[] args){
byte b1=1;
byte b2=2;
byte b3=1 + 2;
byte b4=b1+b2;
System.out.println(b3);
System.out.println(b4);
}
分析: b3 = 1 + 2 , 1 和 2 是常量,為固定不變的數據,在編譯的時候(編譯器javac),已經確定了 1+2 的結果並沒有超過byte類型的取值范圍,可以賦值給變量 b3 ,因此 b3=1 + 2 是正確的。
反之, b4 = b2 + b3 , b2 和 b3 是變量,變量的值是可能變化的,在編譯的時候,編譯器javac不確定b2+b3的結果是什么,因此會將結果以int類型進行處理,所以int類型不能賦值給byte類型,因此編譯失敗。
6 請自己實現兩個整數變量的交換(不需要定義第三方變量)
先擴展一下:
實現兩個變量交換的方式:
方式一:定義一個臨時變量。簡單舉例:
int a=3;
int b=5;
int temp;
temp=a; //temp=3
a=b; //a=5
b=temp; //b=3
方式二:兩加一減(不需要定義臨時變量)
int a=3;
int b=5;
a=a+b; //a=8
b=a-b; //b=3
a=a-b; //a=5
方式三:位運算。也是最有效率的一種方式,同樣不需要定義臨時變量。
位異或運算符的特點:
^的特點:一個數據對另一個數據位異或兩次,該數本身不變。
int a = 1;
int b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
關於^的知識點:
^是異或運算符(把數據轉換成二進制,然后按位進行運算)。
運算規則:0^0 = 0, 1^0 = 1, 0^1 = 1, 1^1 = 0,簡單理解:相同則為0,不同則為1.
如:3^5 的運算過程為:
(1)先將3和5轉換成二進制的11和101
(2)再按對應的位分別進行運算,11位數不足補零
011
^ 101
-----------
110
(3)運算結果轉換成10進制:6
異或運算的三個特點:
(1) 0^0=0, 0^1=1 0與任何數異或=任何數
(2) 1^0=1, 1^1=0 1與任何數異或 =任何數取反
(3) 任何數異或自己=把自己置0
異或運算的常見用途:
(1) 使某些特定的位翻轉
例如對數10100001的第2位和第3位翻轉,其他位不變,則可以將該數與00000110進行按位異或運算。
10100001^00000110 = 10100111
(2) 實現兩個值的交換,而不必使用臨時變量。
例如交換兩個整數a=10100001,b=00000110的值,可通過下列語句實現:
a = a^b; //a=10100111
b = a^b; //b=10100001
a = a^b; //a=00000110
(3) 在匯編語言中經常用於將變量置零:
xor a,a
(4) 快速判斷兩個值是否相等
判斷兩個整數a,b是否相等,則可通過下列語句實現:
return ((a ^ b) == 0)
參考鏈接:https://blog.csdn.net/gtkknd/article/details/52798337
7 最有效率的算出2 * 8
的結果
2*8相當於2乘以2的3次方,所以這里只需要將2向左位移三位即可。即:2<<3 (向左位移為乘,向右為除)
8 關於 switch的表達式下面正確的是
1. byte 可以作為 switch 的表達式嗎? 可以
2. long 可以作為 switch 的表達式嗎? 可以
3. String 可以作為 switch 的表達式嗎? 也可以,但是必須jdk1.7以后才支持
注意:
-
switch語句中,表達式的數據類型,可以是byte,short,int,char,enum(枚舉),JDK7后可以接收字符串。但是不支持浮點類型。
-
在switch語句中,如果case的后面不寫break,將出現case穿透現象,也就是不會再判斷下一個case的值,直接向后運行,直到遇到break,或者整體switch結束
case穿透的測試:不判斷條件,向下執行,直到遇到break為止。
//先看看正常情況
輸出結果為:今天是周四
//將case 4中的break注釋掉
輸出結果為:
今天是周四
今天是周五
可以看到,明明day=4和5是不匹配的,但是case 5中的語句仍舊打印了,因為根本就沒有對case 5進行判斷,這就是case穿透現象。而case 5中遇到了break,所以case穿透現象也就在case 5中結束了。
9 return和 break以及 continue的區別?
return:如果后面接了東西,代表返回這個東西。如果僅僅是個return的話,代表結束當前方法 。 break:是跳出當前循環,然后執行循環外面的內容 continue:是終止本次循環,繼續下次循環 break 和 continue 只能用在循環結構語句中。return,不僅可以用在循環結構中,也可以用在循環結構外
10 運算符 a++ 與 ++a 的區別
就單獨運用的話,其實這兩個並沒有區別。但是參與到混合運算,則兩者有所不同。 舉例:b=a++和b=++a 假如原本a=5。 b=a++是先賦值,再+1.結果是b=5,而a=6. b=++a則是先自加一在賦值,也就是a和b都等於6.
擴充:a++或者a--
a=a++; 事實上,底層是這樣:定義一個臨時變量=a原來的值;a=a+1;b=臨時變量;
public void test06() {
int a=3;
a=a++;
System.out.println(a);//輸出3
}
11 Java 中到底是傳值還是傳地址?
事實上,java中傳遞的都是值,因為地址也是值。所以不管是傳遞基本數據類型還是引用數據類型,都是在傳值。
12 指出下面變量的區別
int[] x;
int[] y[];
int[] x,y[]; // x是一維數組,y是二維數組
解釋一下:
int[] a; // 一維數組a
int[][] b; // 二維數組b
int c[]; //一維數組,相當於int[] c
int[] d[]; //二維數組,相當於int[][] d
int[] e, f[]; //相當於int[]e和int[]f[];所以e是一維數組,f是二維數組
//一維數組:1)int[] x;2)int x[];
//二維數組:1)int[][] y;2)int y[][];3)int[]y[]
13 面向對象特征
封裝、繼承、多態 。如果非要再來一個的話,那就是抽象,不過我們一般比較認同的是前面三個。
-
封裝: 把對象的屬性和操作(或服務)結合為一個獨立的整體,並盡可能隱藏對象的內部實現細節。對外提供公有的方法以供操作。讓調用者不需要知道怎么做,只需要知道做什么即可。
-
繼承: 可以使得層次結構更清晰,實現了代碼的可重復使用
-
多態 降低耦合,增強可替換性,提高了程序的可擴展性。
14 繼承相關面試題一
//下面程序的輸出結果是?
class Fu {
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu {
public int num = 20;
public Zi(){
System.out.println("zi");
}
public void show(){
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}
public class Test1 {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
打印:
fu
zi
30
20
10
15 繼承相關的面試題二
public class Test {
public static void main(String[] args) {
Zi z =new Zi();
}
}
class Fu {
static {
System.out.println("靜態代碼塊Fu");
}
{
System.out.println("構造代碼塊Fu");
}
public Fu() {
System.out.println("構造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("靜態代碼塊Zi");
}
{
System.out.println("構造代碼塊Zi");
}
public Zi() { // 內部系統默認有 super();
System.out.println("構造方法Zi");
}
}
打印:
靜態代碼塊Fu
靜態代碼塊Zi
構造代碼塊Fu
構造方法Fu
構造代碼塊Zi
構造方法Zi
16 繼承面試題三
class Person {
static {
System.out.println("Person 靜態代碼塊"); //3
}
{
System.out.println("Person 構造代碼塊");//4 //6
}
public Person() {
System.out.println("Person 構造方法"); //5 //7
}
}
public class Demo{
static {
System.out.println("Demo靜態代碼塊"); //1
}
public static void main(String[] args) {
System.out.println("我是main方法"); //2
Person p1 = new Person();
Person p2 = new Person();
}
}
小結:
1.首先,初始化父類中的靜態成員變量和靜態代碼塊,按照在程序中出現的順序初始化;
2.然后,初始化子類中的靜態成員變量和靜態代碼塊,按照在程序中出現的順序初始化;
3.其次,初始化父類的普通成員變量和代碼塊,再執行父類的構造方法;
4.最后,初始化子類的普通成員變量和代碼塊,再執行子類的構造方法;
靜態代碼塊在類第一次加載進內存的時候就會執行, 且只執行一次 構造代碼塊在構造方法真正要執行之前就會執行, 每次調用構造方法都會執行一次
靜態代碼塊 執行:隨着類的加載而執行且執行一次,優先於main方法和構造方法的執行。 作用:給類變量進行初始化賦值
17方法重寫重載的面試題
-
Overload 重載能改變返回值類型嗎? 可以,方法重載只看參數列表的不同。
-
Override 重寫和 Overload 重載的區別?
重寫: (一) 父類方法的參數列表必須完全與被子類重寫的方法的參數列表相同 (二) 父類的返回類型必須與被子類重寫的方法返回類型相同 (三) Java中規定,被子類重寫的方法不能擁有比父類方法更加嚴格的訪問權限。編寫過Java程序的人就知道,
父類中的方法並不是在任何情況下都可以重寫的,當父類中方法的訪問權限修飾符為private時,該方法只能被自己的類訪問,不能被外部的類訪問,在子類是不能被重寫的。如果定義父類的方法為public,在子類定義為private,程序運行時就會報錯。
(四) 由於父類的訪問權限修飾符的限制一定要大於被子類重寫方法的訪問權限修飾符,而private權限最小。
所以如果某一個方法在父類中的訪問權限是private,那么就不能在子類中對其進行重寫。如果重新定義,也只是定義了一個新的方法,不會達到重寫的效果。 (五) 在繼承過程中如果父類當中的方法拋出異常,那么在子類中重寫父類的該方法時,也要拋出異常,而且拋出的異常不能多於父類中拋出的異常(可以等於父類中拋出的異常)。換句話說,重寫方法一定不能拋出新的檢查異常,或者比被重寫方法聲明更加寬泛的檢查型異常。例如,父類的一個方法申明了一個檢查異常IOException,在重寫這個方法時就不能拋出Exception,只能拋出IOException的子類異常,可以拋出非檢查異常。同樣的道理,如果子類中創建了一個成員變量,而該變量和父類中的一個變量名稱相同,稱作變量重寫或屬性覆蓋。但是此概念一般很少有人去研究它,因為意義不大。
重載:我們將名字相同,參數列表不同的兩個(或多個)方法稱為重載方法。 參數列表的不同體現在以下兩點: 1 參數的類型不同 2 參數的個數不同
18 一個抽象類如果沒有抽象方法,可不可以定義為抽象類?如果可以,有什么意義
可以。這么做的目的只有一個,就是不讓其它類創建本類對象,交給子類完成。
抽象類: 抽象類中不一定包含抽象方法,但是有抽象方法的類一定是抽象類。 抽象類的子類必須全部重寫抽象父類的抽象方法,除非該子類也是抽象類。。
19 abstract不能與哪些關鍵字共存
1)static
abstract修飾的是對象級別,static修飾的是類級別的,對象方法和類方法是沖突的。
2)final
final修飾的是常量級別的,不可被修改。abstract的目的就是為了讓子類實現,顯然final的存在會使得abstract變得沒有意義。
3)private
private修飾的類或者方法只有自己能使用,子類無法訪問,顯然和abstract是矛盾的。
關於final 與 static的修飾總結
final 關鍵字的修飾特點:
-
修飾類,類不能被繼承,相當於做了丁克
-
修飾方法,那么這個方法不能被重寫
-
修飾變量,變量就變成了常量,只能被賦值一次
* final 修飾變量叫做常量,一般會與 public , static 共用
* 常量命名規范,如果是一個單詞,所有字母大寫,
如果是多個單詞,每個單詞都大寫,中間用下划線隔開,
如 public static final MAX_AGE = 125;
* 如果修飾的變量是基本類型,是值不能被改變
* 在定義變量時, 就馬上初始化【這種初始化方法比較常用】
在構造方法中, 進行初始化 [不常用]
* 修飾引用類型的變量,是地址值不能被改變,
即對象本身不可變, 但對象中的屬性可以改變
修飾引用類型不可以賦值, 同類型的引用對象
final Person p = new Person("hxl", 18);
p.name = "xhl";
p.age = 16;
Person p2 = new Person();
p = p2; // 報錯
p = new Person(); // 報錯
static 關鍵字的特點:
-
隨着類的加載而加載
-
優先於對象存在
-
被類的所有對象共享
-
如果某個成員變量是被所有對象共享的,那么它就應該定義為靜態的。
-
1. static 聲明的成員屬性可以通過類名調用
靜態變量屬於類,所以也稱為為類變量
成員變量屬於對象,所以也稱為實例變量(對象變量)
推薦使用類名調用【強調】。
其實它本身也可以通過對象名調用。[不推薦, 會有警告]
靜態修飾的內容一般我們稱其為:與類相關的類成員
2. static 也可以用來修飾方法
靜態方法只能訪問靜態的成員變量和靜態的成員方法【掌握】
非靜態方法可以訪問靜態的成員變量和靜態的成員方法【掌握】
3. 在靜態方法中是沒有 this 關鍵字的, 如何理解呢?【掌握】
靜態是隨着類的加載而加載, this 是隨着對象的創建而存在。
靜態比對象先存在。
4. 如果一個類中所有的方法都是靜態的
我們可以再多做一步, 私有構造方法, 不讓其他類創建本類對象
確保用類名調用方法
public class Demo01 {
public static void main(String[] args) {
// Student stu = new Student();
Student.test01();
Student.say01();
Student.speak01();
}
}
class Student {
String name;
int age;
private Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
private Student() {
super();
// TODO Auto-generated constructor stub
}
static void test01() {
System.out.println("test01");
}
static void say01() {
System.out.println("say01");
}
public final static void speak01() {
System.out.println("speak01");
}
}
20 package,import,class有沒有順序關系?
-
ackage 只能有一個,必須放在java文件的第一行,
-
rt 只能放在 package 的下面,多個 import 應放在一起,
-
class 放在 package 或者import的下面
21 成員內部類
//要求:使用已知的變量,在控制台輸出30,20,10。
public class InnerClassTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(Outer.this.num);
}
}
}
22 int i=1234;System.out.println(i/1000*1000);輸出的內容是?
輸出的內容是1000。因為i/1000不會保留小數部分,所以等於1.在*1000等於1000。
知識點:ava中,整數使用+、-、*、/、%、++、--這些運算符,無論怎么計算,也不會得到小數
23 指出並解釋下面哪里會編譯錯誤
byte b1=1;
byte b2=2; //byte、short、char類型的變量在進行運算時,會自動轉換為int類型。
byte b3=1+2; //這里不會報錯,因為1+2在編譯時會直接編譯成3
byte b4=b1+b2; //報錯,因為不知道b1+b2的值會不會超出byte的取值范圍
System.out.println(b3);
System.out.println(b4);
public void test01() {
byte a=2;
//a=2*a; 編譯錯誤
a*=2;
}
//byte、short、char類型的變量在進行運算時,會自動轉換為int類型。
//a=2a;(這里是錯誤的,因為a是byte類型,而a*2是int類型)
//a+=2或a*=2等都是可以的,這源於運算符的特殊性。
24 談一談for循環和while循環的區別
控制條件語句所控制的那個變量,在for循環結束后,就不能再被訪問到了,而while循環結束還可以繼續使用,如果你想繼續使用,就用while,否則推薦使用for。原因是for循環結束,該變量就從內存中消 失,能夠提高內存的使用效率。 在已知循環次數的時候使用推薦使用for,循環次數未知的時推薦使用while。
25 java面向對象的六大原則(模式設計的六大原則)
-
單一職責
-
開放封閉
-
里氏替換
-
依賴倒置
-
接口隔離
-
迪米特法則(最少知道原則)
26 java有什么核心優勢讓其流行?
跨平台是JAVA語言的核心優勢,在各個平台上都可以使用JAVA語言。JAVA還具有以下優勢:
安全性,面向對象,簡單性,高性能,分布式,多線程,健壯性。
27java是解釋型語言還是編譯型語言?
既可以說是編譯型的(因為所有的Java代碼都是要編譯的,.java不經過編譯就什么用都沒有 ),也可以說是解釋型的(因為java代碼編譯后不能直接運行,它是解釋運行在JVM上的,所以它是解釋運行的,那也就算是解釋的了),或者說是二者結合的。事實上,現在僅用編譯型和解釋型來區分編程語言已經有些力不從心了。
28標識符能不能以漢字開頭?為什么?
可以,java規定了標識符要以數字、字母、美元符號和下划線組成並且不能以數字開頭。而java默認采用的是unicode編碼,在Unicode編碼中一個漢字相當於一個字母,所以可以使用漢字開頭。但是日常的開發中不建議使用漢字。並且參照阿里巴巴的編程規范的話,是不能以下划線和美元符號開頭或者結尾,不能中英文混用(包括拼音),更不能使用漢字。
29java中有沒有goto語句?有沒有goto關鍵字?
java中沒有goto語句。但是java中goto仍被作為保留字,所以有關鍵字。
30如何用科學計數法表示3.14
314E-2
十進制數表示形式: 3.14 0.314 3140.0
科學計數法表示: 314e-2 314E-3 314E1 e或者E表示10,后面代表次方
31java語言中整型常量的四種表現形式:
二進制:要求以0B或者0b開始,如:0B10110
八進制:要求以0開頭,如015
十進制:不解釋了
十六進制:要求以0X或者0x開頭,如0x15
32浮點數能用於比較嗎?
不能,浮點數是不精確的。如果需要比較,那么使用任意精度整數運算( BigInteger
)和任意精度十進制運算( BigDecimal
)
float a=123213123f;
float b=a+1;
System.out.println(a==b); //輸出結果是true。
33java中垃圾回收的算法:
引用計數法、引用可達法(根搜索算法)
34布爾類型占用一位還是一個字節?
一位。
35 這種寫法好不好?if(a==true)
不好,應改為if(a)
36java中使用哪個關鍵字來定義常量
final。一般和static配合使用。
37使用Scanner接收鍵盤輸入,是否一定要加import Java.util.*;
不用,也可以寫為import java.util.Scanner;或者使用Scanner的全類名.
38引用類型占用幾個字節?
這個問題我真不清楚,放兩個鏈接,大家參考一下
https://blog.csdn.net/uudou/article/details/47662237
https://oomake.com/question/1322554
39算術運算符中類型提升是怎么回事?int a=3,long b=3;a+b返回什么類型?
返回的是long類型。
知識點:
數據類型轉換
自動轉換:
• 將取值范圍小的類型 自動提升為 取值范圍大的類型
轉換規則
• 范圍小的類型向范圍大的類型提升, byte、short、char 運算時直接提升為 int 。
byte、short、char‐‐>int‐‐>long‐‐>float‐‐>double
強制轉換:
1. 將取值范圍大的類型 強制轉換成 取值范圍小的類型 。
2. 比較而言,自動轉換是Java自動執行的,而強制轉換需要我們自己手動執行。
強烈注意
- 浮點轉成整數,直接取消小數點,可能造成數據損失精度。
- int 強制轉成 short 砍掉2個字節,可能造成數據丟失。
40 關系運算符中能不能這么寫:1<a<3
不能。
41 這兩個表達式分別返回什么結果?
((1<3)?"a":"b")+3+4; //應該返回a34
x=-2;x>0?1:(x==0?0:-1); //應該返回-1
42 什么情況下,加號會變成字符串連接符?
當字符串與字符串類型或者其他數據類型進行加法運算的時候。
43 4&5,4|5的結果分別是多少?4&&5這個操作可行嗎?
4&5=4;
4|5=5;
4&&5 在java中這個操作不行!!!
在js中值為5.
在c語言中值為1(真).
解釋:
44 int能否自動轉換成byte,short,char? 是否有一定條件才能轉換?
不能自動轉換,需要強制類型轉換。
45 long能自動轉換成int嗎?long能自動轉換成float嗎?
long不能自動轉換成int,long可以自動轉換為float。因為int的取值范圍比long小,而float的取值范圍比long大。
46自動類型轉換中,容量小和容量大指的是什么意思?
容量大小指的是不同數據類型的存儲數據的范圍
47下面哪種寫法比較好?
a)70L*60*24*365*70*20
b)70*60*24*365*70*20L
a寫法比較好。因為第一種寫法L放在前面,代表70是一個long類型的數,那么運算時會最早的轉換為long類型進行運算。而b寫法在最后面,那么前面的數在進行運算時仍舊是int類型,而多次相乘之后的值很可能超出int的取值范圍,造成精度損失。所以a寫法比較好。
48 簡單講一下& 和&&的區別,|和||的區別
簡單舉例:
如果是:
條件1&條件2,那么程序會判斷條件1和條件2,只有條件1和條件2都為true時,返回值才是true,如果兩者有一個的值為false或者兩者都為false,那么返回值都是false。
&&叫做短路與,顧名思義,類似於電路中的短路。條件1&&條件2,同樣是兩個條件都為true時返回值才是true。只要有一個為false或者兩者都為false則返回false。但是,這里和&就有區別了。如果條件1已經是false了,那么程序不會判斷條件2,直接判定返回值為false。已經確定條件1是false了,那么結果必然為false,所以就不用判斷條件2了,可以提升性能。
條件1|條件2,程序會判斷條件1和條件2,只要條件1和條件2其中有一個的結果是true,那么返回值就是true。當然,如果兩者的返回值都是true,最終結果也是true。
條件1||條件2,與短路與類似,如果程序判斷條件1為true,那么結果必然為true,所以不需要判斷條件2,可以直接返回最終結果為true,節省了性能。
49 為什么不能通過返回類型來區分重載
首先,java分為編譯期和運行期。在調用的時候編譯器不知道具體要使用哪一個方法,也就無法編譯。例如有下面兩個方法:
int sum(int a,int b);
long sum(int a,int b);
當調用sum求和方法時,如:sum(1,2),那么我們到底該調用哪個方法呢?顯然,僅僅通過返回值類型來區分重載是不合理的。
50 ==和equals的區別
其實最大的一個區別點在於“==”是運算符,而equals是方法。很多人在回答這個問題的時候往往會忽略這點。
其次,==如果比較的是基本數據類型,那么比較的是數值是否相等。如果比較的是引用數據類型,那么比較的是引用對象的地址值是否一致。