8.5、模板方法设计模式【了解】
抽象类体现的就是一种模板方法设计模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
解决的问题:
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。
abstract class Template { public final void getTime() { long start= System.currentTimeMillis(); code(); long end= System.currentTimeMillis(); System.out.println("执行时间是:"+ (end-start)); } public abstract void code(); } class SubTemplate extends Template { public void code() { for(inti= 0; i< 10000; i++) { System.out.println(i); } } } |
8.6 接口【重点】
8.6.1 什么是接口?
有时必须从几个类中抽象出一个父类,子类继承它所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都支持USB连接。
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/则必须能...”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能"的关系。
接口的本质是契约,标准,规范,就像我们的法律一样,制定好后大家都要遵守。
8.6.2 接口的特点
接口(interface)是抽象方法和常量值定义的集合。接口的特点:
用interface来定义。
接口中的所有成员变量都默认是由public static final修饰的。
接口中的所有方法都默认是由public abstract修饰的。
接口中没有构造器。
接口采用多继承机制。
接口使用的注意事项:
定义Java类的语法格式:先写继承,后写实现;
class SubClass extends SuperClass implements InterfaceA{ } |
一个类可以实现多个接口,接口也可以继承其它接口。
实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化,否则,仍为抽象类。
接口的主要用途就是被实现类实现。(面向接口编程)。
与继承关系类似,接口与实现类之间存在多态性。
接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义(JDK7.0及之前),而没有变量和方法的实现。
8.6.3 JDK8.0中关于接口的新特性【面试点】
Java8中,可以为接口添加静态方法和默认方法:
静态方法:可以通过接口直接调用静态方法,并执行其方法体。
默认方法:默认方法使用default关键字修饰,通过实现类的对象来调用。
接口方法的冲突解决:
如果多个接口中定义了同名同参数的默认方法,在实现类同时实现了这两个接口时,会出现接口冲突。可以通过在实现类里覆盖接口中同名同参数的默认方法来解决冲突。
如果一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则,接口中具有相同名称和参数的默认方法会被忽略。
8.6.4 接口与抽象类的区别【面试点】
8.7内部类【难点】【面试点】
8.7.1 什么是内部类
在Java中,允许一个类定义另一个类,前者称为外部类,后者称为内部类。
Inner Class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
Inner Class的名字不能与包含它的外部类名称相同;
内部类分类:
-
-
- 成员内部类:非静态成员内部类、静态成员内部类;
- 局部内部类:匿名内部类
-
8.7.2 成员内部类
成员内部类与外部类的不同点:
可以采用private或protected修饰符修饰;
可以在内部类中调用外部类的成员;
可以使用static关键字修饰,但此时就不能再使用外层类的非静态成员。
成员内部类的特点:
可以在内部定义属性、方法、构造器等成员;
可以直接使用外部类的所有成员,包括私有的数据;
外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式;
可以使用abstract关键字修饰,因此可以被其它的内部类继承;
可以使用final关键字修饰;
编译以后生成的字节码文件格式:OuterClass$InnerClass.class。
注意事项:
外部类或静态成员内部类中可以使用static关键字,而非静态成员内部类中不能使用static关键字;
外部类的静态成员部分使用内部类成员时,可以考虑使用静态内部类。
示例1:
class Outer { private int s; public class Inner { public void inner_method() { s= 100; System.out.println("在内部类Inner中s="+ s); } } public void outer_method() { Inner i= newInner(); i.inner_method(); } } public class InnerTest { public static void main(String args[]) { Outer o= new Outer(); o.outer_method(); } } |
示例2:
public class Outer { private int s= 111; public class Inner { private int s= 222; public void inner_method(int s) { System.out.println(s); // 输出局部变量s System.out.println(this.s); // 输出内部类对象的属性s System.out.println(Outer.this.s); // 输出外部类对象属性s } } public static void main(String args[]) { Outer a= new Outer(); Outer.Inner b= a.new Inner(); b.mb(333); } } |
8.7.3 局部内部类
局部内部类的特点:
局部内部类仍然是一个独立的类,在编译之后局部内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号;
局部内部类只能在声明它的方法或代码块中使用,而且是先声明后使用,除此之外的任何地方都不能使用该类;
局部内部类可以使用外部类的成员,包括私有的;
局部内部类可以使用外部方法的局部变量,但是必须是final的,由局部内部类和局部变量的生命周期不同所致;
局部内部类和局部变量地位类似,不能使用访问修饰符修饰;
局部内部类不能使用static修饰,因此也不能包含静态成员。
匿名内部类及其特点:
匿名内部类不能定义任何静态成员、方法和类;
匿名内部类必须继承父类(一般为抽象类)或实现接口;
匿名内部类一定是在new的后面,用其隐含实现一个接口或类;
匿名内部类只能创建一个实例。
new 父类构造器(实参列表)| 实现接口 () { //匿名内部类的类体部分 } |
示例:
interface A { public abstract void fun(); } public class Outer { public static void main(String[] args) { new Outer().call_Inner_method(new A(){ @override public void fun() { System.out.println(“implement for fun"); } }); } public void call_Inner_method(A a) { a.fun(); } } |
8.8 小结
static关键字可以修饰属性、方法、代码块、内部类,一般用来修饰属性和方法。【难点】
final关键字可以修饰属性、方法、类,通常使用在属性上,用来声明常量。【重点】
使用abstract关键字修饰的方法叫做抽象方法,修饰的类叫做抽象类。【重点】
抽象类不一定含有抽象方法,含有抽象方法的类一定是抽象类;
抽象类不能实例化;
子类继承抽象父类必须重写抽象方法。
接口是一个特殊的抽象类,可以实现多继承:【重点】
接口只允许包含常量与抽象方法;
JDK8.0后可以包含一个默认方法和静态方法。