Effective java笔记3--类和接口2
三、接口优于抽象类
java提供两种机制,可以用来定义一个允许多个实现的类型:接口和抽象类。由于java只允许单继承,所以,抽象类作为类型定义受到了极大的限制。
已有的类可以很容易被更新,以实现新的接口。你所需要做的是:增加要求的方法,如果这些方法原先还不存在的话;然后在类的声明上增加一个implements子句。
接口是定义mixin(混合类型)的理想选择。一个mixin是指这样的类型:一个类除了实现它的”基本类型(primary type)"之外,还可以实现这个mixin类型,以表明它提供了某些可供选择的行为。
例如,Comparable是一个mixin接口,它允许一个类表明它的实例可以与其他的可相互比较的对象进行排序操作,这样的接口之所以被称为mixin,是因为它允许可选的功能可被混合到一个类型的基本功能中。抽象类不能被用于定义mixin,同理因为单继承原因。
接口使得我们可以构造出非层次结构的类型框架。类型层次对于组织某些事物是非常合适的,但是其他有些事物并不能被整齐地组织成一个严格的层次结构。
例如,singer(歌唱家),另一个接口代表一个songwriter(作曲家):
public interface Singer{
AudioClip Sing(Song s);
} public interface Songwriter{
Song compose(boolean hit);
}
接口使得安全性地增强一个类的功能成为可能,做法通过介绍的包装类(WrapperClass)模式。如果你用抽象类来定义类型,那么这样就使得程序员除了使用继承的手段来增加功能之外,没有别的选择途径。这样得到的类与包装类相比,功能更差,也更加脆弱。
可以把接口和抽象类的优点结合起来,对于你期望导出的每一个重要接口,都提供一个抽象的骨架实现(skeletal implementation)类。在这里接口的作用任然是定义类型,但是骨架实现类负责所有与接口实现相关的工作。骨架实现被称为AbstractInterface,这里的interface是所实现的接口的名字。
例如,Collections Framework为每个重要集合接口都提供了一个骨架实现,包括AbstractCollection为Collection接口、AbstractSet(为set接口)、AbstractList(为list接口)和AbstractMap(为Map接口).
如果设计合理的话,利用骨架实现,程序员可以很容易的提供他们自己的接口实现。例如,下面是一个静态工厂方法,它包含一个完整的、功能全面的List实现:
//List adapter for int array
static List intArrayAsList(final int[] a){
if(a==null)
throw new NullPointerException(); return new AbstractList(){
public Object get(int i){
return new Integer(a[i]);
} public int size(){
return a.length;
} public Object set(int i,Object o){
int oldVal = a[i];
a[i] = ((Integer)o).intValue();
return new Integer(oldVal);
}
}
}
这个例子是一个Adapter,它使得一个int数组可以被看做一个Integer实例列表。由于int值和Integer实例之间来回转换开销,它的性能不会非常好。注意,这个例子只提供了一个静态工厂,并且这个类是一个可被访问的匿名类(anonymous class),它被隐藏在静态工厂的内部。
骨架实现的优美之处在于,它们为抽象类提供了实现上的帮助,但又没有强加“抽象类被用作类型定义时候”所特有的严格限制。对于一个接口的大多数实现来讲,扩展骨架实现是一个很显然的选择,但也确实只是一个选择而已。如果一个预先已经定义好的类无法扩展骨架实现类,那么,这个类总是可以手工实现这个接口。尽管如此,骨架实现类仍然能够有助于接口的实现。实现了这个接口的类可以把对于接口的方法的调用,转发到一个内部私有的实例上,而这个内部私有类扩展了骨架实现类。这项技术被称为模拟多重继承(simulated multiple inheritance),这项技术具有多重继承的绝大多数优点,并且避免了相应的缺陷。
嵌套类--优先考虑静态成员类
嵌套类(nested class)是指被定义在另一个类的内部的类,嵌套类存在的目的应该只是为它的外围类提供服务。如果一个嵌套类将来可能会用于其他的某个环境中,那么它应该是顶层类(top-level class).
嵌套类有四种:
- 静态成员类(static member class);
- 非静态成员类(nonstatic member class);
- 匿名类(anonymous class);
- 局部类(local class);
Member Types(成员类型)即作为外部类的一个成员存在,与外部类的属性、方法并列同级的类型。成员内部类中不能定义静态变量,但可以访问外部类的所有成员.
除了第一种,其他三种都被称为内部类(inner class),那什么时候使用哪种嵌套类呢?为什么这样做呢?
静态成员类是一种最简单的嵌套类。最好把它看做是一个普通的类,只是碰巧被声明在另一个类的内部而已。它可以访问外围类的所有成员,包括那些声明为私有的成员。静态成员类是外围类的一个静态成员,与其他的静态成员一样,也遵守同样的可访问性规则。如果它被声明为私有的,那么它只能在外围类的内部才可以被访问等等。
静态成员类的一个通常用法是作为公有的辅助类,仅与它的外部类一起使用时才有意义。
非静态内部类nested inner class:
内部类隐含有一个外部类的指针this,因此,它可以访问外部类的一切资源(当然包括private)
外部类访问内部类的成员,先要取得内部类的对象,并且取决于内部类成员的封装等级。
非静态内部类不能包含任何static成员.
匿名类的适用性有一些限制。
- 因为它们同时被声明和实例化,所以匿名类只能被用在代码中它将被实例化的那个点上。
- 因为匿名类没有名字,所以在它们被实例化之后,就不能够再对它们进行引用,如果不是这种情况就不能使用匿名类。
- 因为匿名类出现在表达式的中间,所以它们应该非常简短,可能是20行或者更少,太长的匿名类会影响程序的可读性。
匿名类常用用法:
A、匿名类的一个通常用法是创建一个函数对象(function object),比如Comparator实例。排序:
//Typical use of an anonymous class
Arrays.sort(args,new Comparator(){
public int compare(Object o1,Object o2){
return ((String)o1.length()-((String)o2).length();
}
});
B、匿名类的另一个常用的用法是创建一个过程对象(process object),比如Thread、Runnable或者TimerTask实例。
C、还有一个用法是在一个静态工厂方法的内部(参考IntArrayAsList方法)。
D、在复杂的类型安全枚举类型(它要求为每个实例提供单独的子类)中,用于公有的静态final域的初始化器中。
局部类是四种嵌套类中最少使用的类。在任何“可以声明局部变量”的地方,都可以声明局部类,并且局部类也遵守同样的作用域规则。即在方法中定义的内部类,与局部变量类似,在局部内部类前不加修饰符public或private,其范围为定义它的代码块。
注意:局部内部类中不可定义静态变量,可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的。
public class Outer {
private int s = 100;
private int out_i = 1;
public void f(final int k){
final int s = 200;
int i = 1;
final int j = 10;
class Inner{ //定义在方法内部
int s = 300;//可以定义与外部类同名的变量
//static int m = 20;//不可以定义静态变量
Inner(int k){
inner_f(k);
}
int inner_i = 100;
void inner_f(int k){
System.out.println(out_i);//如果内部类没有与外部类同名的变量,在内部类中可以直接访问外部类的实例变量
System.out.println(k);//*****可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的*****
//System.out.println(i);
System.out.println(s);//如果内部类中有与外部类同名的变量,直接用变量名访问的是内部类的变量
System.out.println(this.s);//用"this.变量名" 访问的也是内部类变量
System.out.println(Outer.this.s);//用外部"外部类类名.this.变量名" 访问的是外部类变量
}
}
new Inner(k);
} public static void main(String[] args) {
//访问局部内部类必须先有外部类对象
Outer out = new Outer();
out.f(3);
}
}
简而言之,共有四种不同的嵌套类,每一种都有自己的用途。
私有成员变量可以被子类继承吗
今天看spring源码,不经意间发现了一问题:在一个抽象类中定义了一个私有成员变量。
仔细想想:抽象类不能被实例化的,只能被子类继承。但是自从学java的继承只有,我们就知道,子类不能继承父类的私有成员变量或方法的。
问题:在该抽象方法中定义这个私有变量有什么用呢?或者说这个私有成员变量再什么地方用得到呢?
所以自己做了一个测试如下:
public abstract class Fatherclass {
private int privatenumber; public int getPrivatenumber() {
return privatenumber;
}
public void setPrivatenumber(int privatenumber) {
this.privatenumber = privatenumber;
}
} public class Childclass extends Fatherclass{ public static void main(String[] args) {
Childclass childclass=new Childclass();
Childclass1 childclass1=new Childclass1();
childclass.setPrivatenumber(125);
System.out.println(childclass.getPrivatenumber());
System.out.println(childclass1.getPrivatenumber());
}
} public class Childclass1 extends Fatherclass { }
运行结果如下:
125
0
通过测试,我们发现子类确实继承了父类的私有属性(也可以说是子类拥有一个属性,继承自父类,但是该属性的访问权限暂时不确定),但是我们无法通过子类直接访问该(继承自父类私有属性)的属性。我暂且该这种属性的访问权限起名为fatherprivate(意为继承自父类私有属性)
转自:https://www.cnblogs.com/yidaijiankuanzhongbuhui/p/8417051.html
Effective java笔记3--类和接口2的更多相关文章
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- Java笔记---枚举类和注解
Java笔记---枚举类和注解 一.枚举类 自定义枚举类 方式一:JDK5.0之前自定义枚举类 class Seasons { //1. 声明Seasons对象的属性 private final St ...
- Effective java笔记(三),类与接口
类与接口是Java语言的核心,设计出更加有用.健壮和灵活的类与接口很重要. 13.使类和成员的可访问性最小化 设计良好的模块会隐藏起所有的实现细节,仅使用API与其他模块进行通信.这个概念称为信息隐藏 ...
- Effective java笔记3--类和接口1
一.使类和成员的可访问能力最小化 要想区别一个设计良好的模块与一个设计不好的模块,最重要的因素是,这个模块对于外部的其他模块而言,是否隐藏了内部的数据和其他的实现细节.一个设计良好的模块会隐藏所有的实 ...
- Effective java笔记(二),所有对象的通用方法
Object类的所有非final方法(equals.hashCode.toString.clone.finalize)都要遵守通用约定(general contract),否则其它依赖于这些约定的类( ...
- Java笔记:抽象类、接口
这篇笔记主要是抽象类和接口,还有简单介绍下三种设计模式:模板模式.工厂模式.命令模式 1.抽象方法和抽象类(1)抽象方法和抽象类都必须使用abstract修饰符来定义,包含抽象方法的类只能被定义成抽象 ...
- effective java笔记之单例模式与序列化
单例模式:"一个类有且仅有一个实例,并且自行实例化向整个系统提供." 单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法 ...
- effective java笔记之java服务提供者框架
博主是一名苦逼的大四实习生,现在java从业人员越来越多,面对的竞争越来越大,还没走出校园,就TM可能面临失业,而且对那些增删改查的业务毫无兴趣,于是决定提升自己,在实习期间的时间还是很充裕的,期间自 ...
- Effective Java 第三版—— 20. 接口优于抽象类
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——22. 接口仅用来定义类型
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- java 类的加载、连接和初始化
JVM和类 调用Java命令运行Java程序时,该命令将会启动一条Java虚拟机进程,不管该Java程序启动了多少条线程,创建了多少个变量,它们都处于该Java虚拟机进程里,共享该JVM进程的内存区. ...
- mysql数据库优化课程---7、网站的搜索技术怎么选
mysql数据库优化课程---7.网站的搜索技术怎么选 一.总结 一句话总结: 1.量很小(像小网站)---like2.量大一点()---标签3.量超级大(像百度)---搜索引擎 1.数据库中取一列比 ...
- python学习笔记(pict+subprocess)
这几天看到接口自动化用例的生成,关于这里博主自己也想了想,是否可以根据参数的范围自动生成用例,这样就不用一条一条的写接口测试用例 这里就设计到用例设计的方法,让我想到之前接触过一款微软的用例自动生成工 ...
- yii2:引用项目外的文件或类
yii2:引用项目外的文件或类 以项目:frontend为例,文件目录如下: frontend/ frontend/controllers frontend/views fronte ...
- yii2: oralce中文,有的汉字是2个字节,有的汉字是3个字节
yii2: oralce中文,有的汉字是2个字节,有的汉字是3个字节 请用mb_substr转成1个英文字节
- MySQL连接中出现大量的 init 状态问题
最怕的就是睡一觉醒来,系统出了问题. 大早系统无法登陆,以前没有经验的同学code的代码,竟然 try catch 没有记录异常日志信息. 查的问题一点头绪都没有,一直锁定在公司公共网关接口出了问题. ...
- 关于htonl()
htons #include <arpa/inet.h> uint16_t htons(uint16_t hostshort); htons的功能: ...
- golang实现图片上传
golang实现图片上传 该代码为使用beego实现前后端图片上传.话不多说,直接上代码. 1.前端代码 html代码: <div class="col-5 f-l text text ...
- 剑指Offer面试题:7.斐波那契数列
一 题目:斐波那契数列 题目:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项.斐波那契数列的定义如下: 二 效率很低的解法 很多C/C++/C#/Java语言教科书在讲述递归函数的时 ...
- 微型 Python Web 框架: Bottle
微型 Python Web 框架: Bottle 在 19/09/11 07:04 PM 由 COSTONY 发表 Bottle 是一个非常小巧但高效的微型 Python Web 框架,它被设计为仅仅 ...