首先我们得了解什么是继承?
在生活中我们有子承父业,这就是一种继承。而在我们面向对象编程中也存在这种现象,其中被继承的类称为父类、基类或者是超类,继承人则称为子类或者派生类。
那么为什么要有继承?
继承是为了提高编程效率,达到代码复用的效果。
extends关键字
在Java语言中一个子类要继承父类需要使用extends关键字。
class father{
public int i;
public void test() {
System.out.println(this.i);
}
}
public class son extends father {
public static void main(String[] args){
son s = new son();
s.i = 1;
s.test();
}
}
- Java语言中一个子类只能有一个父类。
- 子类会继承父类的所有public方法和属性。
- 子类可以根据自己的需要对父类的方法进行改动,这种方法叫做重写(overwrite)。
- 对于父类private的方法和字段,子类是无法访问的。
- 子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用。
子类在new一个自己的实例化对象的时候,会先运行父类的构造方法,然后才运行自己的构造方法。
class father{
public father(){
System.out.println("我是父亲");
}
}
public class son extends father {
public son(){
System.out.println("我是儿子");
}
public static void main(String[] args) {
son son = new son();
}
}
如果一个类的方法和字段只想被同一个包内的类使用,那么public关键字就不能满足我们的需求,用private子类又不能访问,所以我们在这里引入protected关键字
protected关键字
- protected关键字修饰的属性和方法,子类和同一个包的其他类可以访问,其他类则不能访问。
package Demo1;
public class father {
protected int i;
protected void test(){
System.out.println(this.i);
}
}
//子类
package Demo1;
public class son extends father{
public static void main(String[] args){
son s = new son();
s.i = 10;
s.test();
}
}
子类可以访问
同一个包的可以访问:
package Demo1;
public class test extends father{
public static void main(String[] args){
father f = new father();
f.i = 20;
f.test();
}
}
其他包的类(没有继承father)不能访问:
- 子类和父类不在同一个包,那么在子类中实例化父类的对象也无法访问protected修饰的属性和方法,但是子类却可以访问,因为被protected修饰的属性和方法是可以被子类继承的。
在这里我们还要提到一个关键字——final关键字
我们知道final关键字修饰的属性是常量,不可更改该属性的值,但是当final修饰类的时候,则该类就不能被继承。
String类就是一个被final修饰的类(源码):
所以String类不能被继承
package Demo1;
public class test extends String{
public static void main(String[] args){
System.out.println("哦,有错误");
}
}
super关键字
我们基本都会使用super,可是你知道为啥super可以调用父类的方法吗?你知道super是个啥?
super表示获取到父类实例的引用。
super的作用:
- 访问父类的属性
- 访问父类的方法
- 访问父类的构造函数
this关键字和super关键字的区别:
突然想到好像没写重写
子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为重写。
一个重写的例子
public class animal {
String name;
public animal(String name){
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"是一个动物");
System.out.println(this.name+"喜欢吃"+food);
}
}
public class dog extends animal {
public dog(String name) {
super(name);
}
@Override
public void eat(String food) {
System.out.println(this.name+"是一条狗");
System.out.println(this.name+"喜欢吃"+food);
}
}
我们看到dog类继承了animal类,并且重写了父类的方法eat()。
关于重写的注意事项
- 普通方法可以重写,static修饰的方法不可重写
- 重写中子类的方法权限不能低于父类的方法权限
我们试试将dog类的eat()方法改为private,出现如下错误:
我们知道还有一种编程方式叫重载,那么重写和重载有什么不同?
再介绍一种很好用的方法——组合
组合也是为了达到代码复用的目的。
例如表示一个学校:
public class Student {
...
}
public class Teacher {
...
}
public class School {
public Student[] students;
public Teacher[] teachers;
}
相信大家在实际中用到组合这种方法的场景也很多,那么组合和继承有啥不同?
- 组合表示-has-a 的关系,例如刚才的例子一个学校有老师,有学生。
- 继承便是-is-a 的关系,例如“老虎是一种动物”。