继承是所有OOP语言不可缺少的部分,在java中使用extends关键字来表示继承关系。当创建一个类时,总是在继承,如果没有明确指出要继承的类,就总是隐式地从根类Object进行继承。java语言不支持多重继承,也就是说,子类至多只能有一个父类。
1.继承的作用
通过继承,子类可以使用父类中的一些成员变量和方法,从而提高代码的重用性,提高开发效率。
2.哪些类不能被继承
被final修饰的类不能被继承。java中常见的不能被继承的类有:String,StringBuffer,StringBuilder,以及基本类型的包装类Double,Integer,Long等。
3.继承的实现
3.1 子类可以继承父类原有的属性和方法,也可以增加父类所不具备的属性和方法。
package zhishidian;
class Pet {
//父类的属性,有被private和public修饰的
private String name = "无名氏"; //昵称
private int health = 100; //健康值
public int love = 0; //亲密度
/**
* 无参构造方法
*/
public Pet(){
this.health = 95;
System.out.println("执行宠物的无参构造方法");
}
/**
* 有参构造方法
* @param name 昵称
*/
public Pet(String name){
this.name = name;
}
public String getName(){
return name;
}
public int getHealth(){
return health;
}
public int getLove(){
return love;
}
/**
* 输出宠物信息
*/
public void print(){
System.out.println("宠物的自白:\n我的名字叫"
+ this.name + ",我的健康值是" + this.health
+ ",我和主人的亲密程度是" + this.love + "。");
}
}
public class Dog extends Pet {
//子类可以增加父类所不具备的属性和方法
private String strain;//品种
public String getStrain(){
return strain;
}
/**
* 有参构造方法
* @param name 昵称
* @param strain 品种
*/
public Dog(String name, String strain){
//此处不能使用this.name=name; this.name继承自父类,但是被private修饰。
super(name);
this.strain = strain;
}
public static void main(String[] args) {
// 1.创建宠物对象pet并输出信息
Pet pet = new Pet("贝贝");
pet.print();
// 2.创建狗狗对象dog并输出信息
Dog dog = new Dog("欧欧","雪纳瑞");
//子类继承父类原有的属性和方法
dog.print();
System.out.println(dog.love);
}
}
3.2 直接重写父类中的方法。
重写(又叫覆盖)是继承的实现方式之一,也就是说只有在子类中才会出现方法的重写。重写是指在子类中保留父类成员方法的名称不变,参数列表不变,重写成员方法的实现内容,修改成员方法的返回值类型,或更改成员方法的存储权限。(修改存储权限只能从小的范围到大的范围修改,例如private可以修改为public,但是反向出错)
package com.java.test;
class ExtendsTest{
protected int adds(int a,int b){
int s=0;
s=a+b;
return s;
}
protected ExtendsTest doIt(){
return null;
}
}
public class tests extends ExtendsTest{
//重写成员方法的实现内容,修改成员方法的存储权限
public int adds(int a,int b){
return a;
}
//修改成员方法的返回值类型
protected tests doIt(){
return null;
}
//重构,只重写实现内容
protected int adds(int a,int b){
System.out.println("重构");
return a+b;
}
}
4.父类中不能被子类继承的内容
4.1 父类中的构造函数不能被子类继承
构造函数必须与类名一致,并且不能有返回值(包括void),主要作用是完成对象的初始化工作。构造函数总是伴随着new操作一起执行,且不能由程序的编写者直接调用,必须要由系统调用,且只在对象实例化时自动调用一次(普通方法可以被对象调用多次)。
当父类没有提供无参的构造函数时,子类的构造函数必须显式地调用父类的构造函数,如果父类提供了无参数的构造函数,子类可以不显式调用父类的构造函数,编译器默认会调用父类提供的无参构造函数。当有父类时,在实例化对象时会先执行父类的构造函数,然后执行子类的构造函数。
package zhishidian;
class FathersClass{
public FathersClass(String s){
System.out.println("父类的构造函数执行");
}
}
public class ConstructorTest extends FathersClass{
/*
* 当父类没有提供无参数的构造方法时,子类的构造函数(子类的构造函数可以有参数也可以没有参数)中必须显式
* 地调用父类的构造函数,使用super(参数名)调用,若没有显示调用,出错;
* 当父类提供了无参的构造方法时,子类不需要显式调用父类的无参构造方法,编译器会默认调用父类的构造方法;
* */
public ConstructorTest() {
super("s");
System.out.println("子类的构造函数执行");
}
public static void main(String[] args){
//ConstructorTest继承了FathersClass,继承父类就是要获得其成员变量成员方法,
ConstructorTest ct=new ConstructorTest();
}
}
运行结果:
父类的构造函数执行
子类的构造函数执行
父类中没有无参的构造函数,若在子类的构造方法中不使用super("s")进行显式调用父类的有参构造函数,出错:
4.2 子类只能继承父类的非私有(被public和protected修饰)的成员变量和方法。