值传递和引用传递
- 值传递是值的拷贝, 引用传递是引用的拷贝
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.jianshu.com/p/c0c5e0540928
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
String 类型是引用类型, new String 创建了数据在堆, 把这堆数据的首地址存在了栈
change(x) 方法传递参数时, 将首地址传进来
x = "even"; 对 String 改变, 但是无法被记录, 因为源码里 String 是 final 类型:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
而如果是 int a = 2 来进行 change, 也无法改变, 但是因为其他原因:基本类型在方法传递时是值传递, 结果不会影响到原来的值;
如果希望字符串可以改变, 那么使用StringBuilder就可以了, 因为引用类型是首地址传递, 结果会影响到原来的值.
字节Byte, 位bit
1字节(Byte) = 8位(bit)
bit是数据存储的最小单位,也叫做比特
文字: ASCII码中一个英文字母占一个字节, 一个中文占两个字节
标点: 英文标点占一个字节, 中文标点占两个字节
1KB = 1024B(Byte)
CPU的位指CPU一次能处理的最大位数, 比如32位计算机的CPU一次最多能处理32位数据
基本数据类型的取值范围
boolean 8bit
char 16bit
int 32bit
long 64bit
float 32bit
double 64bit
String
不是基本类型, 但是希望把它作为基本类型来用(基本类型传值, 对象传引用)
简单的说是希望让String能像基本类型一样传递值(不会因为引用指向了同一个内存地址而在传递的过程中改变值.)
- 特点: String 的内容不会变.
- 原因:
//JDK源码中: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; //String 的本质是final的数组 }
- 单靠 final 修饰 String 只是让 String 不可继承,
- 而数组 value 被final修饰, 也只是防止数组的引用地址被改, 如果使用
final int[] value = {1,2,3,}; value[2]=100; //数组被改成{1,2,100} 或者 final int[] value = {1,2,3,}; Array.set(value, 2,100); //数组还是被改成{1,2,100}
- 所以还有个 private 让 value[] 只允许自己修改, 并在写 String 时不暴露出操作 value[]的方法.
静态内部类
静态内部类和非静态内部类
静态内部类是个独立的类, 比如A,B两个类, B有点特殊, 虽然独立存在, 只可以被A使用. 这时候, 如果把B并入A里, 复杂度提高, 搞得A违反了单一职责, 又可能被其他类(同一个包下的C)依赖, 不符合设计的本意, 所以不如将其变成A.B, 等于加个注释, 告诉其他类别使用B了, 它只跟A玩.
非静态内部类才是真正的内部类, 持有外部类的引用.
静态内部类英文名static nested classes(静态嵌套类)
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)”
-
为什么要用通配符和边界?
使用泛型的过程中,经常出现一种很别扭的情况。我们有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; }
现在定义一个盘子, 逻辑上"水果盘子"可以装水果, 也可以装苹果
Plate<Fruit> p = new Plate<Apple>(new Apple());
但实际上Java编译器不允许这个操作,
error: incompatible types: Plate<Apple> cannotbe converted to Plate<Fruit>
编译器的逻辑:
苹果 IS-A 水果
装苹果的盘子 NOT-IS-A 装水果的盘子
所以就算容器里装的东西有继承关系, 但容器之间没有继承关系, 所以我们不可以把Plate<Apple>的引用传递给Plate<Fruit>
而通配符就是用来让水果盘子和苹果盘子之间发生关系 -
上界通配符
Plate<? extends Fruit>
一个能放水果以及一切水果派生类的盘子.它和
Plate<Apple>
的区别就是
Plate<? extends Fruit>
是Plate<Apple>
和Plate<Fruit>
的基类
直接好处是可以用苹果盘子给水果盘子赋值了
Plate<? extends Fruit> = Plate<Apple>(new Apple());
如果把Fruit和Apple的例子扩展一下,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>
的基类,下界通配符的范围是
-
副作用
容器的部分功能会失效
盘子容器具有get和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> 后, 盘子没有被标上"苹果", 而是标上一个占位符 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
所以 通配符<?> 和 类型参数<T> 的区别在于, 对于编译器来说, 所有的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- 频繁往外读取内容, 适合用上界Extends
- 经常往里插入内容, 适合用下界Super
参考