抽象类与普通类相比最大的特点是约定了子类的实现要求,但是抽象类存在单继承局限。如果要约定子类的实现要求并避免单继承局限就需要使用接口。
在以后的开发中:接口优先(在一个操作即可以使用抽象类又可以使用接口的时候优先考虑使用接口)
接口定义:接口就是一个抽象方法
和全局常量
的集合,在Java中接口使用interface
关键字定义。
范例:定义一个简单的接口
interface IMessage{
//全局常量
public static final String MSG = "I am a student";
//抽象方法
public abstract void print();
}
为了区分接口,建议在所有的接口前面追加字母I
子类如果想要使用接口,那么就必须用implements
关键字来实现接口,同时一个子类可以实现多个接口【可以使用接口实现多继承的概念】
对于接口的子类(子类不是抽象类)必须覆写接口中的全部抽象方法,随后可以利用子类的向上转型通过实例化子类来得到接口的实例化对象。
例:观察子类实现接口&父接口间相互转换
interface IMessage{
//全局常量
public static final String MSG = "I am a student";
//抽象方法
public abstract void print();
}
interface INews{
public abstract String getNews();
}
//覆写接口中的全部抽象方法
class MessageImpl implements IMessage,INews{
public void print()
{
System.out.println(IMessage.MSG);
}
public String getNews()
{
return IMessage.MSG;
}
}
public class Test{
public static void main(String[] args)
{
//子类向上转型,为父接口实例化对象
IMessage m = new MessageImpl();
m.print();
INews n = (INews) m;
System.out.println(n.getNews());
}
}
接口中不管是属性还是方法,其权限都是public,由于被覆写的方法不能拥有比之前更为严格的权限,所以被覆写的方法权限均为public
由于接口之中只是全局常量
和抽象方法
的集合,所以一下两种定义的格式效果都是一样的:
interface IMessage{
//全局常量
public static final String MSG = "I am a student";
//抽象方法
public abstract void print();
}
interface IMessage{
String MSG = "I am a student";
void print();
}
建议接口中的方法和属性不要加任何的修饰符,public也不要加,保持代码的简洁性。
当一个子类即需要实现接口又需要继承抽象类时,先使用extends继承一个抽象类,而后用implements实现多个接口
interface IMessage{
//抽象方法
public abstract void print();
}
abstract class News{
public abstract void getNews();
}
//覆写接口中的全部抽象方法
class MessageImpl extends News implements IMessage{
public void print()
{
System.out.println("haha");
}
public void getNews()
{
System.out.println("hehe");
}
}
public class Test{
public static void main(String[] args)
{
//子类向上转型,为父接口实例化对象
IMessage m = new MessageImpl();
m.print();
//MessageImpl 是抽象类和接口的共同子类
News news = (News) m;
news.getNews();
}
}
接口不能继承抽象类(接口中只有全局常量和抽象方法,但是抽象类中除了全局常量和抽象方法还有自己的普通方法,接口无法继承并覆写这些普通方法)
,但是抽象类可以实现接口。
抽象类实现接口
//接口
interface IMessage{
//为保持代码的简洁性省略public abstract
void print();
}
//抽象类继承IMessage接口,由于为抽象类所以可以不覆写接口中的print方法
abstract class News implements IMessage{
//抽象方法必须加abstract关键字,否则就会报“缺少方法主体、或声明对象”
public abstract void getNews();
}
//普通类 继承抽象类应该实现所有的接口
class MessageImpl extends News{
public void print()
{
System.out.println("哈哈");
}
public void getNews()
{
System.out.println("呵呵");
}
}
public class Test{
public static void main(String[] args)
{
//向上转型为接口实例化对象
IMessage m = new MessageImpl();
m.print();
//通过父类与父接口的相互转换为抽象类实例化对象
News news = (News)m;
news.getNews();
}
}
实际上此时的结构关系属于三层结构
读许多第三方文库时,可能会出现以下代码:class MessageImpl extends News implements IMessage;
此时的implements IMessage只是为了强调MessageImpl是IMessage的子类。
接口继承抽象类
//抽象类
abstract class News{
//抽象方法必须加abstract关键字,否则就会报“缺少方法主体、或声明对象”
public abstract void getNews();
}
//接口继承抽象类
interface IMessage extends News{
//为保持代码的简洁性省略public abstract
void print();
}
//普通类 继承抽象类应该实现所有的接口
class MessageImpl implements IMessage{
public void print()
{
System.out.println("哈哈");
}
public void getNews()
{
System.out.println("呵呵");
}
}
public class Test{
public static void main(String[] args)
{
//向上转型为接口实例化对象
IMessage m = new MessageImpl();
m.print();
//通过父类与父接口的相互转换为抽象类实例化对象
News news = (News)m;
news.getNews();
}
}
接口可以使用extends关键字继承多个父接口
interface A{
//省略public abstract
void printA();
}
interface B{
//省略public abstract
void printB();
}
interface C extends A,B{
//省略public abstract
void printC();
}
class Impl implements C{
public void printA()
{
System.out.println("A");
}
public void printB()
{
System.out.println("B");
}
public void printC()
{
System.out.println("C");
}
}
public class Test{
public static void main(String[] args)
{
//向上转型,为接口A实例化对象
A a = new Impl();
a.printA();
//通过父接口之间的相互转换为接口B实例化对象
B b = (B)a;
b.printB();
}
}
接口可以定义一系列的内部结构,包括:内部普通类、内部接口;其中static定义的内部接口就相当于一个外部接口
interface A{
//省略public abstract
void printA();
interface B{
void printB();
}
}
//继承两个接口,就必须将两个接口都实现
//如果只是继承A接口,只需要实现接口A中的抽象方法即可
class Impl implements A,B{
public void printA()
{
System.out.print("哈哈");
}
public void printB()
{
System.out.print("呵呵");
}
}
public class Test{
public static void main(String[] args)
{
}
}
接口的应用:定义标准
接口在实际开发之中有三大核心应用环境:
//定义一个usb标准
interface IUSB{
void setup(); //安装驱动
void work(); //进行工作
}
//定义USB子类
class UDiskImpl implements IUSB{
public void setup()
{
System.out.println("安装U盘驱动");
}
public void work()
{
System.out.println("U盘开始工作");
}
}
class PrintDiskImpl implements IUSB()
{
public void setup()
{
System.out.println("安装打印机驱动");
}
public void work()
{
System.out.println("打印机开始工作");
}
}
//定义一个电脑类
class Computer{
public void plugin(IUSB usb)
{
usb.setup(); //安装
usb.work(); //工作
}
}
public class Test{
public static void main(String[] args)
{
Computer computer = new Computer();
computer.plugin(new UDisk());
computer.plugin(new PrintDisk());
}
}
通过以上代码我们发现:接口和对象多态性的概念结合之后,对于参数的统一更加明确了。而且可以发现接口是在类之上的设计抽象。
//定义车接口
interface ICar{
void drive();
void park();
}
class BusImpl implements ICar{
public void drive()
{
System.out.println("公交车驶入");
}
public void park()
{
System.out.println("公交车停放");
}
}
class AutotruckImpl implements ICar{
public void drive()
{
System.out.println("大卡车驶入");
}
public void park()
{
System.out.println("大卡车停放");
}
}
class SedanImpl implements ICar{
public void drive()
{
System.out.println("小轿车驶入");
}
public void park()
{
System.out.println("小轿车停放");
}
}
class MotorbikeImpl implements ICar{
public void drive()
{
System.out.println("摩托车驶入");
}
public void park()
{
System.out.println("摩托车靠边停放");
}
}
class Park
{
public void parkingLot(ICar car)
{
car.drive();
car.park();
}
}
public class Test{
public static void main(String[] args)
{
Park park = new Park();
park.parkingLot(new MotorbikeImpl());
park.parkingLot(new SedanImpl());
park.parkingLot(new AutotruckImpl());
park.parkingLot(new BusImpl());
}
}