文档章节

《Effective java》学习笔记 1 之 对象创建和销毁

厚德
 厚德
发布于 2015/06/10 15:33
字数 1229
阅读 15
收藏 0

        最近看知乎上Android成长之路的帖子推荐了一本书《Effective java》于是下了个中文版的pdf开始学习,鉴于自己英文太差阅读英文版太吃力,所以下了中文版。

    1.使用静态工厂方法来代替构造器(此处静态工厂方法和设计模式的工厂方法不同)

        优点:

1 它有名称,可以更加确切的描述创建的对象。例如BigInteger(int,int,Random)可以使用 BigInteger.probablePrime(int,Random)代替 

2 不必每次都调用他们的时候都创建一个新的对象

3 可以返回原返回类型的任何子类型的对象

4 在创建参数化类型实例的时候,它们使代码变得更加简洁

缺点:

1 如果不含共有的或者受保护的构造器,就不能被子类化。

2 它们于其他的静态方法实际上没有任何区别。

2.遇到了多个构造器参数时要考虑使用构造器

    1 使用重叠构造器

缺点:当参数有许多的时候,客户端代码会很难写,并且难以阅读。

2 使用javaBeans的模式,通过setter方式来设置参数

缺点:构造过程中被分到几个调用中,在构造过程中javaBean可能处于不一致的状态。不安全

3 使用Builder模式

package com.effetive.creation;

import java.util.WeakHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;

/**
 * 营养成分
 * 
 * @author Administrator
 * 
 */
public class NutritionFast {
	// 必选参数
	private int servingSize;
	private int servings;
	// 可选参数
	private int calories;
	private int fat;
	private int sodium;
	private int catbohydrate;
		
	private NutritionFast(Builder builder) {
		servingSize = builder.servingSize;
		servings = builder.servings;
		calories = builder.calories;
		fat = builder.fat;
		sodium = builder.sodium;
		catbohydrate = builder.catbohydrate;
	}

	public static class Builder {
		// 必选参数
		private int servingSize;
		private int servings;
		// 可选参数
		private int calories;
		private int fat;
		private int sodium;
		private int catbohydrate;

		public Builder(int servingSize, int servings) {
			super();
			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 sodium(int val) {
			sodium = val;
			return this;
		}

		public Builder catbohydrate(int val) {
			catbohydrate = val;
			return this;
		}

		public NutritionFast build() {
			return new NutritionFast(this);
		}
	}

	public static void main(String[] args) {
		// 调用
		NutritionFast cocaCola = new NutritionFast.Builder(240, 8)
				.calories(100).sodium(35).build();

	}
}

如果构造器中或静态工厂中具有多个参数,可以选择Builder模式,如果参数比较少还是选择重叠的方式。

3.用私有的构造器或者枚举强化singleton属性(个人感觉使用枚举来做单例模式,我好像没见过)

        public class Elvis{
		private static final Elvis instance = new Elvis();
		private Elvis(){}
		public static Elvis getInstance(){
			return instance;
		} 
		public void leavTheBuilding(){}
	}
	
	public enum Elvis{
		INSTANCE;
		public void leavTheBuilding(){}
	}

4.避免创建不必要的对象

String s = new String("abcd");

String s = "abcd";

我们选择第二种方式,因为第一中方式会创建出2个对象。

Long sum =0l;

for(long i =0; i<Integer.MAX_VALUE;i++){

sum +=i;

}

如果我们把Long 改为long 可以少创建出2^31个Long对象。所以尽量使用基本数据类型。

5.消除过期的对象引用

//自己维护一个栈
	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(Object e){
			if(size==0){
				throw new EmptyStackException();
			}
			Object result = elements[--size];
			//elements[--size] = null;
			return result;
		}
		
		//如果容量不够进行扩充
		public void ensureCapacity(){
			if(elements.length == size){
				elements = Array.copy(elements,2*size+1);
			}
		}
	}

这段程序运行起来可能没有什么错误,但是确存在这严重的内存泄露,如果对Stack的进行压栈操作,然后再进行弹栈,但是弹栈的对象是不能被垃圾回收站回收,因为是个强引用(还在elements数组中)。如果这种过期的引用对象(obsolete reference)没有被回收,可能会出现OutOfMemory的情况.修改方式 :就是把弹栈的对象给制空。

引用过期对象容易出现位置:

1 自己管理的Stack 、存储池、数组 

解决方案:一旦容器元素变成非活动部分的一部分,我们就要手动清空这些容器元素

2 缓存 

一旦你把对象放在缓存中,它很容易被遗忘,从而使它在很长一段时间不使用的时候仍然保留在内存中。

解决方案:可以使用WeakHashMap来当做缓存容器;还可以使用使用Timer,ScheduledThreadPoolExecutor定时器来定时清理

3 内存泄漏还可能出现在监听器或其他回调中 ,可以使用WeakReference作为WeakhashMap的键

例如,在Android中有很多地方Context对象,我们很多时候会在Activity直接用this代表Context,如果这个Activity已经关闭就应该被垃圾回收器回收,但是我们的通过参数的来传递Activity对象,可能其他地方还引用着这个activity对象。我们解决方案可以用this.getApplicationContext()这样可以避免了Activity内存泄漏

我可以使用工具来查找内存泄漏比如Heap Profiler

© 著作权归作者所有

共有 人打赏支持
厚德
粉丝 2
博文 53
码字总数 33193
作品 0
武汉
JVM 运行时数据区简介及堆与栈的区别

理解JVM运行时的数据区是Java编程中的进阶部分。我们在开发中都遇到过一个很头疼的问题就是OutOfMemoryError(内存溢出错误),但是如果我们了解JVM的内部实现和其运行时的数据区的工作机制,...

大数据之路
2015/08/02
0
1
jvm内存模型-深入理解jvm

  最近学习了周志明老师的《深入理解Java虚拟机》,收获颇多,留下一些学习笔记,供以后复习用。   JVM定义了若干个程序执行期间使用的数据区域。这个区域里的一些数据在JVM启动的时候创...

Swen_9826
08/09
0
0
effective java之创建与销毁对象

最近朋友推荐了一本书《Effective Java》,觉得写得不错,写点总结笔记,以备后用。 一、创建对象 1、考虑静态工厂代替构造器 优点:(1)有明确名称。可以理解成,定义的静态方法可以给出明...

kyle1970
2012/10/31
0
0
第三章 spring-bean之DefaultSingletonBeanRegistry(3)

前言 SingletonBeanRegistry是一个非常重要的接口,用于注册,获得,管理singleton对象。 SingletonBeanRegistry目前唯一的实现是DefaultSingletonBeanRegistry,DefaultSingletonBeanRegis...

鸟菜啊
07/18
0
0
Java入门学习之java变量简析 java编程

在Java语言中,所有的变量在使用前必须声明。声明变量的基本格式如下: type identifier [ = value][, identifier [= value] ...] ; Java语言支持的变量类型有3种:1、类变量:独立于方法之外...

老男孩Linux培训
05/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

FFmpeg Maintainer赵军:FFmpeg关键组件与硬件加速

大家好!我是赵军,现就职于英特尔的DCG从事基于FFmpeg的硬件优化工作,两年多前加入FFmpeg社区,2018年4月成为FFmpeg的其中的一个FFmpeg Maintainer,主要负责FFmpeg的硬件优化工作。 概览:...

yizhichao
23分钟前
0
0
ehlib 修改 使行号字体颜色 与标题字体颜色 一致

对ehlib 显示效果不够满意,而做的调整 修改这个过程:procedure TCustomDBGridEh.DrawIndicatorCell(ACol, ARow: Longint; AreaCol, AreaRow: Longint; ARect: TRect; AState: TGri......

vga
49分钟前
1
0
Bash重定向详解

Bash重定向详解 Bash的重定向指的是将命令的输入和输出导向不同地方,而不是默认的标准输入、标准输出和标准错误。Bash的重定向实际上是对标准输入、标准输出和标准错误的重置,进而将所需输...

小陶小陶
今天
3
0
EventBus原理深度解析

一、问题描述 在工作中,经常会遇见使用异步的方式来发送事件,或者触发另外一个动作:经常用到的框架是MQ(分布式方式通知)。如果是同一个jvm里面通知的话,就可以使用EventBus。由于Event...

yangjianzhou
今天
29
0
OpenCV图像处理实例:libuv+cvui显示摄像头视频

#include <iostream>#include <opencv2/opencv.hpp>#define CVUI_IMPLEMENTATION#include <cvui.h>extern "C"{#include <uv.h>}using namespace std;#define WINDOW_NAM......

IOTService
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部