#JAVA笔记#
抽象类
定义
抽象类与普通类基本类似,唯一的区别在于使用abstract关键字修饰,且类中有未实现(没有方法体)的抽象方法(abstract修饰)。抽象方法必须位于抽象类中,抽象方法只能访问抽象成员。
目的在于当一些方法不知道该如何实现时可以采用抽象类,具体的实现交给其子类实现。
所以继承抽象类的子类必须实现其抽象方法,除非该子类也为抽象类。
特点
1、抽象类不能被实例化
2、抽象类可以没有abstract方法;但是一旦包含了abstract方法,该类必须为抽象类。
3、abstract只能修饰方法和类,不能修饰属性和其他。
4、抽象类本质还是类,可以有类的所有成员。
5、抽象方法不能使用private、final、static修饰,因为抽象方法必须被子类重写,这些关键字和重写违背。
抽象类的作用
抽象类的主要作用在于统一规范、代码复用和增强设计清晰度。
1、在抽象类中声明一个抽象方法,相当于向所有子类发布了一个“契约”或“规范”。
2、统一接口,促进代码复用。抽象方法为一系列相关的子类定义了一个统一的额借口,所有子类必须使用相同的名称、参数、返回值实现。如果多个子类有共同的属性和行为,这些共性可以提取到父类,从而实现了代码的高效复用。
3、设计意图更清晰。抽象方法本身就是一种文档,它清晰告诉开发者:这里有一个关键的行为需要被实现,子类必须关注它。
4、便于维护和扩展。当需要为系统添加子类时,抽象方法确保了新类会遵循既定的规范。如果需要修改规范,只需要修改抽象类中的方法声明,所有的子类都会在编译时收到提醒,需要相应地更新其实现。
使用场景——模版设计模式
抽象类-统计耗时
package com.hspedu.abstract1_; import java.util.Date; // 1、定义抽象类 public abstract class Template { //定义模版统计代码耗时——使用抽象类,继承它的子类实现其方法 public void calculate(){ long start=System.currentTimeMillis(); job(); long end=System.currentTimeMillis(); System.out.println("代码耗时为:"+(end-start)); } public abstract void job(); }子类-实现具体业务
package com.hspedu.abstract1_; public class CodeTest extends Template{ private StringBuffer sb=new StringBuffer(); @Override public void job() { for(int i=0;i<800000;i++){ sb.append("a"); } } }main方法—原理:多态+动态绑定机制
多态:ct编译类型为父类Template;运行类型为子类CodeTest
动态绑定:调用统计耗时的方法calculate()使会调用job()方法,此时根据动态绑定机制,会根据运行类型,调用子类的job()方法。
package com.hspedu.abstract1_; public class Test { public static void main(String[] args) { Template ct=new CodeTest(); ct.calculate(); } }接口
定义
接口包含属性和一系列未实现的方法。接口中有抽象方法、静态方法、默认方法三种。
jdk7.0之前,接口中所有方法默认都是抽象方法(即没有方法体,默认有abstract修饰);jdk8.0之后几口可以有静态方法(static关键字修饰)和默认方法(default关键字修饰),可以有方法的具体实现。
特点
1、接口不能被实例化。
2、接口中所有的方法是public方法,接口中的抽象方法,可以不用写abstract。
3、一个普通类实现接口,就必须实现接口中的所有方法。
4、抽象类实现接口,可以不用实现接口的方法。
5、一个类可以实现多个接口。
6、接口中的属性都是public static final修饰的,且必须要初始化。int a=1,等价于 public static final int a=1。(所以接口中的属性多数是一些静态常量。)访问方式:接口名.属性名。
7、一个接口不能继承其他类,但是可以继承多个接口。如 interface A extends B,C{}
8、接口的修饰符只能有public和默认,和类的修饰符一样。
9、接口与接口之间是继承关系,类和接口之间是实现关系。
10、一个类只能继承一个父类,但可以实现多个接口。
如小猴子的父亲只能是猴子(父类),其出生就带有猴子的一些特性,能够自然使用;但是小猴子如果想像鸟意向飞翔,鱼一样游泳,就需要实现鸟的飞翔功能,鱼的游泳功能等等(接口)。
所以,子类继承了父类就自动拥有父类的功能;如果子类需要扩展功能,可以通过实现接口的方式扩展。
11、当子类中有变量x,且父类中有变量x,接口中有常量x,对应同名属性,访问时,要具体指定访问哪一个。访问父类的——super.x,访问接口的——接口名.x,访问子类本身的——this.x
多态
1、多态参数
package com.hspedu.Interface3_; //主函数 public class PolyParam { public static void main(String[] args) { UsbInterface phone=new Phone();//多态,向上转型 Computer computer = new Computer(); computer.getConn(phone); } } //接口 interface UsbInterface{ void usbCon(); } //手机子类实现接口 class Phone implements UsbInterface{ @Override public void usbCon() { System.out.println("手机usb接口"); } } //电脑类 class Computer{ public void getConn(UsbInterface usbInterface){//多态参数,电脑连接手机-手机实现usb接口功能,电脑通过接收手机实例连接手机。 usbInterface.usbCon();//动态绑定 } }2、多态数组
package com.hspedu.Interface3_; public class PolyArray { public static void main(String[] args) { //案例:给USB数组中,存放Phone和相机对象,phone类有一个特殊call方法, // 请遍历Usb数组,如果是phone对象,除了调用Usb接口定义的方法外, // 还需要调用phone特有的call方法。 //创建多态数组,引用指向多个子类对象 UsbInterface2[] usbInterface2=new UsbInterface2[6]; usbInterface2[0]=new Phone2(); usbInterface2[1] = new Phone2(); usbInterface2[2] = new Phone2(); usbInterface2[3] = new Phone2(); usbInterface2[4] = new Camare(); usbInterface2[5]= new Camare(); for(UsbInterface2 u:usbInterface2){ u.usbCon();//动态绑定 if(u instanceof Phone2){ ((Phone2) u).call(); } } } } //接口 interface UsbInterface2{ void usbCon(); } //手机类,实现接口,增加call()方法 class Phone2 implements UsbInterface2{ @Override public void usbCon() { System.out.println("手机usb接口"); } public void call(){ System.out.println("使用打电话功能"); } } //相机类,实现接口 class Camare implements UsbInterface2{ @Override public void usbCon() { System.out.println("相机usb接口"); } }3、动态传递
如果接口A继承了接口C,而子类D实现了接口A,相当于也实现了接口C,所以A、C的引用都可以指向子类D的实例。
使用场景
接口的主要作用是实现代码的规范性和复用性。如上层设计人员可以定义一些接口控制软件的规范(如统一命名、统一需实现的功能),下层实现人员统一实现。
例如:
接口:
package com.hspedu.Interface3_; public interface DBInterface { //定义接口实现数据库连接的统一管理 public void connect();//默认abstract public void close(); }子类:
package com.hspedu.Interface3_; public class MysqlConn implements DBInterface{ @Override public void connect() { System.out.println("建立MYSQL数据库连接"); } @Override public void close() { System.out.println("关闭MYSQL数据库连接"); } }package com.hspedu.Interface3_; public class OracleConn implements DBInterface{ @Override public void connect() { System.out.println("建立Oracle数据库连接"); } @Override public void close() { System.out.println("关闭Oracle数据库连接"); } }main方法:注意此处多态和动态绑定的使用。
package com.hspedu.Interface3_; public class Test { public static void main(String[] args) { //创建子类的实例对象 MysqlConn mysqlConn=new MysqlConn(); conn(mysqlConn); OracleConn oracleConn=new OracleConn(); conn(oracleConn); } //设计为static方法,可以直接调用。 public static void conn(DBInterface conn){//多态:使用DBInterface接口类型接受Mysql或Oracle数据库连接实例。 conn.connect();//动态绑定:运行是执行运行类型的代码。 conn.close(); } }接口与继承类
1、接口和继承解决的问题不同
继承的价值:解决代码复用性和可维护性。
接口的价值:设计,设计好各种规范(方法),让其他子类去实现这些方法,即更加灵活。
2、接口比继承更加灵活,继承是is-a的关系,接口是like-a的关系
3、接口在一定程度上实现了代码的解耦,即接口规范性+动态绑定
快捷键
实现所有接口方法快捷键:alter+enter,鼠标放在报错的地方,类名处。