`

《effective java》之一:创建和销毁对象

    博客分类:
  • Java
阅读更多

第1条:考虑用静态工厂方法代替构造器:

 

public class Services {
	private Services() {
	} // Prevents instantiation (Item 4)

	// Maps service names to services
	private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
	public static final String DEFAULT_PROVIDER_NAME = "<def>";

	// Provider registration API
	public static void registerDefaultProvider(Provider p) {
		registerProvider(DEFAULT_PROVIDER_NAME, p);
	}

	public static void registerProvider(String name, Provider p) {
		providers.put(name, p);
	}

	// Service access API
	public static Service newInstance() {
		return newInstance(DEFAULT_PROVIDER_NAME);
	}

	public static Service newInstance(String name) {
		Provider p = providers.get(name);
		if (p == null)
			throw new IllegalArgumentException(
					"No provider registered with name: " + name);
		return p.newService();
	}
}

 

第2条:遇到多个构造器参数时要考虑用构建器builder:

 

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

 

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

 

从Java 1.5发行版开始,实现Singleton的最佳实践方法是,编写一个包含单个元素的枚举类型:

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

 

第4条:通过私有构造器强化不可实例化的能力:

 

// Noninstantiable utility class
public class UtilityClass {
	// Suppress default constructor for noninstantiability
	private UtilityClass() {
		throw new AssertionError();
	}
}

 

第5条:避免创建不必要的对象:

 

除了重用不可变对象外,也可以重用那些已知不会被修改的可变对象。

class Person {
	private final Date birthDate;

	public Person(Date birthDate) {
		// Defensive copy - see Item 39
		this.birthDate = new Date(birthDate.getTime());
	}

	// Other fields, methods

	/**
	 * The starting and ending dates of the baby boom.
	 */
	private static final Date BOOM_START;
	private static final Date BOOM_END;

	static {
		Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
		gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
		BOOM_START = gmtCal.getTime();
		gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
		BOOM_END = gmtCal.getTime();
	}

	public boolean isBabyBoomer() {
		return birthDate.compareTo(BOOM_START) >= 0
				&& birthDate.compareTo(BOOM_END) < 0;
	}
}

 

 第6条:消除过期的对象引用:

 

内存泄露的一个典型例子:

public class Stack {
	private Object[] elements;
	private int size = 0;
	private static final int DEFAULT_INITIAL_CAPACITY = 16;

	public Stack() {
		elements = new Object[DEFAULT_INITIAL_CAPACITY];
	}

	public void push(Object e) {
		ensureCapacity();
		elements[size++] = e;
	}

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

	/**
	 * Ensure space for at least one more element, roughly doubling the capacity
	 * each time the array needs to grow.
	 */
	private void ensureCapacity() {
		if (elements.length == size)
			elements = Arrays.copyOf(elements, 2 * size + 1);
	}
}

 从栈中弹出来的对象不会当做垃圾回收,因为栈内部维护着这些对象的过期引用(obsolete reference),所谓的过期引用,是指永远不会再被解除的引用。本例中,凡是elements数组的活动部分之外的任何引用都是过期的,活动部分是指elements中下标小于size的那些元素。

pop方法的修订版:

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

 一般而言,只要类是自己管理内存,程序员就应该警惕内存泄露问题,一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。

内存泄露的另一个来源是缓存。

内存泄露的第三个来源是监听器和其他回调。确保回调立即被当做垃圾回收的最佳方法是只保留它们的弱引用 weak reference,例如,只将它们保存成WeakHashMap中的key

 

第7条:避免使用终结方法finalizer:

 

finalizer通常是不可预测的,也是很危险的,一般情况下是不必要的。会导致不稳定,性能降低,不可移植。

 

 

本人博客已搬家,新地址为:http://yidao620c.github.io/

分享到:
评论

相关推荐

    Effective Java第三版1

    ### 第二章 创建和销毁对象 这一章深入探讨了对象的生命周期管理,包括: 1. **静态工厂方法**:相比构造器,静态工厂方法有优点如可以不返回新实例、允许返回同一实例(单例)、可以有更具选择性的访问控制,并且...

    《Effective Java》读书分享.pptx

    在 Java 中,创建和销毁对象是非常重要的。静态工厂方法可以代替构造器,提供了更多的灵活性和性能优势。静态工厂方法可以返回原类型的任何子类型,且可以将构建好的实例缓存起来,方便重复利用,不用每次调用都创建...

    Effective Java.zip

    1. **第2章 创建和销毁对象** - 单例模式:讲解了如何正确实现单例类,避免多线程环境下的并发问题。 - 构造函数:强调构造函数应简洁,避免在构造过程中执行复杂操作。 - 工厂方法:介绍工厂方法模式,作为创建...

    java7hashmap源码-Effective-Java-3th:Effective-Java-3th

    创建和销毁对象 考虑使用静态工厂方法代替构造方法 优点: 有名字 每次调用的时候,不一定要创建新的对象 可以返回一个类型的子类型 Collections就是这种用法 返回对象的类可以随调用的不同而变化(用输入的参数值...

    Effective Java 第三版

    书中的一些关键知识点可能包括:理解对象的创建和销毁、接口设计、类设计、方法设计、泛型的使用、异常处理、并发编程、Java集合框架的使用和扩展等等。在学习这些内容时,读者将被引导深入理解Java语言的细节,并...

    Effective.Java_Java8_并发_java_effectivejava_

    目录:一、创建和销毁对象 (1 ~ 7)二、对于所有对象都通用的方法 (8 ~ 12)三、类和接口 (13 ~ 22)四、泛型 (23 ~ 29)五、枚举和注解 (30 ~ 37)六、方法 (38 ~ 44)七、通用程序设计 (45 ~ 56)八、异常 ...

    java逻辑思维笔试题-effective-java-3rd-edition:有效的Java第3版注释

    创建和销毁对象 03 - 所有对象通用的方法 04 - 类和接口 05 - 泛型 06 - 枚举和注释 07 - Lambda 和流 08 - 方法 09 - 通用编程 10 - 例外 11 - 并发 12 - 序列化 第 2 章 - 创建和销毁对象 第 1 项 - 考虑静态工厂...

    java源码期编译器运行时-Effective-JAVA-Summary:JoshuaBloch的EffectiveJava2ndEditio

    创建和销毁对象 1.使用静态工厂方法而不是构造函数 好处 与构造函数不同,它们有名称 与构造函数不同,它们不需要在每次调用时都创建一个新对象 与构造函数不同,它们可以返回其返回类型的任何子类型的对象 它们减少...

    Effective-Java读书笔记(上)

    #### 第二章 创建/销毁对象 ##### 用静态工厂方法代替构造器 在面向对象编程中,对象的创建通常是通过构造器来完成的。然而,在某些情况下,使用静态工厂方法来创建对象可能会更加灵活和高效。 **静态工厂方法的...

    effective-swift:阅读Effective Java 3E,了解编程中的习惯用法和有效用法,并提出在Swift中使用它的方法。

    第2章对象的创建和销毁 项目编号 标题 副标题 经理 项目1 项目2 项目3 项目4 项目5 不要直接指定资源,请使用依赖对象注入 莉娜 项目6 避免不必要的对象创建 德玛 项目7 释放使用的对象参考 莉娜 项目8 避免使用...

    effecive java 中文版 第二版

    通过以上对“Effective Java 中文版 第二版”的核心知识点的总结,我们可以看到这本书覆盖了Java编程语言的各个方面,包括面向对象设计原则、类与接口的设计、对象的创建与销毁、枚举类型与注解、泛型与集合框架以及...

    java笔试题a说他不和x比-effective-java-in-a-nutshell:简而言之,有效的Java

    章:创建和销毁对象 第 1 条:考虑静态工厂方法而不是构造函数 由于以下原因,最好使用静态工厂而不是构造函数: 它们的名称可以帮助识别静态构造函数的操作 不需要返回新对象,您可以控制何时以及是否需要返回新...

    最新的java程序员不可不学的java基础教程

    2. **类与对象**:Java是一种面向对象的语言,理解类的定义、对象的创建与销毁、封装、继承、多态等概念至关重要。同时,深入探讨构造函数、访问修饰符、抽象类与接口的应用。 3. **异常处理**:Java中的try-catch-...

    java必备知识点大全.pdf

    final、finally、finalize三者区别:final用于声明常量,finally用在try-catch-finally语句中表示必须执行的代码块,finalize是Object类的一个方法,垃圾回收器在销毁对象之前会调用它。 Io流的层次结构:Java中Io...

    Java并发实践英文版(Java Concurrency in Practice)

    - **线程池**:通过管理一组预先创建好的线程来提高性能,避免频繁创建和销毁线程的开销。 - **不可变对象**:使用不可变对象可以避免并发修改问题,因为一旦创建后其状态就不能改变。 #### 七、本书内容概览 第一...

    Java实现多种单例模式

    这种模式在需要频繁创建和销毁对象的场景中尤其有用,因为它可以节省系统资源并确保对象间的协调一致。以下是Java实现的六种单例模式的详细解释: 1. 懒汉式(Lazy Initialization): 这种方式延迟了单例对象的...

    Effictive Java

    #### 二、创建与销毁对象 ##### Item1:考虑提供静态工厂方法而不是构造器 - **目的**:简化对象创建过程,提高代码的可读性和可维护性。 - **实现方式**: - 定义一个静态方法来创建对象,而非直接使用构造器。 -...

Global site tag (gtag.js) - Google Analytics