枚举
枚举类是一种特殊的类,里面的值全部都是静态常量,每一个枚举值都相当于一个本类对象,
只不过,调用对象的toString方法打印的是对象名。如:
//实际上,每一个枚举值都相当于一个本类对象,所以每声明一个枚举值,相当于执行以下代码:
public static final BLUE=new Color();
public static final RED=new Color();
public static final YELLOW=new Color();
public static final GREEN=new Color();
注意:①在枚举类中,枚举值必须放在第一行,其他所有代码,必须放在枚举值的后面。
②枚举类中的构造函数,只能是私有化的,在声明枚举值时,自动调用。如:
enum Color{
BLUE,RED,YELLOW,GREEN,BLACK;
private Color(){
System.out.println("hahahhaha");
}
}
一、String是不可变对象
java.lang.String类使用了final修饰,不能被继承。Java程序中的所有字面值,即双引号括起的字符串,如"abc",都是作为String类的实例实现的。String是常量,其对象一旦构造就不能再被改变。换句话说,String对象是不可变的,每一个看起来会修改String值的方法,实际上都是创造了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。String对象具有只读特性,指向它的任何引用都不可能改变它的值,因此,也不会对其他的引用有什么影响。但是字符串引用可以重新赋值。java字符串在内存中采用unicode编码方式,任何一个字符对应两个字节的定长编码,即任何一个字符(无论中文还是英文)都算一个字符长度,占用两个字节。
例1:
public class Immutable {
public static String upcase(String s) {
return s.toUpperCase();
}
public static void main(String[ ] args) {
String str1= "Hello World";
System.out.println(str1); //Hello World
String str2 = upcase(str1);
System.out.println(str2); //HELLO WORLD
System.out.println(str1); //Hello World
}
}
当把str1传递给upcase()方法时,实际传递的是引用的一个拷贝。其实,每当把String对象作为方法的参数时,都会复制一份引用,而该引用所指的对象其实一直待在单一的物理位置上,从未动过。
二、String常量池
常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。Java为了提高性能,静态字符串(字面量/常量/常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串。对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果常量池中存在即返回该对象。
例2:
标题
public class test1 {
public static void main(String[] args){
String str1 = "Hello";
//不会创建新的String对象,而是使用常量池中已有的"Hello",
String str2 = "Hello";
System.out.println(str1 == str2); //true
//使用new关键字会创建新的String对象
String str3 = new String("Hello");
System.out.println(str1 == str3); //false
}
}
四、创建了几个对象的问题
1 String str1 = "abc";
2 String str2 = new String("abc");
对于1中的 String str1 = “abc”,首先会检查字符串常量池中是否含有字符串abc,如果有则直接指向,如果没有则在字符串常量池中添加abc字符串并指向它.所以这种方法最多创建一个对象,有可能不创建对象。
对于2中的String str2 = new String(“abc”),首先会在堆内存中申请一块内存存储字符串abc,str2指向其内存块对象。同时还会检查字符串常量池中是否含有abc字符串,若没有则添加abc到字符串常量池中。所以 new String()可能会创建两个对象。
所以如果以上两行代码在同一个程序中,则1中创建了1个对象,2中创建了1个对象。如果将这两行代码的顺序调换一下,则1 String str2 = new String(“abc”)创建了两个对象,而2 String str1 = "abc"没有创建对象。
五、String的匹配相等问题
使用String类经常需要对两个字符串进行对比,看是否相等。有==和equals两种选择,这两者方法区别很大:
比对象的内容是否相等使用equals(),比较两个引用是否指向同一个对象时用==;equals()是看内容是否相等,比较好理解。而==是看是否属于同一个对象。
首先还要明白这个概念:常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。主要看编译期字符串能否确定。
看看下面几个例子:
test1: