1、StringBuilder类
在 Java 中,我们可以使用 + 来拼接字符串,类似于下面的代码:
String s = ""; for (int i = 0; i < 1000; i++) { s = s + "," + i; }
但是在每次循环中都会创建新的字符串对象(因为字符串是不可变的),然后扔掉旧的字符串。这样,绝大部分字符串都是临时对象,不但浪费内存,还会影响GC效率。
为了能高效拼接字符串,Java标准库提供了StringBuilder
,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder
中新增字符时,不会创建新的临时对象:
StringBuilder sb = new StringBuilder(1024); for (int i = 0; i < 1000; i++) { //StringBuilder可以进行链式操作 sb.append(',').append(i); } String s = sb.toString();
对于一般的字符串操作,我们可以不必将其改写为 StringBuilder,在对字符串进行频繁的插入、删除等操作时可以将其改写成 StringBuilder。
2、JavaBean
JavaBean 是一种符合命名规范的 class,也就是说,只要符合这些命名规范的类,都可以称之为 JavaBean。
JavaBean 的命名规范:
- JavaBean 类必须是一个公共类,即访问修饰符为 public
- JavaBean 类必须有一个空的构造函数,类中必须有一个无参的public构造方法
- JavaBean类不应有公共实例变量,类变量都应该是 private
- 属性应该由一组读写方法(getXxx 和 setXxx)来访问。可以用IDE (Eclipse、IntelliJ IDEA) 来为属性自动生成 getter / setter 方法
一些特殊情况:如果操作的字段为boolean类型,此时的读方法不应该命名为 getter 方法,而是 is 方法,例如把 getName 变成 isName.
比如:
public class Person { private String age; private boolean man; public String getAge() { return this.age; } public void setAge(String age) { this.age= age; } public boolean isMan(){}; // 读方法 public void setMan(boolean value){} // 写方法 //属性只需要定义getter和setter方法,不一定需要对应的字段 public boolean isChild() { return age <= 6; } }
我们通常把一组对应的读方法(getter
)和写方法(setter
)称为属性,例如,name
属性:
- 对应的读方法是
String getName()
- 对应的写方法是
setName(String)
只有getter
的属性称为只读属性,只有setter
的属性称为只写属性,很明显,只读属性很常见,只写属性不常见。
3、枚举类(enum)
我们使用 enum 来定义枚举类。枚举类中的每个枚举都是单例模式,枚举类中的实例对象是有限且固定的。
public class Main { public static void main(String[] args) { Weekday day = Weekday.SUN; //创建枚举类中的一个实例对象 if (day == Weekday.SAT || day == Weekday.SUN) { //多次创建同一个值的枚举对象,拿到的都是同一个对象 System.out.println("Work at home!"); } else { System.out.println("Work at office!"); } } } enum Weekday { SUN, MON, TUE, WED, THU, FRI, SAT; }
使用enum
定义的枚举类是一种引用类型,引用类型比较,要始终使用equals()
方法,但enum
类型可以例外。这是因为enum
类型的每个常量在JVM中只有一个唯一实例,所以可以直接用==
比较
3.1、枚举类的特点
通过enum
定义的枚举类,和其他的class
没有任何区别,enum
定义的类型就是class
,只不过它有以下几个特点:
- 定义的
enum
类型总是继承自java.lang.Enum
,且无法被继承; - 只能定义出
enum
的实例,而无法通过new
操作符创建enum
的实例; - 定义的每个实例都是引用类型的唯一实例;
- 可以将
enum
类型用于switch
语句
原理:
//我们定义的Color枚举类: public enum Color { RED, GREEN, BLUE; } //编译器编译出的class大概就像这样: public final class Color extends Enum { // 继承自Enum,标记为final class // 每个常量均为全局唯一,并且都是实例 public static final Color RED = new Color(); public static final Color GREEN = new Color(); public static final Color BLUE = new Color(); // private构造方法,确保外部无法调用new操作符: private Color() {} }
所以,编译后的enum
类和普通class
并没有任何区别。但是我们自己无法按定义普通class
那样来定义enum
,必须使用enum
关键字,这是Java语法规定的。
3.2、枚举值的方法
因为enum
是一个class
,每个枚举的值都是class
实例,因此,这些实例有一些方法,如下:
name()方法 返回常量名
String s = Weekday.SUN.name(); // "SUN"
ordinal()返回定义的常量的顺序,从0开始计数
int n = Weekday.MON.ordinal(); // 1
但是改变枚举常量的顺序就会导致ordinal()
返回值发生变化。
因为enum
本身是class
,所以我们可以定义private
的构造方法,并且,给每个枚举常量添加字段:
public class Main { public static void main(String[] args) { Weekday day = Weekday.SUN; if (day.dayValue == 6 || day.dayValue == 0) { System.out.println("Work at home!"); //输出 Work at home! } else { System.out.println("Work at office!"); } } } enum Weekday { MON(1), TUE(2), WED(3), THU(4), FRI(5), SAT(6), SUN(0); public final int dayValue; private Weekday(int dayValue) { this.dayValue = dayValue; } }
这样就无需担心顺序的变化,新增枚举常量时,也需要指定一个int
值。
给枚举类添加的字段也可以是非final类型,即让该字段可以在使用时被修改,但是不推荐这样做!