目录
一、抽象类
1.1 抽象方法
当一个方法只有方法的声明,没有方法的实现时,这个方法就只能被 abstract 关键字修改。而被 abstract 关键字修饰的方法就叫抽象方法。
abstract class Father {
String name;
public abstract void sayHi();
}
class Son extends Father {
public Son() {
}
public Son(String name) {
this.name = name;
}
public void sayHi() {
System.out.println(name);
}
}
public class FinalDemo {
public static void main(String[] args) {
Son son = new Son("小华");
son.sayHi();
}
}
当父类中声明的方法,但又不确定子类如何去实现这个方法时,就需要将父类中的方法定义为抽象方法。此时,父类中的这个抽象方法就是一种约定,或者叫规则。
1.2 抽象类的定义
一个类如果被 abstract 关键字修饰,那么这个类就叫抽象类。抽象类必须有子类,因为抽象类不能直接实例化。
abstract class Father {
String name;
public abstract void sayHi();
public abstract void sayBye();
}
abstract class Son extends Father {
public Son() {
}
public Son(String name) {
this.name = name;
}
/* public void sayBye() {
}*/
public void sayHi() {
System.out.println(name);
}
}
如果某个子类继承了抽象类,那么它必须实现抽象类中的所有抽象方法,如果没有实现所有的抽象方法,那么它也只能是抽象类。
注意:因为被final修饰的类必须不能被继承,而被abstract关键字修饰的类必须有子类。所以它们两个不能同时使用。即抽象类不能被final修饰。
二、接口
2.1 接口的定义
如果一个抽象类中所有的方法都是抽象方法,那么这个类就无需定义成抽象类,而是定义为接口。
在 JDK1.8 之前,接口中只能声明抽象方法,而在 JDK1.8 中定义默认方法和静态方法,这两种方法都是实现了的。如果定义为接口,那么需要使用 interface 关键字来进行修饰。例如:
public interface InterfaceDemo {
public static final String company = "open";
public abstract void say();
public abstract void show();
public abstract int getAge();
}
2.2 接口的使用
在上面的接口,所有的方法都是抽象方法。对接口而言,由于都是抽象方法,因此,对象 public abstrace 关键字是可以省略。
public interface InterfaceDemo {
String company = "open";
void say();
void show();
int getAge();
}
接口中的方法都是抽象的,公共的方法;接口的属性都是静态常量。
在 JDK1.8中,定义默认方法和静态方法。默认方法是使用 defalut 关键字来修饰的,而静态方法是使用 static 关键字来修饰的。
public interface InterfaceDemo {
String company = "open";
void say();
void show();
int getAge();
default void run() {
System.out.println("run() 方法,它是一个默认方法");
}
static String print(String str) {
return str.toUpperCase();
}
}
接口定义后,不能直接实例化,需要有子类,子类通过implements关键字来实现接口。
public class InterADemo implements InterA {
@Override
public void say() {
System.out.println("say()");
}
@Override
public void show() {
System.out.println("show()");
}
@Override
public int getAge() {
return 18;
}
public static void main(String[] args) {
InterADemo id = new InterADemo();
id.say();
id.show();
System.out.println(id.getAge());
id.run();
}
}
2.3 接口与抽象类的异同
2.3.1 相同点
-
接口和抽象类都不能直接实例化,都需要有子类
-
它们都是多态前提,多态前提是要么继承,要么实现,另一个就是要重写
2.3.2 不同点
-
抽象类是使用 abstract 关键字来修饰,而接口是使用 interface 关键字来修饰
-
抽象类子类使用 extends 来继承,而接口的子类是使用 implements 来实现
-
抽象类中是可以有抽象方法也可以没有抽象方法,但接口中不能有非抽象方法
-
抽象类中可以有构造方法,而接口中是没有构造方法的
-
抽象类中的属性可以不是常量,而接口中所有属性都是常量
-
子类只能继承一个父类,但是可以实现多个接口。如果一个类既要继承又要实现,那么是先继承后实现
例如:
abstract class AbsTest {
private String name;
public final int age = 18;
public AbsTest() {
}
public AbsTest(String name) {
this.name = name;
}
}
interface InterB {
String name = "张三";
// 在接口中不允许有构造方法
/*public InterB() {
}*/
}
interface InterC {
}
interface InterD extends InterC {
}
public class AbstractDemo extends AbsTest implements InterB, InterC {
}
在上面的例子中我们知道,接口与接口也可以通过extends进行继承。
注意:
在接口中是支持多继承的
interface InterB {
String name = "张三";
// 在接口中不允许有构造方法
/*public InterB() {
}*/
}
interface InterC {
}
interface InterD extends InterC, InterB {
}
这是为什么呢?
1)对于普通的类:
// Java中为什么不支持多继承
class ClassA {
public void show() {
System.out.println("ClassA.show");
}
}
class ClassB {
public void show() {
System.out.println("ClassB.show");
}
}
public class ExtendsDemo extends ClassA, ClassB {
public static void main(String[] args) {
ExtendsDemo ed = new ExtendsDemo();
ed.show();
}
}
由于JVM不知道调用show()方法时执行的是哪个类中的,所以Java避免这种不确定因素,不支持多继承。
2)在接口中;
// 接口支持多继承
interface InterAA {
void show();
}
interface InterBB {
void show();
}
interface InterCC extends InterAA, InterBB {
void show();
}
public class ExtendsDemo2 implements InterCC {
@Override
public void show() {
System.out.println("ExtendsDemo2.show");
}
}
在接口中支持多继承的原因是:接口中的方法只是声明没有实现,也就是说,在接口中只是定义一种规范,具体的实现在子类中完成。所以就不存在不确定的因素,所以支持多继承 。