Java是对现实社会的模拟,现实中有儿子可以继承父亲的财产,因此有了富二代的。 java中多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类中无需再定义这些属性和行为,只需要和抽取出来的类构成某种关系。如图所示:

其中,多个类可以称为子类,也叫派生类;多个类抽取出来的这个类称为父类、超类(superclass)或者基类。继承描述的是事物之间的所属关系,这种关系是:is-a 的关系。例如,图中猫属于动物,狗也属于动物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。
继承的好处
继承的格式
通过 extends关键字,可以声明一个子类继承另外一个父类,定义格式如下:

继承演示,代码如下:
现实中通用的属性和功能定义在父类中
/** 定义人类Person,做为父类*/
public class Person {//成员变量 对应 现实中的属性private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}// 成员方法 对应现实中的功能public void showInfo(){System.out.println("姓名:" +name +"年龄:" + age);}
}
定义Student子类
/** 定义Student类继承 人类Person*/
public class Student extends Person {//独有的方法public void study() {System.out.println("学习..");}
}
定义Teacher子类
/** 定义Teacher类继承 人类Person*/
public class Teacher extends Person{//独有的方法public void teaching() {System.out.println("教书..");}
}
定义测试类
public class Test {public static void main(String[] args) {//创建子类Student对象Student student = new Student();//调用从父类继承的方法 和变量student.setName("张三");student.setAge(18);student.showInfo(); //姓名:张三 年龄:18//调用本类独有的方法student.study(); //学习..//创建子类Teacher对象Teacher teacher = new Teacher();//调用从父类继承的方法 和变量teacher.setName("李四");teacher.setAge(28);teacher.showInfo(); //姓名:李四 年龄:28//调用本类独有的方法teacher.teaching(); //教书..}
}
//一个类只能有一个父类,不可以有多个父类。
class C extends A{} //ok
class C extends A,B... //error
class A{}
class B extends A{}
class C extends B{}

代码示例
/** 定义动物类Animal,做为父类*/
class Animal {// 定义name属性private String name;// 定义age属性public int age;// 定义动物的吃东西方法public void eat() {System.out.println(age + "岁的" + name + "在吃东西");}
}/** 定义猫类Cat 继承 动物类Animal*/
class Cat extends Animal {// 定义一个猫抓老鼠的方法catchMousepublic void catchMouse() {System.out.println("抓老鼠");}
}/** 定义测试类*/
public class Test {public static void main(String[] args) {// 创建一个猫类对象Cat cat = new Cat();// 为该猫类对象的name属性进行赋值//cat.name = "Tom";// 编译报错,不能直接访问父类中私有的成员// 为该猫类对象的age属性进行赋值cat.age = 2;// 调用该猫的catchMouse()方法cat.catchMouse(); //抓老鼠// 调用该猫继承来的eat()方法cat.eat(); //2岁的null在吃东西}
}
如果子父类中有重名的成员变量,子类中如何访问父类中的成员变量
代码示例
class Animal {private String name = "动物";public int age = 118;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}class Cat extends Animal {// private String name = "猫";public int age = 18;public void show() {// System.out.println("种类:"+ super.name); 编译报错,父类私有的成员变量子类不能直接访问//通过GetXxx方法访问System.out.println("种类:" + getName()); //种类:动物//直接访问变量名称使用的是本类中的System.out.println("我的年龄:" + age); //我的年龄:18// 使用super来访问父类中的非私有成员System.out.println("我父亲的年龄是:" + super.age); //我父亲的年龄是:118}
}public class Test {public static void main(String[] args) {Cat cat = new Cat();cat.show();}
}
我们说父类的所有方法子类都会继承,我们不能直接访问父类中私有的成员方法,但是可以间接访问。
class Animal {private void introduce() {System.out.println("我是动物老大");}public void info(){introduce();}}class Cat extends Animal {}public class Test {public static void main(String[] args) {Cat cat = new Cat();// cat.introduce(); 子类不能直接访问父类中私有的成员方法//间接访问cat.info(); //我是动物老大}
}
我们也可以直接调用父类中,非私有的成员方法
class Animal {public void eat() {System.out.println("我是动物,要吃东西");}}class Cat extends Animal {}public class Test {public static void main(String[] args) {Cat cat = new Cat();cat.eat(); //我是动物,要吃东西}
}
方法重写
当子类中出现了与父类一模一样的方法时,我们称之为方法重写 (Override) 。应用场景:子类觉得父类原来的实现方法不适合于子类。比如新的手机增加来电显示头像的功能,代码如下
class Phone {public void sendMessage() {System.out.println("发短信");}public void call() {System.out.println("打电话");}public void showNum() {System.out.println("来电显示号码");}
}//智能手机类
class NewPhone extends Phone {//重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能public void showNum() {//调用父类已经存在的功能使用supersuper.showNum();//增加自己特有显示姓名和图片功能System.out.println("显示来电姓名");System.out.println("显示头像");}
}public class Test {public static void main(String[] args) {// 创建子类对象NewPhone np = new NewPhone();// 调用父类继承而来的方法np.call();np.sendMessage();// 调用子类重写的方法np.showNum();}
}
注意事项:
@Override:写在方法上面,用来检测是不是有效的正确覆盖重写。这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。建议保留
必须保证父子类之间方法的名称相同,参数列表也相同。大部分情况下,我们只要保证要重写的方法一模一样就好,除非有特殊要求。任何情况下也不能违背下面几点原则
返回值类型:
子类方法的访问权限必须【大于等于】父类方法的访问权限修饰符。 小扩展提示:public > protected > 缺省 > private
几种特殊的方法不能被重写
当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?
首先我们要回忆两个事情,构造方法的定义格式和作用。
构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
构造方法的作用是初始化实例变量的,而子类又会从父类继承所有成员变量。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() ,表示调用父类的实例初始化方法,父类成员变量初始化后,才可以给子类使用。
代码示例
class Fu{public Fu() {System.out.println("我是父类中的无参数构造器");}
}
class Zi extends Fu{public Zi() {System.out.println("我是Zi类中的无参数构造器");}
}public class Test {public static void main(String[] args) {Zi zi = new Zi();/*输出结果:我是父类中的无参数构造器我是Zi类中的无参数构造器*/}}
如果父类没有无参构造怎么办?
class Fu{public int number;public Fu(int number) {System.out.println("我是父类中的有参数构造器");}
}
class Zi extends Fu{public Zi() { //此时子类代码报错。System.out.println("我是Zi类中的无参数构造器");}
}
解决办法:在子类构造器中,用super(实参列表),显示调用父类的有参构造解决。
class Fu {public int number;public Fu(int number) {System.out.println("我是父类中的有参数构造器: " + number);}
}class Zi extends Fu {public Zi() {super(1); //用super(实参列表),显示调用父类的有参构造解决System.out.println("我是Zi类中的无参数构造器");}
}public class Test {public static void main(String[] args) {Zi zi = new Zi();/*输出结果:我是父类中的有参数构造器: 1我是Zi类中的无参数构造器*/}}