final关键字
首先明确,继承的出现打破了封装性,子类继承了父类,就能获得父类的属性和方法,有些封装好的东西就会全部暴露,不安全。所以对于一些特殊的类,为了强制保证其封装性,用final修饰,不允许继承。
final修饰的方法不允许重写
抽象类
当多个类中出现相同功能,但是功能主体不同,可以进行抽取。只抽取功能定义,不抽取功能主体。
public class Test {
public static void main(String[] args) {
new Student().speak();
}
}
class Person {
void speak() {
System.out.println("我是人类");
};
}
class Teacher extends Person {
void speak() {
System.out.println("我是老师");
}
}
class Student extends Person {
void speak() {
System.out.println("我是学生!");
}
}
如果子类中一定会重写某一方法,那么父类中此方法的主体已经没有任何意义,因为会被覆盖。所以父类中不需要方法主体,于是有:
void speak();
但是这种写法不符合规范,既不是方法,也不是类,于是有了一个关键字abstract 使这种写法合法,于是有:
abstract void speak();
这里只声明了函数名称,没有包含函数主体。
此时,如果实例化对象,然后调用此方法是没有意义的,所以要避免此类被实例化。解决方法就是将此类也用abstract修饰。即表明此类不能被实例化。总结规律:
1.抽象方法一定在抽象类中。
2.抽象方法和抽象类都必须被abstract关键字修饰。
3.抽象类不可以创建对象,因为里面的抽象方法没有主体,调用没有意义。
4.抽象类中的方法如果要被使用,必须有子类实现所有的抽象方法,然后建立子类对象调用。注意,子类如果没有复写父类的所有抽象方法,那么子类也必须用abstract修饰,子类还是一个抽象类。
实例:
public class Test {
public static void main(String[] args) {
}
}
/**
* 员工类:姓名 工号,工资,以及工作方法
*
* @author Nexts 2016年11月4日
*/
abstract class Worker {
private String name;
private String id;
private double salary;
public Worker(String name, String id, double salary) {
this.name = name;
this.id = id;
this.salary = salary;
}
abstract void work();
}
/**
* 经理也属于员工 但是多了一个奖金属性,也必须工作
*
* @author Nexts 2016年11月4日
*/
class Maneger extends Worker {
private int bonus;// 奖金
public Maneger(String name, String id, double salary, int bonus) {
super(name, id, salary);// 父类已经初始化三个变量,子类只需要自己初始化一个
this.bonus = bonus; // 子类一定会访问父类中构造函数,但是父类的构造函数已经重载。默认的空参数的构造函数已经不存在,需要手动指定
}
@Override
void work() {
}
}
/**
* 普通员工
*
* @author Nexts 2016年11月4日
*/
class Emplee extends Worker {
public Emplee(String name, String id, double salary) {
super(name, id, salary);
}
@Override
void work() {
}
}
关于子类父类的构造函数特点,参见上一篇文章: 子类父类构造函数特点
接口
可以简单的理解为:当一个抽象类中所有的方法都是抽象的时候,这个抽象类可以理解为一个接口,接口是一个特殊的抽象类。
接口特点:
接口中定义常量和抽象方法。
接口中成员都有固定的修饰符:
常量: public static final
方法: public abstract
如果不写,会默认自动加上。
接口可以被类多实现。Java不支持多继承,但是支持多实现。
public interface A {
void method1();
}
public interface B {
void method2();
}
class Test implements A, B {
@Override
public void method2() {
// TODO Auto-generated method stub
}
@Override
public void method1() {
// TODO Auto-generated method stub
}
}
如果多继承,就需要实现所有接口里面的方法。
为什么不支持多继承,反而支持多实现。
如果继承多个类,不同的类中包含同名方法,但是方法主体不同,子类就不会区分,但是在接口里面,即使多个接口有不同的方法,但是都没有方法主体,在实现接口之后自己写主体,有重名也没有关系。
但是需要注意:多个接口中的同名函数返回值必须相同,如果不相同,它的实现类就不能区分应该实现哪个方法。
多个接口中不能有同名的但是值不同的变量,会冲突。
接口和接口之间支持多继承。
接口中一般存放特有的方法,做功能扩展。共性特征放在父类中通过继承实现,特有功能放在接口中。