接口
生活中的接口:规范、规则
Java中的接口:规范、规则,如果要实现接口,必须要实现接口中的抽象方法。解决了类的单继承的局限性。
概念:
接口就是一种规范和约定,将来实现接口的实现类,必须遵守接口的规则去重写接口中的抽象方法。
接口还解决了Java中类只能单继承的局限性。
创建方式:
接口使用interface关键字,就是把类中的class换成interface
interface 接口名{}
实现接口:
实现接口用implements关键字
class 类 implements 接口名{
}
类实现接口后,要么这个类是抽象类,要么重写接口中的所有抽象方法
接口的特点:
1.接口的成员变量只能是常量,声明的时候,必须要赋值,不能改变
默认以 public static final 修饰
2.接口没有构造方法,所以接口不能实例化
3.接口中的普通方法,只能是抽象方法,默认以 public abstract修饰
package com.day10.interface1;
public interface Father {
//接口中默认的成员变量是常量
//默认以 public static final 修饰
String name="jack";
//接口中,不存在构造方法,所以不能创建对象
// public Father(){
//
// }
//接口中的普通方法只能是抽象方法
//起到一个约束性的作用
public abstract void code();
//接口中可以写静态方法,这个静态方法,必须要有具体的实现
public static void hello(){
System.out.println("接口中的静态方法");
}
//接口中还可以定义默认的default方法
default void show(){
System.out.println("接口中的默认方法");
}
}
package com.day10.interface1;
public interface Mather {
//Interface abstract methods cannot have body即不能有代码体
//接口中的普通方法,默认都是抽象方法
//不加public abstract也可以
void sing();
}
package com.day10.interface1;
//接口的实现类,
//要么是抽象类,
//要么重写所有父接口中的抽象方法
public class Son implements Father,Mather{
@Override
public void code() {
System.out.println("子类重写Father接口中的方法");
}
@Override
public void sing() {
System.out.println("子类重写Mather接口中的方法");
}
}
package com.day10.interface1;
public class Test {
public static void main(String[] args) {
//接口中的成员变量是静态常量,可以通过接口名直接调用
System.out.println(Father.name);
//接口中的成员变量是常量,不能重新赋值
//Father.name="Tom";
//接口中的静态方法可以通过名称直接调用
Father.hello();
//接口中的默认方法不能直接调用
//Father.show();
Son son = new Son();
//子实现类可以继承父接口中的default方法
son.show();
son.code();
}
}
接口中的静态方法、default方法
jdk8中,为了增加接口的可扩展性,对接口新增了static方法和default方法,可以增加接口的灵活性。
static方法,可以通过接口名调用。
default方法不能通过接口名调用,但是可以被实现类继承。
在jdk9中,可以声明private方法,为了提高接口中,内部代码的可重用性。
private可以在内部被调用,但是会将实现的细节对外隐藏。
面试题:接口和抽象类的相同点和不同点?
相同点:1.接口和抽象类都不能被实例化,主要用于被其他类实现和继承。
2.接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
不同点:
声明上:
抽象类:通过abstract关键字修饰
接口:interface 接口名{}
子类:
抽象类:子类使用extends关键字来继承抽象类,如果子类不是抽象类,则需要提供抽象类中所有声明的方法的实现。
接口:子类使用implements关键字来实现接口,需要提供接口中所有声明的方法的实现。
成员变量:
抽象类:既可以定义普通成员变量,也可以定义静态常量
接口:只能定义静态常量,不能定义普通成员变量
构造方法:
抽象类:可以有构造方法,构造方法不用来实例化,一般用来给子类访问
接口:没有构造方法,所以接口不能实例化
普通方法:
抽象类:可以有抽象方法,也可以有普通方法、静态方法
普通方法和静态方法的使用,可以和普通类的用法一样。
接口:只能包含抽象方法、静态方法、默认方法和私有方法,不能为普通方法提供方法实现
多态
概念
一个对象在不同时刻,体现出来的不同状态
Java中写法
父类引用指向子类的对象
格式:声明对象的时候
父类名 变量名 = new 子类名();
或者
父接口 变量名 = new 实现类名();
多态的前提
1.要求有继承或者接口的实现
2.要有方法重写
3.有父类/父接口的引用指向子类对象
成员访问特点
1.成员变量:编译看左边,运行看左边
2.成员方法:编译看左边,运行看右边
多态的好处
可以提升代码的维护性和扩展性
多态的弊端
父类不能使用子类特有的功能。
子类可以当作父类使用,父类不能当作子类使用
在Java的多态中,可以通过转型完成子类特有方法的调用
转型分为:
向上转型:向上转型就是多态,子类对象当作父类使用
写法:父类名 变量名 = new 子类名();
含义:右侧的子类对象,被当作父类看待、使用
比如:
Animal animal = new Dog();
创建一个Dog对象,当作Animal类看待、使用
向上转型一定是安全的,类似于基本类型的隐式转换
向下转型:子类被向上转型为父类后,想调用子类特有的功能, 需要将被当作父类的子类对象,还原成子类
写法:子类 变量 = (子类)向上转型的父类;
比如:
Animal animal = new Dog(); 先向上转型
Dog dog = (Dog)animal; 再向下转型
子类对象Dog被当作父类Animal使用,又将animal还原成Dog对象。
还原之后的dog对象,可以调用子类的特有功能。
向下转型的对象,必须是原对象本身,如果是别的对象,无法还原成自己的对象, 类似于,一个Cat对象,可以被当作Animal对象,但是不能被还原成一个Dog对象
多态的分类
编译时多态:靠方法重载体现。
方法重载具有不同的参数,当我们调用重载的方法的时候,会根据传入参数的不同,自动调用对应具体参数的方法。
运行时多态:靠方法重写体现。
运行时多态,在创建对象之后,调用方法的时候,才去确定调用的是哪个方法, 通过动态绑定来实现的。
package com.day10.duotai;
public class Father {
public String name="jack";
public int age=20;
public void show(){
System.out.println("父类的show方法");
}
public void say(){
System.out.println("父类的say方法");
}
}
package com.day10.duotai;
public class Son extends Father implements Mother{
public String name="tom";
public String gender="男";
@Override
public void show(){
System.out.println("子类重写父类的show方法");
}
public void hello(){
System.out.println("这是子类的hello方法");
}
@Override
public void sing() {
System.out.println("重写的Mother接口中的sing方法");
}
}
package com.day10.duotai;
public interface Mother {
void sing();
public static void show(){
System.out.println("这是父接口中的静态方法");
}
default void show1(){
System.out.println("父接口中的默认方法");
}
}
package com.day10.duotai;
public class Test {
public static void main(String[] args) {
//多态创建Father对象
Father f = new Son();
//多态调用
//调用属性,编译看左边,运行看左边
System.out.println(f.name);
System.out.println(f.age);
// System.out.println(f.gender);
//调用方法,体现了多态性,编译看左边,运行看右边
f.show();
f.say();
//f.hello();
//将被当作父类使用的子类对象,还原成子类对象
//调用子类特有的方法
Son son=(Son) f;
son.hello();
System.out.println(son==f);//true
//创建接口多态
Mother m = new Son();
//多态调用子类的sing方法
m.sing();
//接口中的静态方法,不能通过多态创建的对象调用
//只能通过接口名访问
// m.show();
//多态创建的接口对象,可以调用接口中的default方法
m.show1();
}
}