`
ray_yui
  • 浏览: 216776 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java高质量代码之 — 面向对象

    博客分类:
  • Java
阅读更多

前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间拜读了秦小波老师的《改善Java程序的151建议》,感觉廓然开朗,注意到了很多平时在编写代码中并不会注意的问题,甚至感觉自己对Java只是略懂皮毛,不足以登大雅之堂,特此与读者分享读书笔记,以下内容摘自《改善Java程序的151建议》一书和笔者的理解


Java高质量代码系列文章
      面向对象篇:http://ray-yui.iteye.com/blog/1926984
      数据类型篇:http://ray-yui.iteye.com/blog/1927251
          字符串篇:http://ray-yui.iteye.com/blog/1927647
      数组与集合(1):http://ray-yui.iteye.com/blog/1928170
      数组与集合(2):http://ray-yui.iteye.com/blog/1930155
      枚举与注解:http://ray-yui.iteye.com/blog/1931408
      泛型与发射:http://ray-yui.iteye.com/blog/1933127
                  异常:http://ray-yui.iteye.com/blog/1938946
                      杂:http://ray-yui.iteye.com/blog/1942591


1.在接口中不要存在实现代码
      接口中存在实现?接口中应该只能声明抽象方法,常量,继承其他接口,但抽象方法当中不能存在实现吧?请观看一下的一段代码

public interface TestInterface {

	public static final Test test = new Test() {
		public void doSomething() {
			System.out.println("这就是实现");
		}
	};

	void test();
}


      从以上代码中可以看到,在接口当中使用了匿名内部类的方式对接口当中的常量进行了实现,这种编码方式可以说是很好很强大,但由此带来的是什么?接口从此不再稳定,接口和类有了依赖,当Test类方法doSomething改变时,直接影响了接口,而接口应该是一种规范,是稳定不变的


2.静态变量一定要先声明后使用
      标题是什么意思?难道可以使用一个没有声明的静态变量吗?请看以下代码

public class Test {
	static {
		i = 100;
	}
	public static int i = 1;

	public static void main(String[] args) {
		System.out.println("此时 i 的输出为 1" + i);
	}
}


      从以上代码看到,i先被使用,然后再进行了初始化,那为什么会出现这样的情况?首先要明确,静态变量在类初始化首先被加载的,注意,此时只加载了 i 这个变量,但还没有对 i 进行赋值,然后JVM会根据类中的静态块来顺序执行,以上代码由于静态块static{}放置顺序在前面,所以首先被执行,然后再执行int i = 1的操作


3.不要复写静态方法和静态方法使用类名调用:
      在Java中,可以通过子类对父类的方法进行复写从而增强或减弱父类的行为,但复写是针对非静态方法的,我们都知道静态方法是针对类本身的,通过类名进行调用,当然也可以使用对象来调用,但这样Eclipse本身就会给你报个小警告,使用对象调用是不规范的,所以子类和父类应该尽量避免静态方法重名和静态方法使用类名调用


4.构造函数尽量简化
      我们都知道,在New出一个新对象时,对象会执行一个方法,此方法名为构造函数,而构造函数当中,应该尽量不出现业务代码,因为构造函数的职责就是为类的创建进行初始化的,例如对对象的属性值进行初始化,而业务代码应该封装在类的方法当中,让构造函数尽量简单


5.用构造代码块精炼代码
      现在我们有这样一个需求,在Test类初始化时需要记录日志,但Test类当中有多个构造函数,当然我们可以在每个构造函数当中编写日志,但使用构造代码块将更加的简洁完成以上需求,请看以下代码

public class Test {
	// 直接编写1对{}代表构造代码块
	{
		System.out.println("我是记录日志的构造代码快");
	}

	public Test() {
		System.out.println("执行无参构造");
	}

	public Test(String id) {
		System.out.println("执行有参构造");
	}
}


      以上代码中,构造代码块会增加到每个构造函数中的第一行的位置,这样就代表执行构造代码块再执行构造函数本身的内容


6.使用匿名类的构造函数
      在我们开发当中,若想快速实现一个接口,例如是Comparator(比较器),我们会使用匿名类的形式来进行实现,但有没有想过,匿名类的构造函数在何方?我们都知道构造函数是没有重写的,那我们在对自定义的接口使用匿名方式实现时,如何使用构造函数?请看以下代码

public class Test {
	private Comparator<Test> comparator = new Comparator<Test>() {
		{
			System.out.println("其实我可以代替匿名类的构造函数");
		}
		@Override
		public int compare(Test o1, Test o2) {
			return 0;
		}
	};
}


      使用构造代码块就可以实现对匿名类的构造函数.


7.让多重继承成为现实
      我们都知道Java当中是单继承的,但我们可以使用婉转的方式来实现多继承,这就需要使用到内部类

public abstract class Runable {

	private int speed = 10;

	void run() {
		System.out.println("running..." + speed);
	}
}


public abstract class Flyable {

	private int speed = 10;

	void fly() {
		System.out.println("flying..." + 10);
	}
}


//动物能飞,能跑
public class Animal {

	public void fly() {
		new Flyable() {
		}.fly();
	}

	public void run() {
		new Runable() {
		}.run();
	}
}


      当然我们可以在Animal中再创建一个内部类继承runable或flyable然后在run或fly中创建内部类来实现,这里只给出最方便快捷的实现


8.让工具类不可实例化
      工具类只是帮助我们完成某些特定操作,而且工具类所有方法都应该是static,而且不能实例化,当然很简单就可以完成,只需将构造函数私有化(private)即可,但Java强大的反射机制还是能让我们通过反射形式来实例化工具类,此时更应该在工具类私有的构造函数中加入抛出异常的代码,当初始化时即抛出异常


9.避免对象的浅拷贝
      何谓浅拷贝?有经典的案例,请看如下代码

public static void main(String[] args) {
		int[] numArray = new int[10];
		int[] numArray2 = null;
		// 此种就为浅拷贝,拷贝的是引用
		numArray2 = numArray;

		// 此种为深度拷贝,拷贝的是元素,不是引用
		for (int i = 0, size = numArray.length; i < size; i++) {
			numArray2[i] = numArray[i];
		}

	}


      而在Java中,只要实现了Cloneable接口的对象,都被视为具有拷贝能力,但需要注意,clone方法的拷贝为浅拷贝.


9.复写equlas时需要注意的事情:
      在复写equlas时需要注意,要考虑Null值得情况,推荐中equlas中使用getClass进行类型的判断,复写equlas时必须复写hasCode方法


10.不主动进行垃圾回收
      主动进行垃圾回收是一个非常危险的操作,因为System.gc()需要停止所有的响应来扫描垃圾,所有的请求会全部停止,等待垃圾回收器执行完毕,此时若然堆中存在大量对象时,那这个过程将会非常耗时



总结:
      笔者在本文章中只从《改善Java程序的151建议》中提取部分进行归纳性叙述,推荐各位读者购买这本书,该书不仅从事例中学习,而且涉及到原理,底层的实现,不仅告诉你应该怎么做,还告诉你为什么要这样做.
13
9
分享到:
评论
7 楼 yk.yk 2013-09-09  
看到第八条,我笑了,怎么一个贱字了得!!
6 楼 happy200318 2013-09-09  
mark 学习 学习
5 楼 ray_yui 2013-08-30  
unique.wu 写道
第八条,如果还在私有构造方法里,增加抛出异常的代码,那就太过度设计了。。
代码要这样写,会累死的。。
知道有这么一回事就可以了。

看看apache里大部分的工具类里,连默认的private的构造函数都没有加上。

浅克隆,深度克隆,得依赖于具体场景而言,个人认为克隆方法前加上注释,比较合理一点,并不是所有场景需要深度克隆,然而因为没有深度克隆而引起的数据被攥改的情况又很隐蔽,如果可以,有多种需求可以考虑提供一个浅克隆和一个深度克隆的方法,否则,根据场景的需求来克隆了。

非常感谢你的留言和意见,其实就克隆而言,浅克隆比深克隆就开销上看反而更好.但由于克隆的场景大多是数据库的数据,而我们又大多使用Hibernate,我曾经在使用Hibernate时报出Exception:Found shared references to a collection,这是因为两个对象引用了同一个集合,就是因为浅拷贝引起的,所以我觉得能注意能避免就好
4 楼 unique.wu 2013-08-30  
第八条,如果还在私有构造方法里,增加抛出异常的代码,那就太过度设计了。。
代码要这样写,会累死的。。
知道有这么一回事就可以了。

看看apache里大部分的工具类里,连默认的private的构造函数都没有加上。

浅克隆,深度克隆,得依赖于具体场景而言,个人认为克隆方法前加上注释,比较合理一点,并不是所有场景需要深度克隆,然而因为没有深度克隆而引起的数据被攥改的情况又很隐蔽,如果可以,有多种需求可以考虑提供一个浅克隆和一个深度克隆的方法,否则,根据场景的需求来克隆了。
3 楼 ray_yui 2013-08-23  
zoozooll 写道
個人覺得 ,用java來做這些微小的内存優化操作,太虛了.
創建對象時候不知道内存地址,也不知道内存存儲的方式,指針指向方式,更不知道什麽時候釋放.即使能夠做到,也做不了操作.
這種事情還是交給c和c++.java 語言從它出生開始,就是考慮如果方便開發者抛開這些瑣碎問題的,現在又來到這方面自尋煩惱,真是何苦阿

非常感谢你的留言,也非常有道理,虽然Java处于的层次确实限制了非常多的操作,但绝对不能说做不到就不尽量去优的方面靠呀,若然你需要一种高内存管理例如网游的服务器端,或者高性能系统,那c++等绝对是优的,但若然你选择java,却认为对底层的管理被封死就肆意挥霍的话,那绝对不是一种好的思想和方案
2 楼 zoozooll 2013-08-23  
個人覺得 ,用java來做這些微小的内存優化操作,太虛了.
創建對象時候不知道内存地址,也不知道内存存儲的方式,指針指向方式,更不知道什麽時候釋放.即使能夠做到,也做不了操作.
這種事情還是交給c和c++.java 語言從它出生開始,就是考慮如果方便開發者抛開這些瑣碎問題的,現在又來到這方面自尋煩惱,真是何苦阿
1 楼 85113618 2013-08-19  
谢谢 啊   学习了

相关推荐

    利用eclipse编写高质量的java代码

    利用eclipse编写高质量的java代码

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA学习视频之Java8高级编程(2)

    JAVA学习视频系列Java8编程入门-面向对象编程-高级编程之Java8高级编程(2) Java作为一种面向对象的编程语言,具有强大的跨平台性和丰富的开发工具和框架支持。在我们日常的软件开发过程中,高级编程技术在提升效率...

    JAVA学习视频之Java8高级编程(1)

    JAVA学习视频系列Java8编程入门-面向对象编程-高级编程之Java8高级编程(1) Java作为一种面向对象的编程语言,具有强大的跨平台性和丰富的开发工具和框架支持。在我们日常的软件开发过程中,高级编程技术在提升效率...

    JAVA学习视频之Java8高级编程(3)

    JAVA学习视频系列Java8编程入门-面向对象编程-高级编程之Java8高级编程(3) Java作为一种面向对象的编程语言,具有强大的跨平台性和丰富的开发工具和框架支持。在我们日常的软件开发过程中,高级编程技术在提升效率...

    java源码包---java 源码 大量 实例

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA上百实例源码以及开源项目

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java源码包2

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    java学习:03.硬链接和软连接.md

    同时,Java还提供了自动内存管理和异常处理机制,使开发人员能够更轻松地编写高质量的代码。 总之,Java是一种功能强大、易学易用、具有广泛应用和强大跨平台特性的编程语言。它的设计目标是提供一种高效的开发工具...

    天下陶网络商城Java源码,电商平台源代码 Java语言 先进技术 功能齐全 稳定、高效

    在开发过程中,我们注重代码质量和可维护性,采用面向对象编程思想和规范化的代码结构,使代码易于理解和修改。同时,我们采用单元测试和集成测试相结合的方法,确保代码的稳定性和可靠性。 使用天下陶网络商城Java...

    java源码包4

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    java源码包3

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    java学习:05.Java注解和反射.md

    同时,Java还提供了自动内存管理和异常处理机制,使开发人员能够更轻松地编写高质量的代码。 总之,Java是一种功能强大、易学易用、具有广泛应用和强大跨平台特性的编程语言。它的设计目标是提供一种高效的开发工具...

    一组高质量的代码示例,如java、spring、中间件、工具等(高分项目).zip

    它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以简化开发过程、提高代码的可维护性和可测试性。 2. Spring MVC框架:Spring MVC是基于Spring框架的...

    java学习:索引.md

    同时,Java还提供了自动内存管理和异常处理机制,使开发人员能够更轻松地编写高质量的代码。 总之,Java是一种功能强大、易学易用、具有广泛应用和强大跨平台特性的编程语言。它的设计目标是提供一种高效的开发工具...

    java之路,主要是java中的学习过程与基础项目.rar

    阅读Java编程指南:Java有详细的编程规范和最佳实践,阅读官方的Java编程指南可以帮助你编写高质量的代码。Oracle官方网站提供了Java编程指南的文档,你可以在那里找到有关Java编程的详细信息。 学习Java语法:Java...

    java学习:06.DockerFile.md

    同时,Java还提供了自动内存管理和异常处理机制,使开发人员能够更轻松地编写高质量的代码。 总之,Java是一种功能强大、易学易用、具有广泛应用和强大跨平台特性的编程语言。它的设计目标是提供一种高效的开发工具...

    java学习:01.JUC.md

    同时,Java还提供了自动内存管理和异常处理机制,使开发人员能够更轻松地编写高质量的代码。 总之,Java是一种功能强大、易学易用、具有广泛应用和强大跨平台特性的编程语言。它的设计目标是提供一种高效的开发工具...

    java笔记:02.windows常用快捷键.md

    java笔记:02.windows常用快捷键.md ...同时,Java还提供了自动内存管理和异常处理机制,使开发人员能够更轻松地编写高质量的代码。 总之,Java是一种功能强大、易学易用、具有广泛应用和强大跨平台特性

Global site tag (gtag.js) - Google Analytics