枚举
Java 5.0引入了枚举类型。一个集的枚举是列出某些有穷序列集的所有成员。
public enum <枚举名> {
<枚举实例成员1>, <枚举实例成员2>;
}
由于枚举实例成员都是静态的常量,所以枚举实例成员应该全部是大写字母。
枚举类型类似于类类型,(可以定义成员变量、成员方法、内部类、初始化代码块),但是不能用new来创建其实例对象(也就是说枚举中的构造方法只能用private修饰,不允许外界new产生实例对象),仅可以定义其成员变量并使用枚举中已定义的静态实例成员。
枚举中只能引用已有成员变量,而不能定义新的成员变量,假如同一个枚举实例成员被多此引用,实际上是引用同一个实例成员。
- 枚举的构造方法
枚举像类一样可以有构造方法,一般用构造方法进行对成员变量的初始化。
构造方法只能被private修饰或者默认修饰符。枚举不能被继承。
当定义了带参的构造方法而没有定义默认的无参构造方法时,需要我们在枚举的实例成员的后面分加上括号及相关的构造方法的参数来确保完整定义实例。
在定义枚举时,必须将枚举实例成员放在枚举{}里的最前面(枚举成员实例之间用,
区分,枚举成员实例最后用;
来分割成员变量)。
- 枚举中的方法
定义枚举枚举实例后,可通过<实例对象>.ordinal()
方法来返回枚举的索引。可通过<实例对象>.values()
来获取按照定义枚举时的实例成员顺序为索引的枚举类型数组。通过这种方式可以遍历枚举内容。
for (<枚举类型> <变量名> : <枚举名>.values()) {
System.out.println(<变量名>.ordinal() + <变量名>);
}
Java中的设计模式Design Pattern
拥有一定意义的固定套路,便于实现某种目的,使结构更加清晰。设计模式分为三种:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)和行为型模式(Behavioral Patterns)。
单例设计模式
这种设计模式需要确保类只能产生一个实例。以解决一个全局使用的类频繁的创建和删除。
- 在该类中定义好实例。通过私有化构造来保证只能在该类中创建该实例,在该类中定义类型为类类型的静态成员常量,然后提供public外部的访问方式。
public class Singleton1 {
private static final Singleton1 singleton = new Singleton1();
private Singleton1() {
}
public static final Singleton1 getInstance() {
return singleton;
}
}
- 当使用该类的时候再产生实例。先私有化构造,在类中仅声明该类实例,并不执行new初始化实例操作。(这种方式在单线程下数据安全,但是在多线程下多个线程要访问共享数据所以没有synchronized锁对象时,线程不安全!)解决方式是在getInstance()方法中添加synchronized
public class Singleton2 {
private static Singleton2 singleton;
private Singleton2() {
}
public static final Singleton2 getInstance() {
if (Singleton2.singleton == null) {
singleton = new Singleton2();
}
return singleton;
}
}
- 由于枚举中已经定义了枚举的静态实例成员,可以通过枚举得到单例模式。
public enum Singleton3 {
SINGLETON;
}
- 当静态内部类中要访问外部类的静态成员变量和静态成员方法时,静态内部类仅加载一次(所以多线程下,这种方式是数据安全的)。静态内部类仅在调用时加载,且只加载一次。类加载过程是线程安全的。
public class Singleton4 {
private Singleton4() {
}
public static class Inner {
private static final Singleton4 inner = new Singleton4();
}
public static final Singleton4 getInstance() {
return Inner.inner;
}
}
- 破坏单例的方式
- 通过Java的反射机制来破解单例(即使该类是私有的构造方法)。
- 通过反序列化可以破坏单例。先通过序列化将对象变为字节码,存储进某个文件。以后再用反序列化还原为对象(此时没有用构造的方式创建对象)。可以阻止反序列化。
享元模式 Flyweight Pattern
主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式
public class Flyweight {
public static void main(String[] args) {
// 这里Integer类中实现了享元模式,==比较来判断两者地址值是否相同。重用已有对象。String类中加入有相同对象时,不创建新的对象而是使用常量池中的数据。
System.out.println(Integer.valueOf(-129) == Integer.valueOf(-129));
System.out.println(Integer.valueOf(-128) == Integer.valueOf(-128));
System.out.println(Integer.valueOf(1) == Integer.valueOf(1));
System.out.println(Integer.valueOf(127) == Integer.valueOf(127));
System.out.println(Integer.valueOf(128) == Integer.valueOf(128));
}
}
原型模式 Prototype Pattern
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。
用于创建重复对象,同时又能保证性能。这种模式是实现了一个Cloneable原型接口,该接口用于创建当前对象的克隆。
public class Student {
String name;
int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Prototype implements Cloneable{// 原型模式
String string;
int num;
Student student;
public Prototype(String string, int num, Student student) {
this.string = string;
this.num = num;
this.student = student;
}
@Override
public String toString() {
return "Prototype{" +
"string='" + string + '\'' +
", num=" + num +
", student=" + student +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
这种方式实现的是浅拷贝,也就是说拷贝基本数据类型时,两者没有关联,但拷贝类类型成员变量时(调用clone()方法),两者实际上引用了同一个地址值。这里用clone()来克隆Student类的时候只复制了原来的Student的成员地址。(这里的clone()方法需要抛出CloneNotSupportedException异常,且该方法返回值是Object类型,当需要定义时需要类型转换)浅拷贝是将实现的Cloneable接口中的clone()方法按照编译器默认的方式return super.clone();
覆盖。
public class Prototype implements Cloneable, Serializable {// 深拷贝
String string;
int num;
Student student;
@Override
protected Object clone() throws CloneNotSupportedException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();// 字节数组的输出流
ObjectOutputStream objectOutputStream;
ObjectInputStream objectInputStream;
try {
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);// 对象输出流中可以实现把对象变为字节流
objectOutputStream.writeObject(this);// 把当前对象写入输出流中。
byte[] bytes = byteArrayOutputStream.toByteArray();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
objectInputStream = new ObjectInputStream(byteArrayInputStream);
return objectInputStream.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
return "Prototype{" +
"string='" + string + '\'' +
", num=" + num +
", student=" + student +
'}';
}
public Prototype(String string, int num, Student student) {
this.string = string;
this.num = num;
this.student = student;
}
}
可以通过序列化和反序列化来实现深拷贝。需要将实现的Cloneable接口中的clone()方法按照序列化和反序列化的方式来覆盖。
实现序列化接口Serializable