编写高质量代码:改善Java程序的151个建议 --[36~51]

工具类不可实例化

工具类的方法和属性都是静态的,不需要生成实例即可访 问,而且JDK也做了很好的处理,由于不希望被初始化,于是就设置了构造函数private的访问权限,表示出了类本身之外,谁都不能产生一个实例:

class UtilsClazz{
public UtilsClazz(){
throw new Error("Don't instantiate "+getClass());
}
}
避免对象的浅拷贝

super.clone()的拷贝规则:

  1. 基本类型:如果变量是基本类型,则拷贝其值。比如int、float等
  2. 对 象:如果变量是一个实例对象,则拷贝其地址引用,也就是说此时拷贝出的对象与原有对象共享该实例变量,不受访问权限的控制,这在Java中是很疯狂的,因 为它突破了访问权限的定义:一个private修饰的变量,竟然可以被两个不同的实例对象访问,这让java的访问权限体系情何以堪。
  3. String字符串:这个比较特殊,拷贝的也是一个地址,是个引用,但是在修改时,它会从字符串池(String pool)中重新生成新的字符串,原有的字符串对象保持不变,在此处我们可以认为String是一个基本类型。
使用序列化对象的拷贝

要求要拷贝的对象必须实现了Serializable接口。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable; public final class CloneUtils {
private CloneUtils() {
throw new Error(CloneUtils.class + " cannot instance ");
} // 拷贝一个对象
public static <T extends Serializable> T clone(T obj) {
// 拷贝产生的对象
T cloneObj = null;
try {
// 读取对象字节数据
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(cloneObj);
oos.close();
// 分配内存空间,写入原始对象,生成新对象
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
// 返回新对象, 并做类型转换
cloneObj = (T) ois.readObject();
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return cloneObj; } }

通过CloneUtils工具进行对象的深拷贝了,用词方法进行对象拷贝时需要注意两点:

对象的内部属性都是可序列化的:如果有内部属性不可序列化,则会抛出序列化异常,这会让调试者很纳闷,生成一个对象怎么回出现序列化异常呢?从这一点考虑,也需要把CloneUtils工具的异常进行细化处理。

注 意方法和属性的特殊修饰符:比如final,static变量的序列化问题会被引入对象的拷贝中,这点需要特别注意,同时 transient变量(瞬态变量,不进行序列化的变量)也会影响到拷贝的效果。当然,采用序列化拷贝时还有一个更简单的方法,即使用Apache下的 commons工具包中SerializationUtils类,直接使用更加简洁.

package org.apache.commons.lang3;

 import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map; public class SerializationUtils
{
public SerializationUtils() {} //克隆一个序列化对象
public static <T extends Serializable> T clone(T object)
{ }
//执行串行往返也就是执行序列化或者反序列化
public static <T extends Serializable> T roundtrip(T msg)
{
return (Serializable)deserialize(serialize(msg));
}
//讲一个对象序列化并且输出到输出流中
public static void serialize(Serializable obj, OutputStream outputStream)
{
Validate.isTrue(outputStream != null, "The OutputStream must not be null", new Object[0]);
try { ObjectOutputStream out = new ObjectOutputStream(outputStream);Throwable localThrowable2 = null;
try { out.writeObject(obj);
}
catch (Throwable localThrowable1)
{
localThrowable2 = localThrowable1;throw localThrowable1;
} finally {
if (out != null) if (localThrowable2 != null) try { out.close(); } catch (Throwable x2) { localThrowable2.addSuppressed(x2); } else out.close();
} } catch (IOException ex) { throw new SerializationException(ex);
}
}
//将一个对象序列化并返回字节数组
public static byte[] serialize(Serializable obj)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
serialize(obj, baos);
return baos.toByteArray();
}
//讲一个输入流反序列化成一个对象
public static <T> T deserialize(InputStream inputStream)
{
}
//将一个字节数组反序列化成一个对象
public static <T> T deserialize(byte[] objectData)
{
Validate.isTrue(objectData != null, "The byte[] must not be null", new Object[0]);
return deserialize(new ByteArrayInputStream(objectData));
}
static class ClassLoaderAwareObjectInputStream
extends ObjectInputStream
{
private static final Map<String, Class<?>> primitiveTypes = new HashMap();
private final ClassLoader classLoader; static {
primitiveTypes.put("byte", Byte.TYPE);
primitiveTypes.put("short", Short.TYPE);
primitiveTypes.put("int", Integer.TYPE);
primitiveTypes.put("long", Long.TYPE);
primitiveTypes.put("float", Float.TYPE);
primitiveTypes.put("double", Double.TYPE);
primitiveTypes.put("boolean", Boolean.TYPE);
primitiveTypes.put("char", Character.TYPE);
primitiveTypes.put("void", Void.TYPE);
} ClassLoaderAwareObjectInputStream(InputStream in, ClassLoader classLoader)
throws IOException
{
super();
this.classLoader = classLoader;
} protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException
{
String name = desc.getName();
try {
return Class.forName(name, false, this.classLoader);
} catch (ClassNotFoundException ex) {
try {
return Class.forName(name, false, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException cnfe) {
Class<?> cls = (Class)primitiveTypes.get(name);
if (cls != null) {
return cls;
}
throw cnfe;
}
}
}
}
}
覆写equals方法必须覆写hashCode方法
class Person{

   @Override
public int hashCode() {
return new HashCodeBuilder().append(name).toHashCode();
} }

其中HashCodeBuilder是org.apache.commons.lang.builder包下的一个哈希码生成工具;

org.apache.commons.lang.builder包下相关资料参考学习:

http://www.blogjava.net/19851985lili/articles/95448.html

推荐覆写toString方法(ToStringBuilder或者自己重写toString())
使用package-info类为包服务
  1. 声明友好类和包内访问常量:这个比较简单,而且很实用,比如一个包中有很多内部访问的类或常量,就可以统一放到package-info类中,这样很方便,便于集中管理,可以减少友好类到处游走的情况;
class PkgClazz {
public void test() {
}
} class PkgConstant {
static final String PACKAGE_CONST = "ABC";
}
  1. 为在包上提供注解提供便利:比如我们要写一个注解(Annotation),查看一下包下的对象,只要把注解标注到package-info文件中即可,而且在很多开源项目中也采用了此方法,比如struts2的@namespace、hibernate的@FilterDef等。
  2. 提供包的整体注释说明:如果是分包开发,也就是说一个包实现了一个业务逻辑或功能点或模块或组件,则该包需要一个很好的说明文档,说明这个包是做什么用的,版本变迁历史,与其他包的逻辑关系等,package-info文件的作用在此就发挥出来了,这些都可以直接定义到此文件中,通过javadoc生成文档时,会吧这些说明作为包文档的首页,让读者更容易对该包有一个整体的认识。当然在这点上它与package.html的作用是相同的,不过package-info可以在代码中维护文档的完整性,并且可以实现代码与文档的同步更新。
不要主动进行垃圾回收

编写高质量代码:改善Java程序的151个建议 --[36~51]的更多相关文章

  1. 博友的 编写高质量代码 改善java程序的151个建议

    编写高质量代码 改善java程序的151个建议 http://www.cnblogs.com/selene/category/876189.html

  2. 编写高质量代码改善java程序的151个建议——导航开篇

    2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,慘不忍睹是吧.确实 ...

  3. 编写高质量代码改善java程序的151个建议——[1-3]基础?亦是基础

    原创地址:   http://www.cnblogs.com/Alandre/  (泥沙砖瓦浆木匠),需要转载的,保留下! Thanks The reasonable man adapts himse ...

  4. 编写高质量代码:改善Java程序的151个建议 --[117~128]

    编写高质量代码:改善Java程序的151个建议 --[117~128] Thread 不推荐覆写start方法 先看下Thread源码: public synchronized void start( ...

  5. 编写高质量代码:改善Java程序的151个建议 --[106~117]

    编写高质量代码:改善Java程序的151个建议 --[106~117] 动态代理可以使代理模式更加灵活 interface Subject { // 定义一个方法 public void reques ...

  6. 编写高质量代码:改善Java程序的151个建议 --[78~92]

    编写高质量代码:改善Java程序的151个建议 --[78~92] HashMap中的hashCode应避免冲突 多线程使用Vector或HashTable Vector是ArrayList的多线程版 ...

  7. 编写高质量代码:改善Java程序的151个建议 --[65~78]

    编写高质量代码:改善Java程序的151个建议 --[65~78] 原始类型数组不能作为asList的输入参数,否则会引起程序逻辑混乱. public class Client65 { public ...

  8. 编写高质量代码:改善Java程序的151个建议 --[52~64]

    编写高质量代码:改善Java程序的151个建议 --[52~64] 推荐使用String直接量赋值 Java为了避免在一个系统中大量产生String对象(为什么会大量产生,因为String字符串是程序 ...

  9. Github即将破百万的PDF:编写高质量代码改善JAVA程序的151个建议

    在通往"Java技术殿堂"的路上,本书将为你指点迷津!内容全部由Java编码的最佳 实践组成,从语法.程序设计和架构.工具和框架.编码风格和编程思想等五大方面,对 Java程序员遇 ...

随机推荐

  1. Jquery ajax传递xml方式在ie8下兼容问题

    主要问题就是ie8把xml格式在打开的时候转换成了string,我们只用把其转换回xml就可以了. $.ajax({ type:’GET’, url:’list.php?pagenow=’+count ...

  2. Failed to execute goal org.apache.maven.plugins:maven-clean-plugin:2.5:clean (default-

    Maven项目报错:Failed to execute goal org.apache.maven.plugins:maven-clean-plugin:2.5:clean (default-clea ...

  3. Artifact project04:war :Error during artifact deployment. See server log for details

    困扰了我好长时间,我的错误是 先 Run clean  再package就成功了.

  4. vs code軟件操作

    https://www.imooc.com/article/39349 https://www.html.cn/archives/8144

  5. freemarker -include

    在ftl中使用<#include >时 ,页面被强制显示 需要在struts.xml增加跳转type ,或则可以加同一<result-types></result-typ ...

  6. JAVA web 使用有盟推送总结

    仔细阅读文档,下边的都是废话. 为了省事,iOS和Android 提供了所有了参数,需要那个了修改传参. //ios actionURL为自定义参数 $.ajax({ type : "POS ...

  7. devops工具

    工具类型及对应的不完全列举整理如下: 代码管理(SCM):GitHub.GitLab.BitBucket.SubVersion 构建工具:Ant.Gradle.maven 自动部署:Capistran ...

  8. Git——快速安装Git及初始化配置【二】

    文档 https://git-scm.com/book/zh/v2 下载 mac https://git-scm.com/download/mac Linux https://git-scm.com/ ...

  9. SPOJ705-New Distinct Substrings-后缀数组

    计算所都不相同子串的个数,做法是所有子串的个数减去sigma(height[]).其中height数组的和便是所有相同子串的个数. 注意 N×(N+1)/2会爆int!但是最终答案在int内.所以使用 ...

  10. IDEA 根据 Mysql 自动生成

    1 找到 没有的,file--project structure--modules--+--JPA 2  找到如下 添加Mysql连接,记得 Text Connecting一下看看 然后刷新,就可以出 ...