初识继承
继承的概念有点抽象,让我们先看看下面这个例子
package inherit;
public class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"正在吃"+food);
}
}
class Cat{
String name;
public Cat(String name) {
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"正在吃"+food);
}
public void grab(){
System.out.println(this.name+"捉老鼠");
}
}
class Bird{
String name;
public Bird(String name) {
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"正在吃"+food);
}
public void fly(){
System.out.println(this.name+"正在飞");
}
}
可以看出上面的代码存在许多重复的部分,按道理说所有Animal的类都应该具备name属性以及eat这个方法。
那么有没有一种方法可以使bird,cat可以使用animal中的name属性以及eat这个方法呢?
继承就可以实现这种功能
比如,Cat is an Animal,Bird is An Animal,当类和类之间满足一个类is a 另一个类时,一定存在继承关系。此时我们就可以让 Cat 和 Bird 分别继承 Animal 类, 来达到代码重用的效果.
通过继承我们可以将上面的代码进行缩减
package inherit;
class Animal {
String name;
public Animal() {
}
public Animal(String name) {
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"正在吃"+food);
}
}
class Cat extends Animal{
public Cat(String name) {
this.name = name;
}
public void grab(){
System.out.println(this.name+"捉老鼠");
}
}
class Bird extends Animal{
public Bird(String name) {
this.name = name;
}
public void fly(){
System.out.println(this.name+"正在飞");
}
}
public class Test {
public static void main(String[] args) {
Cat cat=new Cat("猫猫");
Bird bird=new Bird("小鸟");
cat.eat("鱼");
bird.eat("虫");
}
}
继承的规则
- 继承用extends关键字表示:class 子类 extends 父类
- 一个子类只能继承一个父类(单继承),java中不允许多继承,extands后面只能跟一个父类,允许多层继承
- 子类会继承父类的所有属性和方法,有显示继承(public 属性和方法可以直接使用),也有隐式继承(private属性和方法),其实子类也继承了这个属性和方法,但是无法直接使用
明白了继承的规则之后,让我们来思考一个问题,若此时子类和父类中存在同名属性或方法时,访问的到底是子类还是父类呢?
让我们看看下面这段代码
由此可见当子类与父类属性与方法重名的时候,优先访问子类的属性和方法,当子类中没有这个属性时才会访问父类的
super关键字的使用
看了上面的代码之后,相信你可能会有这样的疑问,当子类与父类属性和方法重名时,若我想访问父类的属性和方法该怎么办?
此时,super关键字就派上用场了
package inherit;
class Base { // 父类
int a = 5;
int b = 100;
public void method() {
System.out.println("这是父类的普通方法");
}
}
class Derived extends Base { // 子类通过extends关键字继承父类
int a = 10;
int c = 1000;
public void test () {
System.out.println("当调用子类和父类同名的成员变量a时,默认打印的是:" + this.a);
System.out.println("当调用子类和父类同名的成员变量a时,使用super关键字打印的是:" + super.a);
}
}
public class Test3 {
public static void main(String[] args) {
Derived derived = new Derived();
derived.test();
}
}
注意:
当有继承关系时this关键字默认再当前类中寻找同名属性,若没找到,继续向上寻找父类中是否有同名属性
super关键字修饰属性
表示从父类中寻找同名属性,上面的代码就展示了这个过程。
若直接父类不存在同名属性再向上寻找
class A{
int a=6;
}
class B extends A{
int b=1;
}
class C extends B{
int a=5;
public void test(){
System.out.println(super.a);
}
}
public class Test2 {
public static void main(String[] args) {
C c=new C();
c.test();
}
}
//输出6
super关键字修饰方法
- 修饰构造方法
package inherit;
class Person{
String name;
int age;
public Person() {
System.out.println("Person的无参构造");
}
}
class Chinese extends Person{
public Chinese() {
//编译器会自动在子类构造函数的第一句加上 super(); 来调用父类的无参构造器
//此时可以省略不写。如果想写上的话必须在子类构造函数的第一句
System.out.println("Chinese的无参构造");
}
}
public class Test4 {
public static void main(String[] args) {
Chinese chinese=new Chinese();
}
}
注意:当我们要产生一个子类对象时,默认先产生一个父类对象,即调用子类构造方法前默认先调用父类构造方法,通过在子类构造方法的第一行写上super(参数)
package inherit;
class Person{
String name;
int age;
public Person(String name) {
this.name = name;
System.out.println("Person的一个有参构造,name是:"+name);
}
}
class Chinese extends Person{
public Chinese(String name) {
super(name);//父类没有无参构造,必须在子类构造方法的第一行,显示地写上super(参数)
System.out.println("Chinese的有参构造");
}
}
public class Test4 {
public static void main(String[] args) {
Chinese chinese=new Chinese("小明");
}
}
注意:若父类不存在无参构造则,子类构造方法的首行必须使用super(有参构造)
- 修饰普通方法
与修饰属性类似,直接从父类中寻找同名方法
package inherit;
class Person{
String name;
int age;
// public Person() {
// System.out.println("Person的无参构造");
// }
public Person(String name) {
this.name = name;
System.out.println("Person的一个有参构造,name是:"+name);
}
public void fun(){
System.out.println("Person的一个普通方法");
}
}
class Chinese extends Person{
// public Chinese() {
// //编译器会自动在子类构造函数的第一句加上 super(); 来调用父类的无参构造器
// //此时可以省略不写。如果想写上的话必须在子类构造函数的第一句,
// System.out.println("Chinese的无参构造");
// }
public Chinese(String name) {
super(name);
System.out.println("Chinese的有参构造");
}
public void test(){
super.fun();//调用父类的普通方法
}
}
public class Test4 {
public static void main(String[] args) {
Chinese chinese=new Chinese("小明");
chinese.test();
}
}
注意:
与this不同,super不能指代当前父类的对象引用