实践59
运用interfaces支持多重继承
实践60
没有任何办法能够阻止两个interfaces使用同名的常数和函数,为了避免可能的冲突,应当小心命名常数和函数。
例如例子中给出的 interface Golf和interface Bowling都有computeScore在实现时 为了加以区分 只能再额外创建一个MyGolf或MyBowling 之后让类实现MyGolf/MyBowling来区分开2者间的计算(在使用不同程序提供的接口时可能会出现这种情况)
实践61
如需提供部分实现(partial implementation),请使用抽象类(abstract classes),这些实现很可能对derived class是共通的
实践62
理解和区分interface,abstract class和concrete class之间的差异
interface内函数默认public,常量默认public static final
实践63
谨慎定义和实现不可变类(immutable classes)
如果你希望对象内容永远不被改动,请使用不可变对象(immutable object),这种对象自动拥有“多线程安全性”。
1 将class中所有的数据声明为private
2 只提供取值函数,而不允许存在setter
3 声明class为final (放置被子类化 而子类复写getter或setter)
4 从获取器返回reference给可变对象时,先克隆可变的对象
5 将传递给构造函数的可变对象reference先克隆一份
6 在构造函数中设定class内含的所有数据
实践64
如果不实施克隆动作,你的对象不变性(immutability)就得不到保证。这是因为他处可能保留了这个immutable object 内的某个object 的reference,并对其进行了修改,从而冲破了不变性的[界限]。
考虑一个情况 final class内部有一个非final的对象 而在其中改变了该非final对象的内部属性 由于保存的是reference的关系 final class的object必然也被改变了(就是这种情况)
所以欲传递或接收可变对象(mutable objects)的object references时,请使用clone()。为了保证immutable objects,你必须在传入和回传它们时对它们施行clone()。
注意:Vector实现的clone是浅克隆,如果需要,必须自己实现深克隆版本,例如
public Object clone(){
ShareVector v=(ShareVector)super.clone();
int size=size();
for(int i=0;i<size;i++){
User u=(User)(this.get(i));
v.setElementAt((User)(u.clone()),i);
}
return v;
}
还有一种修改方法,由类自己,克隆所含的对象,提供方法
private Vector cloneVector(Vector v){
int size=v.size();
Vector newVector=new Vector(size);
for(int i=0;i<size;i++){
newVector.add(((User)v.get(i)).clone());
}
return newVector;
}
实现一个immutable class不可变类时,遵循下列规则
1 声明这个class为final
2 声明所有数据为private
3 只提供取值函数getter,不提供设值函数setter
4 在构造函数中设置所有instance数据
5 如果函数返回reference to mutable objects,请克隆那些mutable objects
6 如果函数接收reference to mutable objects,请克隆那些mutable objects
7 如果缺省之浅层克隆不能符合immutable object的正常幸会,请实现出深层克隆。
实践65
3种可以用来定义immutable classes的技术:
1 immutable interface 不可变接口
2 公共接口或基类 common interface or base class
3 immutable delegation class 不可变的委托类
使用不可变接口:
interface ImmutableCircle{
public double radius();
}
class MutableCircle implements ImmutableCircle{
private double radius;
public MutableCircle(double r){
radius=r;
}
public void setRadius(double r){
radius=r;
}
public void double radius(){
return radius;
}
}
public class Test{
public ImmutableCircle createWheel(double r){
return new MutableCircle(r);
}
public static void main(String args[]){
Test t=new Test();
ImmutableCircle iWheel=t.createWheel(5.0);
iWheel.setRadius(7.4); //Error
}
}
由于iWheel是ImmutableCircle类型 只暴露了radius方法,因此自然不能调用setRadius
但是要注意的是,当使用
((MutableCircle)iWheel).setRadius(7.4);
转型后 应当Immutable的Circle被改变了。
使用公共接口或公共基类:
1 一个公共基类/接口,其内声明一些可被其derived classes共享的immutable函数
2 一个derived class,提供mutable函数实现代码
3 另一个derived class,提供immutable函数实现代码
interface PinNumbers{
public String accountOwner();
public int checkingPin();
public int savingPin();
}
class MutablePinNumbers implements PinNumbers{
private String acctOwner;
private int checkingAcctPin;
private int savingAccPin;
MutablePinNumbers(String owner,int cPin,int sPin){
acctOwner=owner;
checkingAcctPin=cPin;
savingAccPin=sPin;
}
//下面提供各自的getter和setter方法 总共6个
}
final class ImmutablePinNumbers implements PinNumbers{
private String acctOwner;
private int checkingAcctPin;
private int savingAccPin;
ImmutablePinNumbers(String owner,int cPin,int sPin){
acctOwner=owner;
checkingAcctPin=cPin;
savingAccPin=sPin;
}
//下面只提供3个getter方法
}
上述方式的实现可以确保不可变性,不会被简单的转型打破
不可变的委托类:
使用immutable delegation class,其中只包含immutable methods,并将外界对他们的调用任务委托给class内含的mutable object
class MutableCircle{
private double radius;
public MutableCircle(double r){
radius=r;
}
public void setRadius(double r){
radius=r;
}
public double radius(){
return radius;
}
}
final class ImmutableCircle{
private MutableCircle mCircle;
public ImmutableCircle(double r){
mCircle=new MutableCircle(r);
}
pbulic double radius(){
return mCircle.radius();
}
}
这样外界只能调用radius方法 其实是通过内部的可变对象调用
但是这种做法让你需要在实现委托模型和维护上花更大的力气,并且每次调用委托函数,都会付出性能上的代价
三者直接的优劣区别:
使用不可变接口:
优点:简单易行,无需付出性能上的代价
缺点:有破绽,通过转型可以破坏
使用公共接口或基类
优点:没有破绽,清晰地将mutable object和immutable objects分离
缺点:需要实现更多的classes,完成更深的classes继承关系
使用不可变的委托类
优点:没有破绽,当无法修改既有mutable object源代码时,此法可用
缺点:需要付出性能上的代价
实践66
当你实现一个clone(),总是应该调用super.clone()以确保产生正确的对象。
当打算实现深层克隆的时候,这条规则也同样适用。
class House implements Cloneable{
//...
public Object clone(){
try{
return super.clone();
}catch(CloneNotSupportedException e){
throw new InternalError();
}
}
}
实践67
不要把希望寄托于finalize()被调用。应当实现自己的non-memory资源清理机制,然后结合class的finalize()一道使用。确信需要如此清理的class必然包含一个public函数,专门负责释放资源,这个函数应当被class的finalize()调用,以确保当JVM调用finalize()时能够释放non-memory资源。如果finalize()未被调用,用户可以直接调用这个public函数。
class Communication{
private ServerSocket ss;
private FileInputStream fileIn;
//...
public synchronized void cleanup() throws IOException{ //确保多线程不会针对相同对象进入该函数
is(ss!=null){ //检查是否为null,在close后置为null,保证不会重复调用close
ss.close();
ss=null;
}
if(fileIn!=null){
fileIn.close();
fileIn=null;
}
}
}
protected void finalized() throws Throwable{
try{
cleanup();
}finally{
super.finalize(); //所有的finlize都应当调用super.finalize()
}
}
实践68
如果一个non-final函数被某个derived class覆盖,在构造函数中调用这个函数可能会导致不可预期的结果。
看一个例子:
class Base{
private int val;
Base{
val=lookup();
}
public int lookup(){
return 5;
}
public int value(){
return val;
}
}
class Derived extends Base{
private int num=10;
public int lookup(){
return num;
}
}
class Test{
public static void main(String args[]){
Derived d=new Derived();
System.out.println(d.value());
}
}
这里打印的结果是0!
这与预期的结果10不符,原因在于lookup函数是在Derived对象建构期间由Base构造函数调用的,当进入Derived的lookup()时,其instance变量初始化行为还未被进行,因此使用了缺省值0。
分享到:
相关推荐
Addison.Wesley.Java.Concurrency.in.Practice.May.2006.chm Agile Java 测试驱动开发的编程技术.pdf Java 8 默认方法和多继承.docx Java NIO通信框架在电信领域的实践.docx java.png javaconcurrencyinpractice.pdf...
《Java并发编程实践学习笔记》 在Java编程领域,并发编程是不可或缺的一部分,尤其是在多核处理器和高并发应用中。本笔记将深入探讨《Java Concurrency In Practice》这本书中的核心概念,结合Guava库的实际使用...
Addison.Wesley.Java.Concurrency.in.Practice.May.2006.chm Agile Java 测试驱动开发的编程技术.pdf Java 8 默认方法和多继承.docx Java NIO通信框架在电信领域的实践.docx java.png javaconcurrencyinpractice.pdf...
java concurrent源码 Java7 核心类库源码解析 请直接查看.java : 通过JavaDoc+Test书写 ,方便链接到源码 Tracker 20181014 Java11正式发布并作为新的长期支持版本, 未来的应用会逐步迁移到Java11. 因此Java8以前的...
贪吃蛇java程序源码 practice2020 这里存放了自己练习着玩的Python程序 2020-2-1 Saturday 2020年一月底,趁着春节假期,带着Nasa玩了一把turtle画图模块,儿子看到自己敲出的代码变成图案,连呼“好神奇哟!” 春节...
初级java笔试题谷歌面试大学 我最初将其创建为一个简短的学习主题待办事项列表,但它发展到您今天看到的大列表。 在 Google 工作是最初的动力,因此得名。 ,但是 repo 名称仍然存在,现在更改它会弄乱很多人。 此处...
这份"JavaPracticeNotes"集合了关于Java的精选笔记,旨在帮助学习者深入理解和掌握Java的核心概念及实践技巧。 1. **基础语法** - 类与对象:Java是面向对象的语言,一切皆为对象。类是对象的模板,对象则是类的...
《程序设计实践》是计算机科学领域的一本经典著作,由著名的计算机科学家Brian W. Kernighan和Rob Pike共同编写。这本书旨在提供一个全面而深入的视角,探讨编程实践中遇到的各种问题和解决方案,无论你是初学者还是...
在“Practice-Uploads:我的日常编码实践”这个项目中,我们可以看到一个新手程序员通过每日上传代码进行自我学习和提升的过程。这个存储库包含了不同编程语言的实践代码,包括Python、Java、C++以及Jupyter Notebook...
书籍如《Effective Java》、《Java Concurrency in Practice》和《Head First Java》等,都是学习Java高级编程的经典之作。在线资源如Oracle的Java Tutorials和Stack Overflow上的问答,为解决实际问题提供了大量...
"Java-Programming:Java资料库,用于大学作业,问题集和笔记"是一个专门针对Java学习者提供的资源集合,它包含了丰富的学习材料,旨在帮助学生更好地理解和掌握Java编程。 该资料库的核心内容可能包括以下几个方面...
这个项目可能包含了源代码、教程、笔记和其他学习材料,为初学者和有经验的Java开发者提供了实践平台。下面将详细讨论Java编程语言的关键知识点。 1. **基础语法**:Java的基础始于变量、数据类型、运算符和控制...
- **书籍**:《Effective Java》、《Java Concurrency in Practice》、《Clean Code: A Handbook of Agile Software Craftsmanship》等经典书籍深入讲解Java编程技巧和最佳实践。 - **社区与论坛**:Stack Overflow...
总的来说,"summer-practice-2015"这个压缩包很可能包含了参与者的代码示例、学习笔记、项目文档等,记录了他们在那个夏天对Java编程的探索与成长。通过回顾这些资料,无论是初学者还是有经验的开发者,都能从中汲取...
《CMake实践:尽量使用外部构建与二进制文件存储目录切换》 CMake是一种跨平台的构建系统,它以CMakeLists.txt文件作为配置文件,简化了构建和编译过程,尤其适合管理大型项目。CMake的特点包括开源、跨平台以及...