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());
         }
     }
 }