zoukankan      html  css  js  c++  java
  • 【Java基础】创建和销毁对象

    Num1:考虑用静态工厂方法代替构造器

    对于类而言,常见的方法是提供一个公有的构造器,但其实还有一种方法叫做静态工厂方法(static factory method),它只是一个返回类的实例静态方法。

    目前比较流行的规范是把静态工厂方法命名为valueOf或者getInstance

    valueOf:该方法返回的实例与它的参数具有同样的值,例如:

    Integer a=Integer.valueOf(100); //返回取值为100的Integer对象
    

    从上面代码可以看出,valueOf()方法能执行类型转换操作,在本例中,把int类型的基本数据转换为Integer对象。

    getInstance:返回的实例与参数匹配,例如:

    Calendar cal=Calendar.getInstance(Locale.CHINA); //返回符合中国标准的日历
    

    优势:

    • 静态工厂方法与构造器不同的第一大优势在于,他们有名称,更有可读性。
    • 静态工厂方法与构造器不同的第二大优势在于,不必每次调用它们的时候都创建一个新对象。
    • 静态工厂方法与构造器不同的第三大优势在于,它们可以返回原返回类型的任何子类型的对象。
    • 静态工厂方法与构造器不同的第四大优势在于,在创建参数化实例的时候,它们使代码变得更加简洁。

    缺点:

    • 类如果不含公有的或者受保护的构造器,就不能被子类化。
    • 它们与其他的静态方法实际上没有任何区别。

    Num2:遇到多个构造器参数时要考虑用构造器

    一般有以下三种构造器的方式

    • 重叠构造器模式
    • JavaBeans模式
    • Builder模式

    重叠构造器模式

    public class NutritionFacts {
    	private final int servingSize; // (mL) required
    	private final int servings; // (per container) required
    	private final int calories; // optional
    	private final int fat; // (g) optional
    	private final int sodium; // (mg) optional
    	private final int carbohydrate; // (g) optional
    
    	public NutritionFacts(int servingSize, int servings) {
    		this(servingSize, servings, 0);
    	}
    
    	public NutritionFacts(int servingSize, int servings, int calories) {
    		this(servingSize, servings, calories, 0);
    	}
    
    	public NutritionFacts(int servingSize, int servings, int calories, int fat) {
    		this(servingSize, servings, calories, fat, 0);
    	}
    
    	public NutritionFacts(int servingSize, int servings, int calories, int fat,
    			int sodium) {
    		this(servingSize, servings, calories, fat, sodium, 0);
    	}
    
    	public NutritionFacts(int servingSize, int servings, int calories, int fat,
    			int sodium, int carbohydrate) {
    		this.servingSize = servingSize;
    		this.servings = servings;
    		this.calories = calories;
    		this.fat = fat;
    		this.sodium = sodium;
    		this.carbohydrate = carbohydrate;
    	}
    
    	public static void main(String[] args) {
    		NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
    	}
    }
    

    JavaBeans模式

    在这种模式下,调用一个无参构造器来创建对象,然后调用setter方法来设置每个必要的参数。如下:

    public class NutritionFacts {
    	// Parameters initialized to default values (if any)
    	private int servingSize = -1; // Required; no default value
    	private int servings = -1; // "     " "      "
    	private int calories = 0;
    	private int fat = 0;
    	private int sodium = 0;
    	private int carbohydrate = 0;
    
    	public NutritionFacts() {
    	}
    
    	// Setters
    	public void setServingSize(int val) {
    		servingSize = val;
    	}
    
    	public void setServings(int val) {
    		servings = val;
    	}
    
    	public void setCalories(int val) {
    		calories = val;
    	}
    
    	public void setFat(int val) {
    		fat = val;
    	}
    
    	public void setSodium(int val) {
    		sodium = val;
    	}
    
    	public void setCarbohydrate(int val) {
    		carbohydrate = val;
    	}
    
    	public static void main(String[] args) {
    		NutritionFacts cocaCola = new NutritionFacts();
    		cocaCola.setServingSize(240);
    		cocaCola.setServings(8);
    		cocaCola.setCalories(100);
    		cocaCola.setSodium(35);
    		cocaCola.setCarbohydrate(27);
    	}
    }
    

    Builder模式

    不直接生成想要的对象,而是让调用者利用所有必要的参数调用构造器,得到一个builder对象,然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数,最后客户端调用无参的build方法来生成一个不可变的对象。

    public class NutritionFacts {
    	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 final int servingSize;
    		private final int servings;
    
    		// Optional parameters - initialized 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.servingSize = servingSize;
    			this.servings = servings;
    		}
    
    		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 NutritionFacts build() {
    			return new NutritionFacts(this);
    		}
    	}
    
    	private NutritionFacts(Builder builder) {
    		servingSize = builder.servingSize;
    		servings = builder.servings;
    		calories = builder.calories;
    		fat = builder.fat;
    		sodium = builder.sodium;
    		carbohydrate = builder.carbohydrate;
    	}
    
    	public static void main(String[] args) {
    		NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();
    	}
    }
    

    小结####

    与构造器相比,builder模式的优势在于,builder可以有多个可变的参数,构造器就像方法一样,只能有一个可变参数。总之,如果类的构造器或静态工厂中具有多个参数,设计这种类的时候,builder模式就是一种不错的选择。

    Num3:用私有构造器或者枚举类型强化Singleton属性

    Singleton简单的说就是仅仅被实例化一次的类。实现Singleton有三种方式。

    Field方式

    public class Elvis {
    	public static final Elvis INSTANCE = new Elvis();
    
    	private Elvis() {
    	}
    
    	public void leaveTheBuilding() {
    		System.out.println("Whoa baby, I'm outta here!");
    	}
    
    	// This code would normally appear outside the class!
    	public static void main(String[] args) {
    		Elvis elvis = Elvis.INSTANCE;
    		elvis.leaveTheBuilding();
    	}
    }
    

    Method方式

    public class Elvis {
    	private static final Elvis INSTANCE = new Elvis();
    
    	private Elvis() {
    	}
    
    	public static Elvis getInstance() {
    		return INSTANCE;
    	}
      
    	public void leaveTheBuilding() {
    		System.out.println("Whoa baby, I'm outta here!");
    	}
    
    	// This code would normally appear outside the class!
    	public static void main(String[] args) {
    		Elvis elvis = Elvis.getInstance();
    		elvis.leaveTheBuilding();
    	}
    }
    

    特别要说明下,如果要使得类支持可序列化,仅仅加上implements Serializable是不够的,需要在方法里加上这么一个方法。

    	private Object readResolve() {
    		// Return the one true Elvis and let the garbage collector
    		// take care of the Elvis impersonator.
    		return INSTANCE;
    	}
    

    枚举类方式

    public enum Elvis {
    	INSTANCE;
    
    	public void leaveTheBuilding() {
    		System.out.println("Whoa baby, I'm outta here!");
    	}
    
    	// This code would normally appear outside the class!
    	public static void main(String[] args) {
    		Elvis elvis = Elvis.INSTANCE;
    		elvis.leaveTheBuilding();
    	}
    }
    

    Num4:消除过期的对象引用

    所谓过期引用:是指永远也不会再被解除的引用。在支持垃圾回收的语言中,内存泄露是很隐蔽的,如果一个对象引用被这个对象无意识地保留起来,那么,垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的所有其他对象,从而对性能造成潜在的重大影响。

    那么该如何修复呢,很简单:一旦对象引用已经过期了,只需要清空这些引用即可。

    	public Object pop() {
    		if (size == 0)
    			throw new EmptyStackException();
          	Object result = elements[--size];
          	elements[size] = null;
    		return result;
    	}
    
    

    一般而言,只要类是自己管理内存,程序员就应该警惕内存泄露问题。

    内存泄露的另一个常见问题是缓存,所以一般可以弱引用weak reference代表缓存,当缓存过期后,它们会自动被删除,记住缓存项的生命周期是外部引用而不是值引用的。

    内存泄露的第三个常见来源是监听器和其他回调。如果你实现了一个API,客户端在这个API中注册回调,却没有显式地取消注册,那么除非采取某些动作,否则就会积聚,确保回调立即被当作垃圾回收的最佳方法是只保存它们的弱引用。

  • 相关阅读:
    我要翻译《Think Python》- 004 第二章 变量, 表达式和语句
    我要翻译《Think Python》-003 第一章 编程之道
    我要翻译《Think Python》-002 贡献列表 & 目录部分
    我要翻译《Think Python》
    ORA-12514 解决方法
    好玩的东西
    sublime HtmlPrettify
    [转]bing壁纸天天换 初识shell魅力
    nginx+lua+redis 处理APK包替换
    算法整理
  • 原文地址:https://www.cnblogs.com/cr330326/p/5607235.html
Copyright © 2011-2022 走看看