接口就是多个类的公共规范
接口是一种引用数据类型,最重要的内容就是其中的抽象方法
如何定义一个接口的格式:
public interface 接口名称{
//接口内容
}
备注:换成了关键字interface之后,编译生成的字节码文件仍然是:.java --> .class
如果是java7,那么接口中包含的内容有:
如果是java8,还可以额外包含有:
如果是java9,还可以额外包含有:
在任何版本的java中,接口都能定义抽象方法
接口和抽象类的区别
注意事项:
public interface MyInterfaceAbstract {
// 这是一个抽象方法
public abstract void methodAbs1();
// 这也是抽象方法
abstract void methodAbs2();
// 这也是抽象方法
public void methodAbs3();
// 这也是抽象方法
void methodAbs4();
}
接口使用步骤:
public class MyInterfaceAbstractImpl implements MyInterfaceAbstract {
@Override
public void methodAbs1() {
System.out.println("这是第一个方法");
}
@Override
public void methodAbs2() {
System.out.println("这是第二个方法");
}
@Override
public void methodAbs3() {
System.out.println("这是第三个方法");
}
@Override
public void methodAbs4() {
System.out.println("这是第四个方法");
}
}
注意事项:
如果实现类并没有覆盖重写接口中所有抽象方法,那么这个实现类自己就必须是抽象类
public class Demo01Interface {
public static void main(String[] args) {
//创建实现类的对象使用
MyInterfaceAbstractImpl impl = new MyInterfaceAbstractImpl();
impl.methodAbs1();
impl.methodAbs2();
}
}
从java8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表){
方法体
}
备注:接口当中的默认方法可以解决接口升级的问题
public interface MyInterfaceDefault {
// 抽象方法
public abstract void methodAbs();
// 新添加了一个抽象方法,会对实现类造成影响
// public abstract void methodAbs2();
// 新添加的方法,改成默认方法
public default void methodDefault(){
System.out.println("这是新添加的默认方法");
}
}
两个实现类
public class MyInterfaceDefaultA implements MyInterfaceDefault {
@Override
public void methodAbs() {
System.out.println("实现了抽象方法,AAA");
}
}
public class MyInterfaceDefaultB implements MyInterfaceDefault {
@Override
public void methodAbs() {
System.out.println("实现了抽象方法,BBB");
}
@Override
public void methodDefault() {
System.out.println("实现类覆盖重写了接口的default方法");
}
}
public class Demo02Interface {
public static void main(String[] args) {
MyInterfaceDefaultA a = new MyInterfaceDefaultA();
a.methodAbs(); // 调用抽象方法,实际运行的是右侧实现类
//调用默认方法,如果实现类中没有,会向上找接口
a.methodDefault();
MyInterfaceDefaultB b = new MyInterfaceDefaultB();
b.methodAbs();
b.methodDefault();//实现类B覆盖重写了接口的默认方法
}
}
从java8开始,接口当中允许定义静态方法
格式:
public static 返回值类型 方法名称(参数列表){
方法体
}
提示:就是将abstract或者default换成static即可,带上方法体
public interface MyInterfaceStatic {
public static void methodStatic(){
System.out.println("这是接口的静态方法");
}
}
实现类
public class MyInterfaceStaticImpl implements MyInterfaceStatic {
// 没有抽象方法,不报错
}
静态方法的调用
public class Demo03Interface {
public static void main(String[] args) {
MyInterfaceAbstractImpl impl = new MyInterfaceAbstractImpl();
//错误写法!
// impl.methodStatic();
// 直接通过接口名称调用静态方法
MyInterfaceStatic.methodStatic();
}
}
注意:不能通过接口实现类的对象来调用接口当中的静态方法,静态跟对象没关系
正确用法:通过接口名称,直接调用其中的静态方法
格式:
接口名称.静态方法名(参数);
问题描述:
我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题
但是这个共有方法不应该让实现类使用,应该是私有化的
解决方案:
从java9开始,接口当中允许定义私有方法
public interface MyInterfacePrivateA {
public default void methodDefault1(){
System.out.println("默认方法1");
methodCommon();
}
public default void methodDefault2(){
System.out.println("默认方法2");
methodCommon();
}
private void methodCommon(){
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
public interface MyInterfacePrivateB {
public static void methodStatic1(){
System.out.println("默认方法1");
methodStaticCommon();
}
public static void methodStatic2(){
System.out.println("默认方法2");
methodStaticCommon();
}
private static void methodStaticCommon(){
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰
从效果上看,这其实就是接口的【常量】
格式:
public static final 数据类型 常量名称 = 数据值;
备注:
一旦使用final关键字进行修饰,说明不可改变
注意事项:
public interface MyInterfaceConst {
// 这其实就是一个常量,一旦赋值,不可以修改
public static final int NUM_OF_MY_CLASS = 10;
}
访问
public class Demo05Interface {
public static void main(String[] args) {
// 访问接口中的常量
System.out.println(MyInterfaceConst.NUM_OF_MY_CLASS);
}
}
使用接口时,需注意:
extends继承或者implements实现,是多态性的前提
代码当中体现多态性,其实就是一句话,父类引用指向子类对象
格式:
父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 = new 实现类名称();
在多态的代码中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找
public class Fu {
int num = 10;
public void method(){
System.out.println("父类方法");
}
public void methodFu(){
System.out.println("父类特有方法");
}
}
public class Zi extends Fu {
int num = 20;
@Override
public void method() {
System.out.println("子类方法");
}
public void methodZi(){
System.out.println("子类特有方法");
}
}
public class Demo01Multi {
public static void main(String[] args) {
// 使用多态的写法
//左侧父类的引用,指向了右侧子类的对象
Fu obj = new Zi();
obj.method(); //父子都有,优先用子
obj.methodFu(); //子类没有,父类有,向上找到父类
}
}
其实就是多态写法:
父类名称 对象名 = new 子类名称();
eg: Animal animial = new Cat();
含义:右侧创建一个子类对象,把它当作父类来看待使用
注意事项:向上转型一定是安全的,从小范围转向了大范围
向上转型有一个弊端:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容
解决方案:用对象的向下转型【还原】
格式:
子类名称 对象名 = (子类名称)父类对象;
含义:将父类对象,【还原】成为本来的子类对象
类似于: 基本数据类型的强制数据转换
父类
public abstract class Animal {
public abstract void eat();
}
猫——子类
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
狗——子类
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃屎");
}
public void watchHouse(){
System.out.println("狗看家");
}
}
main方法
public class down {
public static void main(String[] args) {
Animal animal = new Cat();//本来是猫,向上转型为动物
animal.eat();//猫吃鱼
/*
注意事项:
1. 必须保证对象本来创建的时候,就是猫,才能够向下转型为猫。
2. 如果对象创建的时候本来不是猫,现在非要向下转型为猫,就会报错(ClassCastException)。
*/
// 向下转型,进行【还原】动作
Cat cat = (Cat) animal;//本来是猫,意见被当作动物了,还原回来成为本来的猫
cat.catchMouse();//猫抓老鼠
//本来是猫,现在非要当成狗c
Dog dog = (Dog) animal;//错误写法!编译不会报错,但是会出现异常 java.lang.ClassCastException
}
}
知道一个父类引用的对象本来是什么子类
格式:
对象 instanceof 类名称
这将会得到一个boolean值结果,也就是判断前面的对象能不能当作后面类型的实例
public class Demo02Instanceof {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
if(animal instanceof Dog){
Dog dog =(Dog) animal;
dog.watchHouse();
}
if(animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
// instanceof 的作用,不知道传入参数的类型时使用
public static void giveMeAPat(Animal animal){
if(animal instanceof Dog){
Dog dog =(Dog) animal;
dog.watchHouse();
}
if(animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
}
public abstract interface USB {
public abstract void open();//打开设备
public abstract void close();//关闭设备
}
笔记本类
public class Computer {
public void powerOn() {
System.out.println("笔记本电脑开机");
}
public void powerOff() {
System.out.println("笔记本电脑关机");
}
// 使用USB设备的方法
public void useDevice(USB usb) {
usb.open();
usb.close();
if (usb instanceof Keyboard) {
Keyboard keyboard = (Keyboard) usb;
keyboard.type();
} else if (usb instanceof Mouse) {
Mouse mouse = (Mouse) usb;
mouse.click();
}
}
}
鼠标类
public class Mouse implements USB {
@Override
public void open() {
System.out.println("打开鼠标");
}
@Override
public void close() {
System.out.println("关闭鼠标");
}
public void click(){
System.out.println("点击鼠标");
}
}
键盘类
public class Keyboard implements USB {
@Override
public void open() {
System.out.println("打开键盘");
}
@Override
public void close() {
System.out.println("关闭键盘");
}
public void type(){
System.out.println("键盘输入");
}
}
Main方法
public class DemoMain {
public static void main(String[] args) {
Computer computer = new Computer();
computer.powerOn();
//准备一个鼠标,供电脑使用
//首先进行向上转型
USB usbMouse = new Mouse();
computer.useDevice(usbMouse);
//创建一个USB键盘
Keyboard keyboard = new Keyboard();
//方法参数时USB类型,传递进去的是实现类对象
computer.useDevice(keyboard);//正确写法!也发生了向上转型
computer.powerOff();
}
}