六、Interface接口
1、介绍Interface
定义成员,通过implements来实现接口
Interface:接口仅仅只是有相同的行为特征,继承是"是不是"的关系,接口是"能不能"的关系,也支持多态,可以取代具体的子类或抽象父类作为参数或返回类型,那么就可以传入任何实现该接口的东西。
接口定义成员:
JDK7之前:只能定义全局常量(public static final)与抽象方法(public abstract),并且这些前缀可不写效果依旧。
interface Skill{ int flyTime = 100;//默认与右边相同:public static final int flyTime = 100; void fly();//默认与右边相同:public abstract void fly(); }
JDK8:除了全局常量和抽象方法,还可以定义静态、默认方法(技术角度来看是合法的,看起来违背了接口理念)
静态方法(static):可通过接口.静态方法直接调用方法,并执行方法体。
默认方法(default):可通过创建实现类(先实现接口)对象,调用接口的默认方法,执行方法体。
//接口 interface Skill{ //静态方法 static void walk(){ System.out.println("走路...."); } //默认方法:包含实现体 default void fly() { System.out.println("fly......"); } } //实现接口 class Person implements Skill{ } public class Main { public static void main(String[] args){ //直接接口调用 Skill.walk();//走路.... //实现类调用默认方法 new Person().fly();//fly...... } }
注意:接口没有构造器!!!
相关设计模式:代理模式、工厂模式
2、接口特性
实现多接口
格式:class 类名称 extends 类 implements 接口1,接口2{}
特点:弥补了Java单继承的局限性。
接口冲突案例:实现多个接口时都有同名同参数方法需要重写其方法
interface Skill{ //默认方法 default void fly() { System.out.println("skill接口的fly......"); } } interface Clothes{ //默认方法 default void fly() { System.out.println("clothes会飞......"); } } //实现两个接口 class Student implements Skill,Clothes { //重写方法 @Override public void fly() { System.out.println("student自己会飞"); } } public class Main { public static void main(String[] args){ new Student().fly();//student自己会飞 } }
说明:实现多个接口时,若是都有同名同参数,会出现接口冲突,需要对冲突方法进行重写,否则会报错!!
接口多继承
多继承:接口与接口之间是可以继承的,并且能够多继承!
interface AA{ void sleep(); } interface BB{ void walk(); } //这里使用到了extends继承 interface CC extends AA,BB{ }
注意:如果类实现多继承的接口,那么必须实现所有的抽象方法,才能进行实例化;没有实现抽象方法的则会变为抽象类。
匿名接口类
接口类的实现方式:就是创建一个类实现其接口。
匿名接口类:与匿名抽象类有点类似,如下
interface USB{ void start(); void stop(); } //Flash驱动 class Flash implements USB{ @Override public void start() { System.out.println("Flash开始准备工作....."); } @Override public void stop() { System.out.println("Flash结束传输工作....."); } } public class Main { public static void main(String[] args){ //接口类实例化 USB usb = new Flash(); //匿名接口类 (可作为参数传递到方法中,实现多态) new USB() { //也可用USB u = new USB(){实现} 多态形式接收 @Override public void start() { System.out.println("xxx驱动启动了....."); } @Override public void stop() { System.out.println("xxx驱动结束运行了....."); } }; } }
接口注意点(3点)
下面的接口与类是接下来注意点中的使用部分:
interface Skill{ //默认方法 default void fly() { System.out.println("skill接口的fly......"); } } class Person{ //与接口同名同参数方法 public void fly(){ System.out.println("Person的fly..."); } }
注意点如下:
实现接口,若是其接口有默认方法可以进行重写。
若是继承父类以及实现的接口中都有同名同参数的方法时,子类再没有重写情况下,会调用父类中的方法。
//继承Person以及实现Skill接口 extends写在前 class Student extends Person implements Skill{ } public class Main { public static void main(String[] args){ //调用的是父类的方法 new Student().fly();//fly...... } }
对于父类、接口以及自己重写的方法该如何去调用同名同参数的方法?三种
//继承Person以及实现Skill接口 extends写在前 class Student extends Person implements Skill{ @Override public void fly() { System.out.println("Student自己会飞啦"); } //测试调用不同的fly方法 public void executeMethod(){ fly();//调用自己重写的fly()方法 super.fly();//调用父类的fly()方法 Skill.super.fly();//调用实现接口的fly()方法,若是有其他接口也如这样调用 } } public class Main { public static void main(String[] args){ new Student().executeMethod(); } }
针对于父类、接口的属性获取方式:
class A{ public int m = 5; } interface B{ int m=6; } class C extends A implements B{ public C(){ System.out.println(super.m);//直接super.属性,与上面获取父类方法一致 System.out.println(B.m);//直接B.属性,因为接口中属性是static } } public class Main { public static void main(String[] args){ new C(); } }
3、接口实例演示
接口与多态应用
接口与我们生活中的USB接口也有类似的地方,会定义一些传输数据,以及例如传输数据、开始与结束的方法。
使用:满足多态,实际上定义了一种规范,在开发中很多都面向接口编程。
实例:接口的一种使用方式
//定义了USB的两个规范方法 interface USB{ void start(); void stop(); } //Flash驱动 class Flash implements USB{ @Override public void start() { System.out.println("Flash开始准备工作....."); } @Override public void stop() { System.out.println("Flash结束传输工作....."); } } //打印机驱动 class Printer implements USB{ @Override public void start() { System.out.println("Printer开始准备工作....."); } @Override public void stop() { System.out.println("Printer结束传输工作....."); } } //电脑主机 class Computer{ /** * 用于主机进行装配驱动并传输数据 * @param usb 多态,传入不同驱动 */ public void transferData(USB usb){ usb.start(); System.out.println("传输数据....."); usb.stop(); } } public class Main { public static void main(String[] args){ new Computer().transferData(new Flash()); System.out.println("更换设备...."); new Computer().transferData(new Printer()); } }
USB接口:相当于一种规范,让不同的驱动实现其中的固定步骤。
Flash、Printer实现类:用于实现USB接口的方法,两个驱动都有其不一样的启动与结束
Computer类:单独电脑类,其中传输方法中的参数就是需要指定驱动类传入,这样的话我想用哪个驱动传入进来即可
包含了多态的使用!
4、接口面试题
题1:一个类、一个接口,类与接口中有相同属性名,如何调用获取
interface A{ int x=0; } class B{ int x=1; } public class C extends B implements A{ public void pX(){ System.out.println(super.x); System.out.println(A.x); } public static void main(String[] args) { new C().pX(); } }
对于继承父类:super.属性
对于实现接口属性:接口名.属性 因为属性默认为public static final静态常量,所以可直接接口名获取
七、内部类
1、介绍内部类及分类
内部类:java中允许将一个B类声明放入到A类中,那么B就是内部类,A就是外部类。
//类,也称外部类 class A{ //内部类 class B{ } }
分类:
成员内部类:静态、非静态
局部内部类:方法内,代码块内,构造器内
分类举例如下:
class Person{ //1.1静态成员内部类 static class A{ } //1.2非静态成员内部类 class B{ } public void method(){ //2.1 局部内部类(局部方法中) class C{ } } { //2.2 局部内部类(代码块中) class D{ } } public Person(){ //2.3 局部内部类(构造器中) class E{ } } }
2、内部类属性方法调用
成员内部类:一方面作为外部类的成员,另一方面作为一个类
作为外部类成员:可调用外部类的接口;可static修饰;可使用四种权限符
作为一个类:可定义属性、方法、构造器等,可被final修饰,可被abstract修饰
①针对于static内部类:其内部方法中无法调用外部类的属性及方法,因为想要调用首先外部类必须是静态的,但是作为外部类是不能被static修饰的。
②针对于非static内部类:其内部方法可以调用外部属性与方法。
外部类属性与方法(static):外部类名.属性 或 外部类名.方法
外部类属性与方法(非static):外部类名.this.属性 或 外部类名.this.方法名
示例演示:
②中的调用外部类属于与方法(static):正常通过类名调用即可
class Person{ private static String name; public static void eat(){ System.out.println("eat吃东西"); } //内部类(非静态) class P{ private String name; public void eat(){ //调用外部类静态属性 Person.name = "123"; //调用外部类静态方法 Person.eat(); } } }
②中的调用外部类属于与方法(非static):需要类名+this,与之前实现接口调用属性有点类似
class Person{ private String name; public void eat(){ System.out.println("eat吃东西"); } //内部类(非静态) class P{ private String name; public void eat(){ //调用外部类属性(非静态) Person.this.name = "123"; //调用外部类方法(非静态) Person.this.eat(); } } }
3、三个主要问题
实例化内部类
内部类也分为两种:静态与非静态
class Person{ //静态内部类 static class A{ public void show(){ System.out.println("我是A的show()"); } } //内部类 class B{ public void show(){ System.out.println("我是B的show()"); } } }
根据上面的代码我们准备好了静态内部类以及内部类:
静态内部类实例:Person.A a = new Person.A(); 直接创建静态内部类实例
内部类实例:
//首先实例化外部类 Person person = new Person(); //接着再实例化内部类,很合理 Person.B b = person.new B();
区分内部类与外部类属性
见代码:之前内部属性调用也有说明
class Person{ //①外部类属性 String name="小明"; public class Bird{ //②内部类属性 String name="麻雀"; //③参数属性 void show(String name){ //输出外部类的name System.out.println(Person.this.name); //调用Person类中的this(相当于Bird)的name属性 //输出成员内部类Bird的name System.out.println(name); //直接name,就是离得最近的形参 //输出show中的形参name System.out.println(this.name); //this(指的是Person类) 调用这个类的属性 } } }
开发中内部类应用(Comparable接口)
【1】返回局部内部类实现comparable接口的匿名实例
class MyTest{ //返回一个非匿名接口实现类 public Comparable<Object> getComparable(){ //实现Comparable接口 class MyComparable implements Comparable<Object>{ @Override public int compareTo(Object o) { return 0; } } return new MyComparable(); } }
【2】不实现接口实现类,直接返回匿名接口类对象
class MyTest{ //返回一个匿名接口类 public Comparable<Object> getComparable(){ return new Comparable<Object>() { @Override public int compareTo(Object o) { return 0; } }; } }
参考资料
[1]. java类什么时候加载?,加载原理机制是怎么样的?
[2]. 书籍《head first java 2.0》