java面向对象(下)-- 类的继承、方法的重写、super关键字、final关键字
继承的概念
在现实生活中,继承一般是指子女继承父类的财产。在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系。
例如:猫和狗都属于动物,程序中便可以描述为猫和狗都继承自动物,同理,波斯猫和巴厘猫继承自猫,而沙皮狗和斑点狗继承自狗,这些动物之间会形成一个继承体系,如图:
继承的特性
-
子类拥有父类非 private 的属性、方法。
-
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
-
子类可以用自己的方式实现父类的方法。
-
Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
-
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
在java中,类的继承是指在一个现有类的继承上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类,子类会自动拥有父类所有可继承的属性和方法。在程序中,如果想声明一个类继承另一个类,需要使用extends关键字。
1 //定义Animal类 2 class Animal { 3 String name;//定义name属性 4 //定义动物叫的方法 5 void shout() { 6 System.out.println("动物发出了叫声!"); 7 } 8 } 9 //Dog类继承Animal类 10 class Dog extends Animal{ 11 //定义一个定义name的方法 12 public void printName(){ 13 System.out.println("name = " + name); 14 } 15 } 16 //定义测试类 17 class Example { 18 public static void main(String[] args) { 19 Dog dog = new Dog(); //创建一个Dog类的实例对象 20 dog.name ="沙皮狗"; //为Dog类的属性name赋值 21 dog.printName(); //调用Dog的printName()方法 22 dog.shout(); //调用Dog继承来的shout()方法 23 } 24 }
运行结果:
Dog通过extends关键字继承了Animal类,这样Dog便是Animal类的子类。子类虽然没有定义name属性和shout()方法,但是却能访问者两个成员,也就是说,子类在继承父类的时候,会自动拥有父类所有的成员。
注意:
1.在java中,类只支持单继承,不允许多次继承,也就是说一个类只能有一个直接父类。
2.多个类可以继承一个父类,下面的情况是允许的
3.在java中,多层继承是可以的,即一个类的父类可以再去继承另外的父类。
4.在java中,子类和父类是一种相对的概念,也就是说一个类是某个类父类的同时,也可以是另一个类的子类。
方法的重写
在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。
在前面的例子中,Dog从Animal类继承了shout()方法,但是太抽象,这显然不能描述一种具体动物的叫声,为了解决这个问题,可以在Dog中重写父类Animal中的shout()方法,以满足需求。
1 //定义Animal类 2 class Animal { 3 //定义动物叫的方法 4 void shout() { 5 System.out.println("动物发出了叫声!"); 6 } 7 } 8 //Dog类继承Animal类 9 class Dog extends Animal{ 10 //定义狗叫的方法 11 void shout(){ 12 System.out.println("汪汪汪......"); 13 } 14 } 15 //定义测试类 16 class Example { 17 public static void main(String[] args) { 18 Dog dog = new Dog(); //创建一个Dog类的实例对象 19 dog.shout(); //调用Dog的shout()方法 20 } 21 }
运行结果:
子类对父类的方法进行重写后,只会调用子类重写的方法,并不会调用父类的方法
注意:子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限,如父类中的方法时public,子类的方法就不能是private的。
super关键字
当子类重写父类的方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题,在java中专门提供了一个super关键字用于访问父类的成员,例如访问父类的成员变量、成员方法和构造方法。
1.使用super关键字调用父类的成员变量和成员方法。
语法格式:super.成员变量
super.成员方法([参数1,参数2····])
1 //定义Animal类 2 class Animal { 3 String name = "动物"; 4 //定义动物叫的方法 5 void shout() { 6 System.out.println("动物发出了叫声!"); 7 } 8 } 9 //Dog类继承Animal类 10 class Dog extends Animal{ 11 String name = "沙皮狗"; 12 //重写父类的shout()方法 13 void shout(){ 14 super.shout(); 15 } 16 //调用打印name的方法 17 void printName(){ 18 System.out.println("name = " +super.name);//访问父类的成员变量 19 } 20 } 21 //定义测试类 22 class Example { 23 public static void main(String[] args) { 24 Dog dog = new Dog(); //创建一个Dog类的实例对象 25 dog.shout(); //调用Dog对象重写的shout()方法 26 dog.printName();//调用Dog对象的printName()方法 27 } 28 }
运行结果:
在子类Dog的shout()方法使用"super.shout()"调用了父类被重写的方法,在printName()方法中使用''super.name''访问的是父类的成员变量。
2.使用super关键字调用父类的构造方法。
语法格式:super([参数1,参数2·····])
1 //定义Animal类 2 class Animal { 3 public Animal(String name) { 4 System.out.println("我是一只"+name); 5 } 6 } 7 //Dog类继承Animal类 8 class Dog extends Animal{ 9 public Dog() { 10 super("沙皮狗"); 11 } 12 } 13 //定义测试类 14 class Example { 15 public static void main(String[] args) { 16 Dog dog = new Dog(); //实例化Dog对象 17 18 } 19 }
运行结果:
在实例化Dog对象时一定会调用Dog的构造方法,Dog类的构造方法被调用时父类的构造方法也被调用了。需要注意的是,通过super调用父类的构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次。
在子类的构造方法中通过super指定调用父类的哪个构造方法,如果没有指定,在实例化类对象时,会自动调用父类无参的构造方法,如果没特殊要求,尽量在类中定义一个无参的构造方法,避免被继承时出现错误。
super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
final关键字
final关键字可用于修饰类、变量和方法,它有“这是无法改变的”或者“最终”的含义,因此被final修饰的类、变量和方法将具有以下特性:
- final修饰的类不能被继承。
- final修饰的方法不能被子类重写。
- final修饰的变量(成员变量和局部变量)是常量,只能赋值一次
注意:
无论属性是基本类型还是引用类型,作用都是变量里面存放的“值”不可变
经常和static关键字一起使用,作为常量
-
基本类型,变量放的是实实在在的值,如1,“abc”等
-
引用类型,变量放的是个地址,所以用final修饰引用类型变量指的是它里面的地址不能变,即它只能指向初始时指向的那个对象,而不关心指向的对象内容的变化
所以修饰的变量必须被初始化