枚举、包装类、接口

枚举

1 概述

某些类型的对象是有限的几个,这样的例子举不胜举:

  • 星期:Monday(星期一)......Sunday(星期天)

  • 性别:Man(男)、Woman(女)

  • 月份:January(1月)......December(12月)

  • 季节:Spring(春节)......Winter(冬天)

  • 支付方式:Cash(现金)、WeChatPay(微信)、Alipay(支付宝)、BankCard(银行卡)、CreditCard(信用卡)

  • 员工工作状态:Busy(忙)、Free(闲)、Vocation(休假)

  • 订单状态:Nonpayment(未付款)、Paid(已付款)、Fulfilled(已配货)、Delivered(已发货)、Checked(已确认收货)、Return(退货)、Exchange(换货)、Cancel(取消)

枚举类型本质上也是一种类,只不过是这个类的对象是固定的几个,而不能随意让用户创建。

在JDK1.5之前,需要程序员自己通过特殊的方式来定义枚举类型。

在JDK1.5之后,Java支持enum关键字来快速的定义枚举类型。

2 JDK1.5之前

在JDK1.5之前如何声明枚举类呢?

  • 构造器加private私有化

  • 本类内部创建一组常量对象,并添加public static修饰符,对外暴露这些常量对象

示例代码:

public class TestEnum {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
}
}
class Season{
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();

private Season(){

}

public String toString(){
if(this == SPRING){
return "春";
}else if(this == SUMMER){
return "夏";
}else if(this == AUTUMN){
return "秋";
}else{
return "冬";
}
}
}

3 JDK1.5之后

语法格式:

【修饰符】 enum 枚举类名{
   常量对象列表
}

【修饰符】 enum 枚举类名{
   常量对象列表;
   
   其他成员列表;
}

示例代码:

public class TestEnum {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
}
}
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}

示例代码:

public class TestEnum {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
}
}
enum Season{
SPRING("春"),SUMMER("夏"),AUTUMN("秋"),WINTER("冬");
private final String description;

private Season(String description){
this.description = description;
}

public String toString(){//需要手动编写,无法使用Generate toString()...
return description;
}
}

枚举类的要求和特点:

  • 枚举类的常量对象列表必须在枚举类的首行,因为是常量,所以建议大写。

  • 如果常量对象列表后面没有其他代码,那么“;”可以省略,否则不可以省略“;”。

  • 编译器给枚举类默认提供的是private的无参构造,如果枚举类需要的是无参构造,就不需要声明,写常量对象列表时也不用加参数,

  • 如果枚举类需要的是有参构造,需要手动定义private的有参构造,调用有参构造的方法就是在常量对象名后面加(实参列表)就可以。

  • 枚举类默认继承的是java.lang.Enum类,因此不能再继承其他的类型。

  • JDK1.5之后switch,提供支持枚举类型,case后面可以写枚举常量名。

  • 枚举类型如有其它属性,建议(不是必须)这些属性也声明为final的,因为常量对象在逻辑意义上应该不可变。

4 枚举类型常用方法

1.toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法!
2.name():返回的是常量名(对象名) 【很少使用】
3.ordinal():返回常量的次序号,默认从0开始
4.values():返回该枚举类的所有的常量对象,返回类型是当前枚举的数组类型,是一个静态方法
5.valueOf(String name):根据枚举常量对象名称获取枚举对象

示例代码:

public class TestEnum {
public static void main(String[] args) {
Season[] values = Season.values();
for (int i = 0; i < values.length; i++) {
switch(values[i]){
case SPRING:
System.out.println(values[i]+":春暖花开,万物复苏");
break;
case SUMMER:
System.out.println(values[i]+":百花争艳,郁郁葱葱");
break;
case AUTUMN:
System.out.println(values[i]+":菊桂飘香,百树凋零");
break;
case WINTER:
System.out.println(values[i]+":梅花独开,大地一色");
break;
}
}
}
}
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}

5 练习

案例: 1、声明月份枚举类Month:

(1)创建:1-12月常量对象

JANUARY,FEBRUARY,MARCH,APRIL,MAY,JUNE,JULY,AUGUST,SEPTEMBER,OCTOBER,NOVEMBER,DECEMBER

(2)声明两个属性:value(月份值,例如:JANUARY的value为1), description(描述,例如:JANUARY的description为1月份是一年的开始)。

(3)声明一个有参构造,创建12个对象

(4)声明一个方法:public static Month getByValue(int value)

(5)手动重写toString():返回对象信息,例如:1->JANUARY->1月份是一年的开始。

2、在测试类中,从键盘输入1个1-12的月份值,获取对应的月份对象,并打印对象

包装类

1 包装类

Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而当要使用只针对对象设计的API或新特性(例如泛型),那么基本数据类型的数据就需要用包装类来包装。

序号基本数据类型包装类(java.lang包)
1 byte Byte
2 short Short
3 int Integer
4 long Long
5 float Float
6 double Double
7 char Character
8 boolean Boolean
9 void Void

2 装箱与拆箱

装箱:把基本数据类型转为包装类对象。

转为包装类的对象,是为了使用专门为对象设计的API和特性

拆箱:把包装类对象拆为基本数据类型。

转为基本数据类型,一般是因为需要运算,Java中的大多数运算符是为基本数据类型设计的。比较、算术等

基本数值---->包装对象

Integer i1 = new Integer(4);//使用构造函数函数
Integer i2 = Integer.valueOf(4);//使用包装类中的valueOf方法

包装对象---->基本数值

Integer i1 = new Integer(4);
int num1 = i1.intValue();

JDK1.5之后,可以自动装箱与拆箱。

注意:只能与自己对应的类型之间才能实现自动装箱与拆箱。

Integer i = 4;//自动装箱。相当于Integer i = Integer.valueOf(4);
i = i + 5;//等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5;
//加法运算完成后,再次装箱,把基本数值转成对象。
Integer i = 1;
Double d = 1;//错误的,1是int类型

总结:对象(引用数据类型)能用的运算符有哪些?

(1)instanceof

(2)=:赋值运算符

(3)==和!=:用于比较地址,但是要求左右两边对象的类型一致或者是有父子类继承关系。

(4)对于字符串这一种特殊的对象,支持“+”,表示拼接。

3 包装类的一些API

1、基本数据类型和字符串之间的转换

(1)把基本数据类型转为字符串

int a = 10;
//String str = a;//错误的
//方式一:
String str = a + "";
//方式二:
String str = String.valueOf(a);

(2)把字符串转为基本数据类型

String转换成对应的基本类型 ,除了Character类之外,其他所有包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型,例如:

  • public static int parseInt(String s):将字符串参数转换为对应的int基本类型。

  • public static long parseLong(String s):将字符串参数转换为对应的long基本类型。

  • public static double parseDouble(String s):将字符串参数转换为对应的double基本类型。

或把字符串转为包装类,然后可以自动拆箱为基本数据类型

  • public static Integer valueOf(String s):将字符串参数转换为对应的Integer包装类,然后可以自动拆箱为int基本类型

  • public static Long valueOf(String s):将字符串参数转换为对应的Long包装类,然后可以自动拆箱为long基本类型

  • public static Double valueOf(String s):将字符串参数转换为对应的Double包装类,然后可以自动拆箱为double基本类型

注意:如果字符串参数的内容无法正确转换为对应的基本类型,则会抛出java.lang.NumberFormatException异常。

int a = Integer.parseInt("整数的字符串");
double d = Double.parseDouble("小数的字符串");
boolean b = Boolean.parseBoolean("true或false");

int a = Integer.valueOf("整数的字符串");
double d = Double.valueOf("小数的字符串");
boolean b = Boolean.valueOf("true或false");

2、数据类型的最大最小值

Integer.MAX_VALUE和Integer.MIN_VALUE
Long.MAX_VALUE和Long.MIN_VALUE
Double.MAX_VALUE和Double.MIN_VALUE

3、字符转大小写

Character.toUpperCase('x');
Character.toLowerCase('X');

4、整数转进制

Integer.toBinaryString(int i) 
Integer.toHexString(int i)
Integer.toOctalString(int i)

4 包装类对象的缓存问题

包装类缓存对象
Byte -128~127
Short -128~127
Integer -128~127
Long -128~127
Float 没有
Double 没有
Character 0~127
Boolean true和false
Integer i = 1;
Integer j = 1;
System.out.println(i == j);//true

Integer i = 128;
Integer j = 128;
System.out.println(i == j);//false

Integer i = new Integer(1);//新new的在堆中
Integer j = 1;//这个用的是缓冲的常量对象,在方法区
System.out.println(i == j);//false

Integer i = new Integer(1);//新new的在堆中
Integer j = new Integer(1);//另一个新new的在堆中
System.out.println(i == j);//false
    @Test
public void test3(){
Double d1 = 1.0;
Double d2 = 1.0;
System.out.println(d1==d2);//false 比较地址,没有缓存对象,每一个都是新new的
}

5 面试题

1、类型转换问题

    @Test
public void test4(){
Double d1 = 1.0;
double d2 = 1.0;
System.out.println(d1==d2);//true 和基本数据类型比较会自动拆箱,比较数据值
}
@Test
public void test2(){
Integer i = 1000;
double j = 1000;
System.out.println(i==j);//true 会先将i自动拆箱为int,然后根据基本数据类型“自动类型转换”规则,转为double比较
}
@Test
public void test(){
Integer i = 1000;
int j = 1000;
System.out.println(i==j);//true 会自动拆箱,按照基本数据类型进行比较
}

2、不可变对象

public class TestExam {
public static void main(String[] args) {
int i = 1;
Integer j = new Integer(2);
Circle c = new Circle();
change(i,j,c);
System.out.println("i = " + i);//1
System.out.println("j = " + j);//2
System.out.println("c.radius = " + c.radius);//10.0
}
/*
* 方法的参数传递机制:
* (1)基本数据类型:形参的修改完全不影响实参
* (2)引用数据类型:通过形参修改对象的属性值,会影响实参的属性值
* 这类Integer等包装类对象是“不可变”对象,即一旦修改,就是新对象,和实参就无关了
*/
public static void change(int a ,Integer b,Circle c ){
a += 10;
// b += 10;//等价于 b = new Integer(b+10);
c.radius += 10;
/*c = new Circle();
c.radius+=10;*/
}
}
class Circle{
double radius;
}

 接口

1 概述

生活中大家每天都在用USB接口,那么USB接口与我们今天要学习的接口有什么相同点呢?

USB是通用串行总线的英文缩写,是Intel公司开发的总线架构,使得在计算机上添加串行设备(鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等)非常容易。只须将设备插入计算机的USB端口中,系统会自动识别和配置。 有了USB,我们电脑需要提供的各种插槽的口越来越少,而能支持的其他设备的连接却越来越多。

那么我们平时看到的电脑上的USB插口、以及其他设备上的USB插口是什么呢?

其实,不管是电脑上的USB插口,还是其他设备上的USB插口都只是遵循了USB规范的一种具体设备而已。

根据时代发展,USB接口标准经历了一代USB、第二代USB 2.0和第三代USB 3.0 。

USB规格第一次是于1995年,由Intel、IBM、Compaq、Microsoft、NEC、Digital、North Telecom等七家公司组成的USBIF(USB Implement Forum)共同提出,USBIF于1996年1月正式提出USB1.0规格,频宽为1.5Mbps。

USB2.0技术规范是有由Compaq、Hewlett Packard、Intel、Lucent、Microsoft、NEC、Philips共同制定、发布的,规范把外设数据传输速度提高到了480Mbps,被称为USB 2.0的高速(High-speed)版本.

USB 3.0是最新的USB规范,该规范由英特尔等公司发起,USB3.0的最大传输带宽高达5.0Gbps(640MB/s),USB3.0 引入全双工数据传输。5根线路中2根用来发送数据,另2根用来接收数据,还有1根是地线。也就是说,USB 3.0可以同步全速地进行读写操作。

USB版本最大传输速率速率称号最大输出电流推出时间
USB1.0 1.5Mbps(192KB/s) 低速(Low-Speed) 5V/500mA 1996年1月
USB1.1 12Mbps(1.5MB/s) 全速(Full-Speed) 5V/500mA 1998年9月
USB2.0 480Mbps(60MB/s) 高速(High-Speed) 5V/500mA 2000年4月
USB3.0 5Gbps(500MB/s) 超高速(Super-Speed) 5V/900mA 2008年11月
USB 3.1 10Gbps(1280MB/s) 超高速+(Super-speed+) 20V/5A 2013年12月

下面是USB2.0和USB3.0标准下的各类接口示意图:

电脑边上提供了USB插槽,这个插槽遵循了USB的规范,只要其他设备也是遵循USB规范的,那么就可以互联,并正常通信。至于这个电脑、以及其他设备是哪个厂家制造的,内部是如何实现的,我们都无需关心。

这种设计是将规范和实现分离,这也正是Java接口的好处。Java的软件系统会有很多模块组成,那么各个模块之间也应该采用这种面相接口的低耦合,为系统提供更好的可扩展性和可维护性。

  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。继承是一个"是不是"的is-a关系,而接口实现则是 "能不能"的has-a关系。

    • 例如:你能不能用USB进行连接,或是否具备USB通信功能,就看你是否遵循USB接口规范

    • 例如:Java程序是否能够连接使用某种数据库产品,那么要看该数据库产品有没有实现Java设计的JDBC规范

2 定义格式

接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。

引用数据类型:数组,类,接口。

1、接口的声明格式

【修饰符】 interface 接口名{
   //接口的成员列表:
   // 静态常量
   // 抽象方法
   // 默认方法
   // 静态方法
   // 私有方法
}

示例代码:

interface Usb3{
   //静态常量
long MAX_SPEED = 500*1024*1024;//500MB/s
   
   //抽象方法
void read();
   void write();
   
   //默认方法
   public default void start(){
       System.out.println("开始");
  }
   public default void stop(){
       System.out.println("结束");
  }
   
   //静态方法
   public static void show(){
       System.out.println("USB 3.0可以同步全速地进行读写操作");
  }
}

2、接口的成员说明

接口定义的是多个类共同的公共行为规范,这些行为规范是与外部交流的通道,这就意味着接口里通常是定义一组公共方法。

在JDK8之前,接口中只允许出现:

(1)公共的静态的常量:其中public static final可以省略

(2)公共的抽象的方法:其中public abstract可以省略

理解:接口是从多个相似类中抽象出来的规范,不需要提供具体实现

在JDK1.8时,接口中允许声明默认方法和静态方法:

(3)公共的默认的方法:其中public 可以省略,建议保留,但是default不能省略

(4)公共的静态的方法:其中public 可以省略,建议保留,但是static不能省略

在JDK1.9时,接口又增加了:

(5)私有方法

除此之外,接口中不能有其他成员,没有构造器,没有初始化块,因为接口中没有成员变量需要初始化。

3、面试题拷问?

1、为什么接口中只能声明公共的静态的常量?

因为接口是标准规范,那么在规范中需要声明一些底线边界值,当实现者在实现这些规范时,不能去随意修改和触碰这些底线,否则就有“危险”。

例如:USB1.0规范中规定最大传输速率是1.5Mbps,最大输出电流是5V/500mA

USB3.0规范中规定最大传输速率是5Gbps(500MB/s),最大输出电流是5V/900mA

例如:尚硅谷学生行为规范中规定学员,早上8:25之前进班,晚上21:30之后离开等等。

2、为什么JDK1.8之后要允许接口定义静态方法和默认方法呢?因为它违反了接口作为一个抽象标准定义的概念。

静态方法:因为之前的标准类库设计中,有很多Collection/Colletions或者Path/Paths这样成对的接口和类,后面的类中都是静态方法,而这些静态方法都是为前面的接口服务的,那么这样设计一对API,不如把静态方法直接定义到接口中使用和维护更方便。

默认方法:(1)我们要在已有的老版接口中提供新方法时,如果添加抽象方法,就会涉及到原来使用这些接口的类就会有问题,那么为了保持与旧版本代码的兼容性,只能允许在接口中定义默认方法实现。比如:Java8中对Collection、List、Comparator等接口提供了丰富的默认方法。(2)当我们接口的某个抽象方法,在很多实现类中的实现代码是一样的,此时将这个抽象方法设计为默认方法更为合适,那么实现类就可以选择重写,也可以选择不重写。

3、为什么JDK1.9要允许接口定义私有方法呢?因为我们说接口是规范,规范时需要公开让大家遵守的

私有方法:因为有了默认方法和静态方法这样具有具体实现的方法,那么就可能出现多个方法由共同的代码可以抽取,而这些共同的代码抽取出来的方法又只希望在接口内部使用,所以就增加了私有方法。

3 实现接口

接口的使用,它不能创建对象,但是可以被实现(implements ,类似于被继承)。

类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements关键字。

1、实现接口语法格式

【修饰符】 class 实现类  implements 接口{
// 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写
// 重写接口中默认方法【可选】
}

【修饰符】 class 实现类 extends 父类 implements 接口{
   // 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写
// 重写接口中默认方法【可选】
}

注意:

  1. 如果接口的实现类是非抽象类,那么必须重写接口中所有抽象方法。

  2. 默认方法可以选择保留,也可以重写。

    重写时,default单词就不要再写了,它只用于在接口中表示默认方法,到类中就没有默认方法的概念了

  3. 不能重写静态方法

示例代码:

class MobileHDD implements Usb3{

//重写/实现接口的抽象方法,【必选】
public void read() {
System.out.println("读数据");
}
   public void write(){
       System.out.println("写数据");
  }
//重写接口的默认方法,【可选】
//重写默认方法时,default单词去掉
public void end(){
       System.out.println("清理硬盘中的隐藏回收站中的东西,再结束");
  }
}

2、如何调用对应的方法

  • 对于接口的静态方法,直接使用“接口名.”进行调用即可

    • 也只能使用“接口名."进行调用,不能通过实现类的对象进行调用

  • 对于接口的抽象方法、默认方法,只能通过实现类对象才可以调用

    • 接口不能直接创建对象,只能创建实现类的对象

public class TestInteface {
public static void main(String[] args) {
//创建实现类对象
MobileHDD b = new MobileHDD();

//通过实现类对象调用重写的抽象方法,以及接口的默认方法,如果实现类重写了就执行重写的默认方法,如果没有重写,就执行接口中的默认方法
b.start();
b.read();
b.stop();

//通过接口名调用接口的静态方法
MobileHDD.show();
}
}

3、练习

1、声明一个LiveAble接口

  • 包含两个抽象方法:

    • void eat();

    • void breathe();

  • 包含默认方法 default void sleep(),实现为打印“静止不动”

  • 包含静态方法 static void drink(),实现为“喝水”

2、声明动物Animal类,实现LiveAble接口。

  • void eat();实现为“吃东西”,

  • void breathe();实现为"吸入氧气呼出二氧化碳"

  • void sleep()重写为”闭上眼睛睡觉"

3、声明植物Plant类,实现LiveAble接口。

  • void eat();实现为“吸收营养”

  • void breathe();实现为"吸入二氧化碳呼出氧气"

4、在测试类中,分别创建两个实现类的对象,调用对应的方法。通过接口名,调用静态方法

定义接口:

public interface LiveAble {
   // 定义抽象方法
   public abstract void eat();
   public abstract void breathe();
   //定义默认方法
   public default void sleep(){
  System.out.println("静止不动");
  }
   //定义静态方法
   public static void drink(){
  System.out.println("喝水");
  }
}

定义实现类:

public Animal implements LiveAble {
//重写/实现接口的抽象方法
   @Override
   public void eat() {
       System.out.println("吃东西");
  }
   
   //重写/实现接口的抽象方法
   @Override
   public void breathe(){
       System.out.println("吸入氧气呼出二氧化碳");
  }
   
   //重写接口的默认方法
   @Override
   public void sleep() {
       System.out.println("闭上眼睛睡觉");
  }
}
public class Plant implements LiveAble {
//重写/实现接口的抽象方法
   @Override
   public void eat() {
       System.out.println("吸收营养");
  }
   //重写/实现接口的抽象方法
   @Override
   public void breathe(){
       System.out.println("吸入二氧化碳呼出氧气");
  }
}

定义测试类:

public class InterfaceDemo {
   public static void main(String[] args) {
       // 创建实现类(子类)对象  
       Animal a = new Animal();
       // 调用实现后的方法
       a.eat();
       a.sleep();
       a.breathe();
       
       //创建实现类(子类)对象
       Plant p = new Plant();
       p.eat();
       p.sleep();
       p.breathe();
       
       //通过接口调用静态方法
       LiveAble.drink();
  }
}
输出结果:
吃东西
闭上眼睛睡觉
吸入氧气呼出二氧化碳
吸收营养
静止不动
吸入二氧化碳呼出氧气
喝水

4 接口的多实现

之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。

实现格式:

【修饰符】 class 实现类  implements 接口1,接口2,接口3。。。{
// 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写
// 重写接口中默认方法【可选】
}

【修饰符】 class 实现类 extends 父类 implements 接口1,接口2,接口3。。。{
   // 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写
// 重写接口中默认方法【可选】
}

接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次

定义多个接口:

interface A {
   public abstract void showA();
   public abstract void show();
}

interface B {
   public abstract void showB();
   public abstract void show();
}

定义实现类:

public class C implements A,B{
   @Override
   public void showA() {
       System.out.println("showA");
  }

   @Override
   public void showB() {
       System.out.println("showB");
  }

   @Override
   public void show() {
       System.out.println("show");
  }
}

练习

1、声明第一个接口Runner,包含抽象方法:void run()

2、声明第二个接口Swimming,包含抽象方法:void swim()

3、声明兔子类,实现Runner接口

4、声明乌龟类,实现Runner接口和Swimming接口

interface Runner{
void run();
}
interface Swimming{
void swim();
}
class Rabbit implements Runner{

@Override
public void run() {
System.out.println("兔子跑得快");
}

}
class Tortoise implements Runner,Swimming{

@Override
public void swim() {
System.out.println("乌龟游得快");
}

@Override
public void run() {
System.out.println("乌龟跑的慢");
}

}

5 默认方法冲突问题

1、亲爹优先原则

当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法。代码如下:

定义接口:

interface A {
   public default void methodA(){
       System.out.println("AAAAAAAAAAAA");
  }
}

定义父类:

class D {
    public void methodA(){
        System.out.println("DDDDDDDDDDDD");
    }
}

定义子类:

class C extends D implements A {
// 未重写methodA方法
}
class B extends D implements A{
   //当然也可以选择重写
   public void methodA(){
       System.out.println("BBBBBBBBBBBB");
  }
}

定义测试类:

public class Test {
   public static void main(String[] args) {
       C c = new C();
       c.methodA();
       
       B b = new B();
       b.methodA();
  }
}
输出结果:
DDDDDDDDDDDD
BBBBBBBBBBBB

2、必须做出选择

当一个类同时实现了多个接口,而多个接口中包含方法签名相同的默认方法时,怎么办呢?

无论你多难抉择,最终都是要做出选择的。代码如下:

声明接口:

interface A{
public default void d(){
System.out.println("今晚7点-8点陪我吃饭看电影");
}
}
interface B{
public default void d(){
System.out.println("今晚7点-8点陪我逛街吃饭");
}
}

选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法。

class C implements A,B{
@Override
public void d() {
A.super.d();
}
}

选择自己完全重写:

class D implements A,B{
@Override
public void d() {
System.out.println("自己待着");
}
}

6 接口的多继承

一个接口能继承另一个或者多个接口,接口的继承也使用 extends 关键字,子接口继承父接口的方法。

定义父接口:

interface A {
   void a();
   public default void methodA(){
       System.out.println("AAAAAAAAAAAAAAAAAAA");
  }
}
interface B {
   void b();
   public default void methodB(){
       System.out.println("BBBBBBBBBBBBBBBBBBB");
  }
}

定义子接口:

interface C extends A,B{
   @Override
   public default void methodB() {
       System.out.println("CCCCCCCCCCCCCCCCCCCC");
  }
}

小贴士:

子接口重写默认方法时,default关键字可以保留。

子类重写默认方法时,default关键字不可以保留。

class D implements C{
@Override
public void a() {
System.out.println("xxxxx");
}
@Override
public void b() {
System.out.println("yyyyy");
}
}
class E implements A,B,C{//效果和上面的D是等价的
@Override
public void b() {
System.out.println("xxxxx");
}
@Override
public void a() {
System.out.println("yyyyy");
}
}

7 接口与实现类对象的多态引用

实现类实现接口,类似于子类继承父类,因此,接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是你new的实现类对象实现的方法体。

public class TestInterface {
public static void main(String[] args) {
Flyable b = new Bird();
b.fly();

Flyable k = new Kite();
k.fly();
}
}
interface Flyable{
   //抽象方法
void fly();
}
class Bird implements Flyable{
@Override
public void fly() {
System.out.println("展翅高飞");
}
}
class Kite implements Flyable{
@Override
public void fly() {
System.out.println("别拽我,我要飞");
}
}
原文地址:https://www.cnblogs.com/LzMingYueShanPao/p/14478428.html