值傳遞和引用傳遞
- 值傳遞是值的拷貝, 引用傳遞是引用的拷貝
public static void main(String[] args) {
String x = new String("goeasyway");
change(x);
System.out.println(x);
}
public static void change(String x) {
x = "even";
}
作者:goeasyway
鏈接:http://www.reibang.com/p/c0c5e0540928
來源:簡書
著作權(quán)歸作者所有未斑。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)劲室,非商業(yè)轉(zhuǎn)載請注明出處放钦。
String 類型是引用類型, new String 創(chuàng)建了數(shù)據(jù)在堆, 把這堆數(shù)據(jù)的首地址存在了棧
change(x) 方法傳遞參數(shù)時, 將首地址傳進(jìn)來
x = "even"; 對 String 改變, 但是無法被記錄, 因為源碼里 String 是 final 類型:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
而如果是 int a = 2 來進(jìn)行 change, 也無法改變, 但是因為其他原因:基本類型在方法傳遞時是值傳遞, 結(jié)果不會影響到原來的值;
如果希望字符串可以改變, 那么使用StringBuilder就可以了, 因為引用類型是首地址傳遞, 結(jié)果會影響到原來的值.
字節(jié)Byte, 位bit
1字節(jié)(Byte) = 8位(bit)
bit是數(shù)據(jù)存儲的最小單位,也叫做比特
文字: ASCII碼中一個英文字母占一個字節(jié), 一個中文占兩個字節(jié)
標(biāo)點: 英文標(biāo)點占一個字節(jié), 中文標(biāo)點占兩個字節(jié)
1KB = 1024B(Byte)
CPU的位指CPU一次能處理的最大位數(shù), 比如32位計算機(jī)的CPU一次最多能處理32位數(shù)據(jù)
基本數(shù)據(jù)類型的取值范圍
boolean 8bit
char 16bit
int 32bit
long 64bit
float 32bit
double 64bit
String
不是基本類型, 但是希望把它作為基本類型來用(基本類型傳值, 對象傳引用)
簡單的說是希望讓String能像基本類型一樣傳遞值(不會因為引用指向了同一個內(nèi)存地址而在傳遞的過程中改變值.)
- 特點: String 的內(nèi)容不會變.
- 原因:
//JDK源碼中: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; //String 的本質(zhì)是final的數(shù)組 }
- 單靠 final 修飾 String 只是讓 String 不可繼承,
- 而數(shù)組 value 被final修飾, 也只是防止數(shù)組的引用地址被改, 如果使用
final int[] value = {1,2,3,}; value[2]=100; //數(shù)組被改成{1,2,100} 或者 final int[] value = {1,2,3,}; Array.set(value, 2,100); //數(shù)組還是被改成{1,2,100}
- 所以還有個 private 讓 value[] 只允許自己修改, 并在寫 String 時不暴露出操作 value[]的方法.
靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類是個獨(dú)立的類, 比如A,B兩個類, B有點特殊, 雖然獨(dú)立存在, 只可以被A使用. 這時候, 如果把B并入A里, 復(fù)雜度提高, 搞得A違反了單一職責(zé), 又可能被其他類(同一個包下的C)依賴, 不符合設(shè)計的本意, 所以不如將其變成A.B, 等于加個注釋, 告訴其他類別使用B了, 它只跟A玩.
非靜態(tài)內(nèi)部類才是真正的內(nèi)部類, 持有外部類的引用.
靜態(tài)內(nèi)部類英文名static nested classes(靜態(tài)嵌套類)
Lambda
- gralde中替換編譯器為jack
defualtConfig{
useJack(true)
}
- 引用Java8
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
范例:
btnHandler.setOnClickListener(v -> {
Log.i("a","a");
});
泛型 參考自Link
-
<? extends T>
:是指 “上界通配符(Upper Bounds Wildcards)” -
<? super T>
:是指 “下界通配符(Lower Bounds Wildcards)”
-
為什么要用通配符和邊界窥翩?
使用泛型的過程中,經(jīng)常出現(xiàn)一種很別扭的情況项贺。我們有Fruit類君躺,和它的派生類Apple類class Fruit {} class Apple extends Fruit {}
然后有一個最簡單的容器:Plate類峭判。盤子里可以放一個泛型的“東西”。我們可以對這個東西做最簡單的“放”和“取”的動作:set( )和get( )方法棕叫。
class Plate<T>{ private T item; public Plate(T t){item=t; public void set(T t){item=t; public T get(){return item; }
現(xiàn)在定義一個盤子, 邏輯上"水果盤子"可以裝水果, 也可以裝蘋果
Plate<Fruit> p = new Plate<Apple>(new Apple());
但實際上Java編譯器不允許這個操作,
error: incompatible types: Plate<Apple> cannotbe converted to Plate<Fruit>
編譯器的邏輯:
蘋果 IS-A 水果
裝蘋果的盤子 NOT-IS-A 裝水果的盤子
所以就算容器里裝的東西有繼承關(guān)系, 但容器之間沒有繼承關(guān)系, 所以我們不可以把Plate<Apple>的引用傳遞給Plate<Fruit>
而通配符就是用來讓水果盤子和蘋果盤子之間發(fā)生關(guān)系 -
上界通配符
Plate<? extends Fruit>
一個能放水果以及一切水果派生類的盤子.它和
Plate<Apple>
的區(qū)別就是
Plate<? extends Fruit>
是Plate<Apple>
和Plate<Fruit>
的基類
直接好處是可以用蘋果盤子給水果盤子賦值了
Plate<? extends Fruit> = Plate<Apple>(new Apple());
如果把Fruit和Apple的例子擴(kuò)展一下,class Food{}; class Fruit extends Food{} class Meat extends Food{} class Apple extends Fruit{} class Apple extends Fruit{} class Pork extends Meat{} class Beef extends Meat{} class RedApple extends Apple{} class GreenApple extends Apple{}
上界通配符的范圍是
-
下界通配符
Plate<? super Fruit>
一個能放水果以及一切水果基類的盤子,
Plate<? super Fruit>
是Plate<Fruit>
的基類, 但不是Plate<Apple>
的基類,下界通配符的范圍是
-
副作用
容器的部分功能會失效
盤子容器具有g(shù)et和set的方法class Plate<T>{ private T item; public Plate(T t){item = t;} public void set(T t){item = t;} public T get(){return item;} }
- 4.1 上界<? extends T>不能往里存, 只能往外取
set 方法會失效, 但 get 方法有效
編譯器在看到 Plate<Apple> 后, 盤子沒有被標(biāo)上"蘋果", 而是標(biāo)上一個占位符 CAP#1, 來表示捕獲一個 Fruit 或 Fruit 的子類, 具體是什么類, 不知道, 所以以后想往里插入Apple 或者 Meat / Fruit, 編譯器都不知道能不能和 CAP#1 匹配, 所以就都不允許.Plate<? extends Fruit> p = new Plate<Apple>(new Apple()); //不能存入元素 p.set(new Fruit()); //ERROR p.set(new Apple()); //ERROR //讀取出來的東西只能存放在Fruit和它的基類 Fruit fruit = p.get(); Object object = p.get(); Apple apple = p.get();//ERROR
所以 通配符<?> 和 類型參數(shù)<T> 的區(qū)別在于, 對于編譯器來說, 所有的T, 都代表同一種類型
這里T要么都是String, 要么都是Integer, 反正保持一致public <T> List<T> fill(T...t);
而Plate<?>表示, 盤子里放的是什么, 我不知道 - 4.2 下界<? super T> 可以往里存, 但是取出來時只能放在 Object;
Plate<? super Fruit> p = new Plate<Fruit>(new Fruit()); //存入元素正常 p.set(new Fruit()); p.set(new Apple()); //讀取出來的東西只能存放在Object Apple apple = p.get(); //ERROR Fruit fruit = p.get(); //ERROR Object object = p.get();
- PESC原則
Producer Extends Consumer Super- 頻繁往外讀取內(nèi)容, 適合用上界Extends
- 經(jīng)常往里插入內(nèi)容, 適合用下界Super
參考