Java的基本使用之核心类
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
- 属性(注意,不是成员变量,属性指的是getter或者setter方法名后面的属性名,比如getName,属性即为name)应该由一组读写方法(getXxx 和 setXxx)来访问,一个 JavaBean 对象的属性可以是可读写、或只读、或只写。可以用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方法,不是一定需要有对应的字段即成员变量。比如这个类中就没有下面对应的child字段 public boolean isChild() { return age <= 6; } }
我们通常把一组对应的读方法(getter
)和写方法(setter
)称为属性,例如,name
属性:
- 对应的读方法是
String getName()
- 对应的写方法是
setName(String)
只有getter
的属性称为只读属性,只有setter
的属性称为只写属性,很明显,只读属性很常见,只写属性不常见。
3、枚举类(enum)
3.1、枚举类介绍
枚举类说明:
- 枚举类的对象是确定的,只有有限个。例如,如果把季节定义成类,那么这个类只有四个对象:春夏秋冬。此时就能把季节定义为一个枚举类,这个枚举类的对象是确定的并且只有有限个。
- 当需要定义一组常量时,强烈建议使用枚举类。
- 如果枚举类只有一个对象,则可以作为一种单例模式的实现方式。
枚举类的举例:
- 季节:春,夏,秋,冬
- 线程的状态:创建、就绪、运行、阻塞、死亡
枚举类中的每个枚举都是单例模式,枚举类中的实例对象是有限且固定的。
3.2、定义枚举类
在JDK 5.0之前,需要我们自定义枚举类。
//自定义枚举类 class Season{ //1.声明Season对象的属性:private final修饰 private final String seasonName; private final String seasonDesc; //2.私有化类的构造器,并给对象属性赋值 private Season(String seasonName,String seasonDesc){ this.seasonName = seasonName; this.seasonDesc = seasonDesc; } //3.提供当前枚举类的多个对象:public static final修饰 public static final Season SPRING = new Season("春天","春天来了"); public static final Season SUMMER = new Season("夏天","夏天来了"); public static final Season AUTUMN = new Season("秋天","秋天来了"); public static final Season WINTER = new Season("冬天","冰天来了"); }
从JDK5.0 开始可以使用enum关键字来定义枚举类,简化书写过程。
package test; //使用enum关键字枚举类 public enum Season { //1.提供当前枚举类的对象,多个对象之间用","隔开,末尾对象";"结束 SPRING("春天","春天来了"), SUMMER("夏天","夏天来了"), AUTUMN("秋天","秋天来了"), WINTER("冬天","冰天来了"); //2.声明Season对象的属性:private final修饰 private final String seasonName; private final String seasonDesc; //3.私化类的构造器,并给对象属性赋值 private Season(String seasonName,String seasonDesc){ this.seasonName = seasonName; this.seasonDesc = seasonDesc; } //4.其他需求:根据需要定义 public String getSeasonName() { return seasonName; } public String getSeasonDesc() { return seasonDesc; } //其他诉求1:提供toString() @Override public String toString() { return "Season{" + "seasonName='" + seasonName + '\'' + ", seasonDesc='" + seasonDesc + '\'' + '}'; } }
使用枚举类时,通过 枚举类名.常量名 来使用,此时得到的是枚举类的实例对象,可以通过访问该类的成员方法来获取相应的数据。
package test; public class Test02 { public static void main(String[] args) { Season spring = Season.SPRING; System.out.println(spring); //Season{seasonName='春天', seasonDesc='春暖花开'} String seasonStr = Season.SUMMER.getSeasonName(); String seasonDesc = Season.SUMMER.getSeasonDesc(); System.out.println(seasonStr + " " + seasonDesc); // 夏天 夏天来了 } }
3.3、枚举类的特点
通过enum
定义的枚举类,和其他的class
没有任何区别,enum
定义的类型就是class
。
- 使用enum关键字定义的枚举类默认继承了java.lang.Enum类,由于Java的单继承性,不能再继承其他类。
- 必须要在第一行声明枚举类的对象,否则会报错。
- 从JDK5.0 开始Java的 switch语句可以把使用enum定义的枚举类的对象作为表达式,并且case只能直接使用枚举类对象名,不能加类名限定。如下:
package test; public class Test02 { public static void main(String[] args) { Season sea = Season.SPRING; switch (sea){ case Season.SPRING://这里编译会报错,应该直接使用 SPRING System.out.println(111); break; case SUMMER: System.out.println(222); break; case AUTUMN: break; case WINTER: break; } } }
使用enum
定义的枚举类是一种引用类型,引用类型比较,要始终使用equals()
方法,但enum
类型可以例外。这是因为enum
类型的每个常量在JVM中只有一个唯一实例,所以可以直接用==
比较
3.4、枚举类的主要方法
- values()方法:将枚举类的所有对象以数组形式返回,利用此方法可以方便地遍历枚举类的值。
- valueOf(String name)方法:返回枚举类中对象名为name的对象。若没有,则抛出IllegalArgumentException的异常。
- toString()方法:返回枚举类对象的名称
package test; public class Test02 { public static void main(String[] args) { Season summer = Season.SUMMER; //toString():返回枚举类对象的名称 System.out.println(summer.toString()); //values():返回所的枚举类对象构成的数组 Season[] values = Season.values(); for(int i = 0;i < values.length;i++){ System.out.println(values[i]); } //valueOf(String objName):返回枚举类中对象名是objName的对象。 Season winter = Season.valueOf("WINTER"); //如果没objName的枚举类对象,则抛异常:IllegalArgumentException Season winter1 = Season.valueOf("WINTER1"); System.out.println(winter1); } }
输出结果如下:
3.5、枚举值的其他方法
因为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类型,即让该字段可以在使用时被修改,但是不推荐这样做!