Java SE中必可避免的会学到new关键字(用以创建对象),之后又了解到了克隆以及反射都可以创建对象。。今天又学到了静态工厂以及构建器,所以呢,在此做一个小结。
下面我先以创建对象的几种方式开始讲起,然后在优化构造器用以创建对象(即为何尽量使用构建器而不是其他的几种),介绍的不周到的地方还请大佬见谅,我还是个弟弟~~~~
创建对象五种方式
-
new关键字
语法:类名 对象名=new 类名();
Student student1=new Student("小刘",22);
-
反射:Class类的newInstance方法
语法:java.lang.Class Class 类对象名称=java.lang.Class.forName(要实例化的类全称);类名 对象名=(类名)Class类对象
名称.newInstance();
Class cl=Class.forName("Student");
Student student2=(Student)cl.newInstance();
-
反射:Constructor类的newInstance方法
Constructor<Student> constructor = Student.class.getInstance()
Student stu3 = constructor.newInstance();
注意:对于构造器的反射还可以解析私有构造器,反射还可以解析一个类的方法还有属性,详情看我另外一篇博客或者百度。。
Class classPer1=Class.forName("demo.Person"); //int为Person类私有构造器中的参数,如果为多参则依次添加多个参数的类即可 Constructor constructor=classPer1.getDeclaredConstructor(int.class); //暴力反射 constructor.setAccessible(true); Person person=(Person) constructor.newInstance(2);
-
克隆:object.clone() (不常用)
语法:类名对象名=(类名)已创建好的类对象名.clone();
Student student3=(Student)student2.clone();
-
对象的反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
对上述示例的说明如下:
- new 关键字:调用类的无参构造方法,也是java中高耦合的罪魁祸首。
- Class 对象的 newInstance():调用类的无参构造方法。Class的newInstance方法内部是调用Constructor的newInstance()方法。其实这也是众多框架Spring、Hibernate、Struts等使用后者的方式。
- Constructor类的 newInstance():调用类的无参认构造方法,或者有参构造。
- Object 类的 clone() :必须实现 Cloneable 接口。不会调用类的构造方法,它会创建一个复制的对象,这个对象和原来的对象具有不同的内存地址,但它们的属性值相同。
- 对象的反序列化:不会调用类的构造方法
优化过程
-
构造器
问题:参照静态工厂的优点就是它的问题。。
-
静态工厂
优点:
有名称,便于阅读。
Singleton
可以返回任意子类型的对象,提高了灵活性。
创建参数化实例的时候,它使得代码变得简单。
缺点:不能很好地扩展到大量的可选参数,即对类中大量的属性实例化不能很好地解决。
模板:
package serviceprovider;
public class Car {
private int price;
private int length;
private int height;
private int width;
private String color;
private static final Car redCar = new Car("red");
private static final Car blueCar = new Car("blue");
private static final Car bestSaleCar = new Car(350000, 3, 2, 2, "blue");
public Car(int price) {
super();
this.price = price;
}
public Car(int price, int length, int height, int width, String color) {
super();
this.price = price;
this.length = length;
this.height = height;
this.width = width;
this.color = color;
}
public Car(String color) {
super();
this.color = color;
}
/**
* 下面是静态工厂方法
*/
public static Car getRedCar(){
return redCar;
}
public static Car getBlueCar(){
return blueCar;
}
/**
* 获取这个季度卖的最好的车
* @return
*/
public static Car getBestSaleCar(){
return bestSaleCar;
}
}
-
重叠构造器,即第一个构造方法只提供必要参数,第二个构造器有一个可选参数,第三个构造器有两个可选参数。。直到最后一个构造以包含了所有的可选参数
优点:可行
缺点:当有许多参数的时候,客户代码很难编写,并且任然难以阅读。
-
Javabean方式,即setter和getter方法
优点:与重叠构造器类似,可行。
缺点:Javabean模式自身有着很严重的缺点,构造过程被分到了几个调用中,在构造过程中可能处于不一致的状态,并且还需
要程序员付出额外的努力来确保它的线程安全。
-
构建器
优点:保证像重叠构造器那样的安全性,也能保证像Javabean模式那么好的可读性。
缺点:可能就是在创建对象之前,必须先创建它的构建器。。
示例:
public class NutritionFcts{
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder{
//Required parameters
private int servingSize;
private int servings;
//Optional parameters---initalized to default values
private int calories=0;
private int fat=0;
private int carbohydrate=0;
private int sodium=0;
public Builder(int servingSize,int servings){
this.servings=servings;
this.servingSize=servingSize;
}
public Builder calories(int val){
calories=val;
return this;
}
public Builder fat(int val){
fat=val;
return this;
}
public Builder carbohydrate(int val){
carbohydrate=val;
return this;
}
public Builder sodium(int val){
sodium=val;
return this;
}
public NutritionFcts builder(){
return new NutritionFcts();
}
}
private NutritionFcts(Builder builder){
servingSize=builder.servingSize;
servings=builder.servings;
calories=builder.calories;
fat=builder.fat;
carbohydrate=builder.carbohydrate;
sodium=builder.sodium;
}
}
//客户端代码
NutritionFcts cocaCola=new NutritionFcts.Builder(200,20).calories(100).fat(20).carbohydrate(65).sodium(89).builder();
通用生成对象Generator(可做工具类)
1、申明一个Generator接口,提供一个next()方法,用以返回一个新的类对象。
public interface Generator<T> {
T next();
}
2、定义一个BasicGenerator类,对Generator接口进行实现,用以生成某个类的对象。通过create()方法创建新的对象,使用泛型参数。
package generator;
/**
* @author wangjie
* @version 2018/11/19
* 一个通用的generator
*/
public class BasicGenerator<T> implements Generator<T> {
private Class<T> type;
public BasicGenerator(Class<T> type){
this.type = type;
}
@Override
public T next(){
try{
return type.newInstance();
}catch(Exception e){
throw new RuntimeException(e);
}
}public static <T> Generator<T> create(Class<T> type){
return new BasicGenerator<T>(type);
}}
3、定义一个具有默认构造器的简单类:这个类CountedObject能够实现计数功能,告诉我们创建了几个CountedObject实例,并通过toString()方法打印其编号。
package generator;
/**
* @author wangjie
* @version 2018/11/19
*/
public class CountedObject {
private static long counter = 0;
private final long id = counter++;
public long id(){ return id; }
public String toString(){ return "CountedObject " + id; }
}
4、此时,可以使用BasicGenerator很容易地为CountedObject类创建一个Generator:
package generator;
/**
* @author wangjie
* @version 2018/11/19
*/
public class BasicGeneratorDemo {
public static void main(String[] args) {
Generator<CountedObject> gen = BasicGenerator.create(CountedObject.class);
for (int i = 0; i < 5; i++) {
System.out.println(gen.next());
}
}
}