抽象类和接口
抽象类和接口都是为了将方法进行抽象,然后让子类去实现,所以定义抽象方法就是两者第一个相同点;
这种父类是没有必要去创建实例对象的,所以它们第二个相同点就是不能创建本类对象,只能由子类去实例化对象。
两者最明显的差异点,就是子类要扩展它们时,对抽象类用的是 extends 关键字,我们称之为继承,接口用的是 implements 关键字,我们称之为实现,这是关键字和称呼的不同,本质都一样,抽象类可以去实现接口,接口只能继承接口,不能继承类,同时,一个类最多只能继承一个父类,但可以实现多个接口,所以当我们发现既可以用抽象类,又可以用接口的时,尽量去使用接口,这样灵活度会更高。
抽象类更进一步抽象就诞生了接口,接口比抽象类更纯粹,没有成员属性,只有方法,子类实现接口后,唯一能做的就是重写方法,不像抽象类,子类继承抽象类之后,连带着将父类的成员属性,连带着将父类的成员属性也继承过来了,这里就是两者的又一差异点,
抽象类可以定义成员属性,而接口不能定义成员属性,只能定义静态属性,而且只能用 final 关键字,定义静态常量,不能定义静态变量,接口除了成员属性外还没有构造器,可以说是非常纯粹了,说白了,接口是只有方法和静态常量的类。
抽象类不能被实例化,还要个构造器做什么?
它的用处就是:限定子类的构造行为。
抽象类可以将构造器,定义好几个参数,子类要想实例化则必须,想办法传入这几个参数才行。
版本差异:
其实接口在 JDK1.8 之前更加的纯粹,那时接口只能定义抽象方法,不能自己实现方法,不能定义静态方法,到了 Java8 才可以定义静态方法,以及可以用 default 关键字来实现方法。
public interface Runnable{
void run();
default void defaultMethod(){
System.out.println("default 方法");
}
static void staticMethod(){
System.out.println(" 静态方法");
}
}
为啥在 java 8 加了这个特性呢?
因为java8
许多原有的接口,新增了很多的方法,这些新增的方法会影响到之前的子类,
如果你继承了某个接口,突然接口新增了一个方法,而你没有去实现,你的子类就会编译失败,为了保证向下兼容性,java8
就退出了 default
关键字,被default
关键字修饰的方法,就不是抽象方法了,也就不会强制要求,已有的子类去实现方法,default 方法
出现后,大家发现还挺好用!
public interface Runnable {
void run();
default void defaultMethod() {
privateMethod();
privateMethod();
privateMethod();
}
private void PrivateMethod() {
System.out.println("私有方法")
}
}
就大量在接口中,去实现一些默认逻辑,可是一个方法中实现复杂逻辑,就会导致代码难以维护,于是 java9
又推出了一个新特性,那就是能在接口中,定义private
方法,这样就可以将一些内部逻辑拆开。
可以发现越到后面,抽象类和接口的差异就越来越小,
那什么时候该用抽象类,什么时候该用接口?
很好判断,当你需要让子类继承成员变量,或者需要控制子类的实例化,否则你就用接口,
抽象类(abstract class) | 接口(interface) | |
---|---|---|
定义 | 包含抽象方法的类 | 主要是抽象方法和静态常量的类 |
组成 | 构造器 抽象方法 普通成员方法,成员变量 静态方法,静态常量 常量 |
静态常量 抽象方法 default 方法 ,静态方法 (Java 8) 私有方法(Java 9) |
使用 | 子类继承抽象类(extends) | 子类实现接口(implements) |
关系 | 子类只能继承一个抽象类 抽象类可以实现多个接口 |
子类可以实现多个接口 接口不能继承类,但可以继承多个接口 |
选择 | 如果要继承父类的成员变量,或者需要控制子类的实例化,则选抽象类 | 优先选择接口,避免单继承的局限 |
接口实例化
1、接口不能直接实例化对象
学习接口时就知道它与类的区别:接口不能用于实例化对象。但是可以在 Java 中,使用接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
public interface TestInterface{}
TestInterface testInterface = new TestInterface();//这种肯定是不允许的
2、实现接口的子类可以通过创建对象赋值给接口
接口不能实例化,用接口的实现类可以实例化,将实现类的对象在内存中的地址指向接口,这个接口就可以使用了。 父类引用指向子类对象。
public interface Anim{}
public class Cat implements Anim {}
Anim anim= new Cat(); //这种是可以的,声明变量被绑定在一个以此接口实现的对象
List, Set, Map 都是接口,使用时先实现,List
接口可以被声明出来,但决不能实例化,它可以作为子类的句柄指向子类的实例。
3、子类创建对象赋值给接口后,接口再赋值给子类需要强制转换
Anim anim= new Cat();
Cat cat=(Cat)anim;
本文来自博客园,作者:走马!,转载请注明原文链接:https://www.cnblogs.com/zou-ma/p/16070900.html
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术