1 抽象类和抽象方法
1.1 抽象类的概念
- 随着继承层次中一个个新的子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计的非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
1.2 抽象类和抽象方法
- 用abstract关键字来修饰的类,这个类叫做抽象类。
- 用abstract关键字修饰一个方法,这个方法叫抽象方法(只有方法的声明,没有具体的实现)。
- 含有抽象方法的类必须声明是抽象类。
- 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写抽象类中的抽象方法,并提供方法体。如果没有重写全部的抽象方法,那么该子类必须是抽象类。
- 不能用abstract修饰变量、代码块和构造器。
- 不能用abstract修饰私有方法,静态方法、final修饰的方法和final修饰的类。
1.3 抽象类的注意事项
- abstract关键字不能用来修饰属性、构造器等结构。
- abstract关键字不能修饰私有方法、静态方法、final的方法、final的类。
1.3 抽象类的应用示例
- 示例:
package day15;/** * 雇员 */public abstract class Employee { private String name; private Integer id; private Double salary; public Employee() { } public Employee(String name, Integer id, Double salary) { this.name = name; this.id = id; this.salary = salary; } /** * 工作 */ public abstract void work();}
package day15;public class CommonEmployee extends Employee { public CommonEmployee() { } public CommonEmployee(String name, Integer id, Double salary) { super(name, id, salary); } @Override public void work() { System.out.println("员工在一线写代码"); }}
package day15;public class Manager extends Employee { /** * 奖金 */ private Double bonnu; public Manager() { } public Manager(String name, Integer id, Double salary, Double bonnu) { super(name, id, salary); this.bonnu = bonnu; } @Override public void work() { System.out.println("管理员工,提高公司运行的效率"); }}
package day15;public class EmployeeTest { public static void main(String[] args) { Employee employee = new Manager("许威威",1001,5000.00,1000.00); System.out.println(employee); employee.work(); }}
2 模板方法的设计模式
2.1 什么是模板方法的设计模式
- 当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
- 换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。
2.2 模板方法的设计模式的应用示例
- 示例:
package day15;public abstract class Template { public void speed(){ long start = System.currentTimeMillis(); code(); long end = System.currentTimeMillis(); System.out.println("消耗时间:"+(end - start)+"毫秒"); } /** * 子类需要重写这个方法 */ protected abstract void code();}
package day15;public class SubTemplate extends Template { @Override protected void code() { for (int i = 0; i < 500; i++) { System.out.println(i); } }}
package day15;public class TemplateTest { public static void main(String[] args) { Template template = new SubTemplate(); template.speed(); }}
3 接口
3.1 接口的引入
- 一方面,有时必须从几个类中派生出一个子类,集成它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
- 另一方面,有时必须从几个类中抽取一些共同的行为特征,而它们之间又没有is a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、手机等都支持USB连接。
- 接口就是规范,定义的一组规则,体现了现实世界中“如果你是/要……则必须能……”的思想。继承是一个“是不是”的关系,而接口实现则是“能不能”的关系。
- 接口的本质是契约,标准或规范,就如同我们的法律一样。制定好大家都要遵守。
3.2 接口的举例
3.3 接口的概念
- 接口就是抽象方法和常量值定义的集合。
3.4 接口的特点
- 由interface来定义。
- 接口中的所有成员变量默认都是public static final修饰的。
- 接口中的所有方法默认都是public abstract修饰的。
- 接口中没有构造器。
- 接口采用的多继承机制。
- 接口的语法格式:
class 子类 extends 父类 implements 接口{}
- 一个类可以实现多个接口,接口和接口之间是多继承关系。
- 实现接口的类必须提供接口中所有方法的具体实现内容,才可实例化。否则,该类是抽象类。
- 接口的主要用途就是被实现类实现。(面向接口编程)
- 和继承关系类似,实现类和接口之间存在多态性。
- 接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类只包含常量和公共的抽象方法(JDK7之前),而没有变量和抽象方法的实现。
3.5 接口的应用示例
- 示例:USB
package day15;/** * USB */public interface USB { /** * 常量:可以定义长、宽、高、传输速率等 */ void start(); void stop();}
package day15;/** * 打印机 */public class Printer implements USB { @Override public void start() { System.out.println("打印机开始工作"); } @Override public void stop() { System.out.println("打印机结束工作"); }}
package day15;/** * U盘 */public class UDisk implements USB { @Override public void start() { System.out.println("u盘开始工作"); } @Override public void stop() { System.out.println("u盘结束工作"); }}
package day15;public class USBTest { public static void main(String[] args) { USB usb = new Printer(); usb.start(); usb.stop(); usb = new UDisk(); usb.start(); usb.stop(); }}
3.6 JDK8中接口的新特性
- 在JDK8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这完全合法,只是它看起来违反了接口作为一个抽象定义的理念。
- JDK8中接口中的静态方法,使用static关键字修饰。只能通过接口直接调用静态方法。(这个就是将以前的工具类慢慢迁移到接口中)
- JDK8中接口中的默认方法,使用default关键字修饰。可以通过实现来对象来调用,我们在已有的接口中提供新方法的同时,还保持了和旧版本代码的兼容性。
- 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。
- 如果一个接口中定义了一个默认的方法,而另外一个接口中也定义了一个同名同参数的方法(不论此方法是否为默认方法),在实现类同时实现了这两个接口时,会出现接口冲突。解决方法就是实现类必须覆盖接口中的同名同参数的方法来解决冲突。
3.6.1 JDK8中接口定义的示例
- 示例:
package day15;/** * JDK8中接口的新特性 */public interface JDK8Interface { static void demo() { System.out.println("江苏"); } default void demo1() { System.out.println("北京"); } default void demo2() { System.out.println("安徽"); }}
package day15;public class JDK8InterfaceImpl implements JDK8Interface { @Override public void demo2() { System.out.println("实现了:安徽"); }}
package day15;public class JDK8InterfaceTest { public static void main(String[] args) { JDK8Interface.demo();//接口中定义的静态方法,只能通过接口来调用 JDK8Interface jdk8Interface = new JDK8InterfaceImpl(); jdk8Interface.demo1();//通过实现类的对象,可以调用接口中的默认方法 jdk8Interface.demo2(); }}
4 内部类
- 在Java中,允许将一个类A定义在另一个类B中,那么此时类A被称为内部类,类B被称为外部类。
4.1 分类
- 根据内部类定义的位置不同,可以将内部类分为成员内部类(静态、非静态)和局部内部类(方法体内、代码块内、构造器内)。
package day15;/** * 这是外部类 */public class Outer { //成员static的内部类 static class AA{ } //成员非static的内部类 class BB{ } public Outer(){ //定义在构造器中的局部内部类 class CC{ } } { //定义在代码块中的局部内部类 class DD{ } } public void method(){ //定义在方法中的局部内部类 class EE{ } } }
4.2 成员内部类
- 作为类的角色:
- ⑴类中可以定义属性、方法、构造器等。
package day15;public class Outer { class BB { private String name; public BB() { } public BB(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } static class AA { private String name; public AA() { } public void show() { } }}
- ⑵可以被final修饰。表示此类不能被继承。
- ⑶可以被abstract修饰。表示此类不能被实例化。
- 作为外部类的成员:
- ⑴调用外部类的结构(静态结构不能访问非静态的结构)。
package day15;public class Outer { String name; public void eat(){ System.out.println("吃"); } class BB { String a = name; public void show(){ System.out.println("展示"); eat(); } } static class AA { }}
- ⑵可以被static修饰。
- ⑶可以被四种不同的权限修饰符修饰。
- 实例化成员内部类的对象。
package day15;public class Outer { class AA{ } static class BB{ }}
package day15;public class OuterTest { public static void main(String[] args) { //静态成员变量 Outer.BB bb = new Outer.BB(); //非静态成员变量 Outer.AA aa = new Outer().new AA(); }}
4.3 局部内部类的特点
- 局部内部类依然是一个独立类,在编译之后内部类会被编译成独立的.class文件,但是前面会以类名和$符号,以及数字编号开头。
- 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。
- 局部内部类可以使用外部类的成员,包括私有的。
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。
- 局部内部类和局部变量类似,不能使用权限访问修饰符修饰。
- 局部内部类不能使用static修饰。
4.4 匿名内部类
- 匿名内部内不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或一个类。
- 格式:
new 父类构造器(实参列表)|实现接口(){ //匿名你诶不类的实现部分 }
- 匿名内部类的特点:
- ⑴匿名内部类必须继承父类或实现接口。
- ⑵匿名内部类只能有一个对象。
- ⑶匿名内部类对象只能使用多态形式的引用。
- 示例:
package day15;public class InnerTest { public static void main(String[] args) { } public Comparable comparable(){ //匿名内部类 return new Comparable