boolean比较特殊,只有true和false,可以单位存储,但不是规定。JVM编译时会将boolean类型转为int类型,1=true,0=false。JVM支持boolean数组,但是是通过读写byte数组实现。
具体是指将基本类型转化为包装类型。具体做法是通过调用valueOf方法实现的。例如,将char转型为Character类型调用的就是Character.valueOf()。在valueOf的执行上表现为,按类型分类:
代码举例:
Character c = "c";
指将包装类型转换为基本类型。具体做法是通过包装类型的xxxValue方法来实现转换。
代码举例:
Character c = "c";
char a = c;
手动装箱是指显式调用new的方式经行装箱,例如:
Character c = new Character("c");
自动装箱指用字面值代替显示调用new的方式进行装箱,这种方式是jdk 1.5之后出现的特性,例如:
Character c = "c";
区别:手动装箱每次创建新对象,自动装箱会先判断缓冲池中是否存在该字面量,若有则直接返回它的引用,若无再创建新对象。在 Java 8 中,Integer 缓存池的大小默认为 -128~127。
资料:在 jdk 1.8 所有的数值类缓冲池中,Integer 的缓冲池 IntegerCache 很特殊,这个缓冲池的下界是 - 128,上界默认是 127,但是这个上界是可调的,在启动 jvm 的时候,通过 -XX:AutoBoxCacheMax= 来指定这个缓冲池的大小,该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界。
String 被声明为final,也就是说无法被继承,所有的包装类型也无法被继承。当前String内部存储字符串的方式是使用带final关键字的byte数组,因此还带有coder标识来识别编码方式。由于存储字符串的数组是final修饰的,无法被修改,也就意味着String对象一旦被创建就无法被改变。不改变就意味着有几个好处:
String | StringBuffer | StringBuilder | |
---|---|---|---|
可变性 | 不可变 | 可变 | 可变 |
线程安全性 | 线程安全 | 线程安全 | 线程不安全 |
字符串常量池保存所有的字符串字面量,字符串池由String类私有的维护, 在创建String对象的时候有两种创建方式,两种的性能不大相同:
String a = new String("a");
这种方法的执行过程如下,JVM首先拿着"a"这个字符串去String pool里面找,如果没找到,就先在池里新建一个”a“对象然后再去堆里新建一个”a"字符串对象,再把堆里的字符串对象的引用返回;如果找到了,pool和JVM相视一笑,JVM就直接在堆里创建"a"字符串对象并返回它的引用。 String a = "a";
这种方法会让JVM先带着”a"去pool里面找有没有一样的,如果找到了就直接返回pool里的字符串对象的引用;如果找不到,JVM只能长叹一声然后在pool里创建一个新的”a"字符串对象并返回它的引用。Java参数是按值传递,不是引用传递。传对象的时候实际传递的是这个对象的地址。(我理解的就是进去的东西只是一个指针,调用对象的方法的时候会自动解引用)因此,在函数内对传进来的对象进行修改如果是使用 ” . “ 的方式(使用方法或直接修改【这不封闭】)可以修改成功。若是使用 ”=“的方式,只是把形参的值(形参存地址)换了一个,外面的实参没动,实参的值不变(存的地址不变)。
举例:
public class PassByValueExample {
public static void main(String[] args) {
Dog dog = new Dog("A");
System.out.println(dog.getObjectAddress()); // Dog@4554617c
func(dog);
System.out.println(dog.getObjectAddress()); // Dog@4554617c
System.out.println(dog.getName()); // A
}
private static void func(Dog dog) {
System.out.println(dog.getObjectAddress()); // Dog@4554617c
dog = new Dog("B");
System.out.println(dog.getObjectAddress()); // Dog@74a14482
System.out.println(dog.getName()); // B
}
}
Java 不支持隐式向下转型,不允许精度降低的自动操作。
首先,字面量的浮点数,都是double类型的。这就导致了float不能直接写字面量赋值,即下面的例子是失败的:
float a = 1.1;// 跑不动
那要想成功怎么办,让字面量f:
float a = 1.1f;// 冲
字面量的整数,很有意思,会根据字面量的大小是不是在整数类型的取值范围内来判断这个语句是否有类型转换的问题,举个例子,下面的代码数值在short的取值范围内:
Short a = 1;// 可以跑
下面的不在取值范围内:
Short a = 32768; // 不行
Java的switch支持了一个非常令人激动的特性,可以在条件判断中使用字符串类型,哦我的上帝,真令人高兴。同时switch是不支持long的,因为设计switch的时候就没想过可能会有那么case,如果有,那一定是神仙。有复杂的值需要判断,这边建议您用if。
一言以蔽之,不许动。
修饰变量(也叫静态变量,下面的一样):被修饰的变量将会是整个类一起共享的,而不是单个对象独占的,内存中就一份,不管这个类你创建了多少对象。实例变量(没有static修饰变量的都是)也好说,就是每个对象自己的,几个对象就几个实例变量。
修饰方法:同样,被修饰的方法是整个类共有的,但是,这个方法里面只能有静态变量,必须有方法体,不能有this和super。
修饰语句块:整个类共有,只在类初始化的时候运行一次。
修饰内部类:非静态内部类需要依赖外部实例,没有外部实例就不能创建,有了外部实例后使用"外部实例.new 内部类()"的格式创建内部类,不限量。静态内部类不依赖外部实例,可以自由创建。
静态导包:在使用静态变量和方法时不用再指明 ClassName,从而简化代码,但可读性大大降低,举例:
package a;// 提供静态内部类
/**
* @author ZTL
*/
public class JavaBlogTest {
public static class MyInnerClass {
}
public static void main(String[] args) {
MyInnerClass a = new MyInnerClass();
MyInnerClass b = new MyInnerClass();
}
}
package b;// 消费静态内部类
import static a.JavaBlogTest.*;
/**
* @author ZTL
*/
public class JavaBlogTest2 {
public static void main(String[] args) {
MyInnerClass a = new MyInnerClass();
}
}