继承
继承的概念
在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的类被称为子类,子类拥有父类可继承的属性和方法。在程序中想让一个类继承另一个类需要使用到extends关键字
[修饰符] class 子类名 extends 父类名{
// 代码
}
在实现类的继承中需要注意一些问题:
(1)在java中只支持单继承,不允许多重继承,一个类只能拥有一个直接父类
(2)多个类可以继承同一个父类
(3)在java中,多层继承是可以的,一个父类可以去继承另外的父类
class A{}
class B extends A{}
class C extends B{}
重写父类方法
在继承关系中,子类会自动继承父类中公共的方法,但是有时在子类中需要对继承的方法进行一些修改,即对父类方法进行重写。需要注意的是,子类重写方法需要和重写的方法有相同的方法名,参数列表和返回值的类型。
super关键字
当子类重写父类的方法后,子类对象无法直接访问父类重写的方法,在java中专门提供了一个super关键字来访问父类的成员,可以访问父类的成员变量,成员方法和构造方法。
package Demo01;
public class Test1 {
public static void main(String[] args) throws Exception {
Dog dog = new Dog(); //创建一个dog对象
dog.shout(); //调用dog对象重写的shout()方法
dog.printName(); //调用dog对象的printName()方法
}
}
class Animal{ //定义Animal类
String name = "动物";
void shout(){
System.out.println("动物发出叫声");
}
}
class Dog extends Animal{
String name = "犬类";
@Override
void shout(){
super.shout(); //访问父类的成员方法
}
void printName(){
System.out.println("name = "+super.name ); //访问父类的成员变量
}
}
//输出结果为
动物发出叫声
name = 动物
Dog类继承了Animal类,重写了shout()方法并重新定义了子类的name属性。
package Demo01;
public class Test1 {
public static void main(String[] args) {
Dog dog = new Dog(); //创建Dog的实例对象
}
}
class Animal{
public Animal(String name){
System.out.println("我是一只"+name);
}
}
class Dog extends Animal{
public Dog(){
super("野狗");//调用父类有参的构造方法
}
}
//输出结果为
我是一只野狗
创建Dog类对象时一定会调用Dog类的构造方法,被调用时执行了内部的super(“野狗”)方法,从而调用了父类的有参构造方法,需要注意的是通过super调用父类的构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次。在子类的构造方法中一定会调用父类的某个构造方法,这时可以在子类的构造方法中通过super关键字字指定调用父类的那个构造方法,如果没有指定,会默认调用父类的午餐构造方法,若父类未定义无参方法,则会报错。
final关键字
final关键字可用于修饰类,变量和方法,final修饰的类,变量和方法将具有一下特性
1.final修饰的类不可以被继承。
2.final修饰的方法不可被继承。
3.final修饰的变量是常量,只能赋值一次。(final修饰变量的同时需要赋予一个初始值)
抽象类以及接口
抽象类
抽象方法必须用abstract来修饰,并且在定义方法是不需要实现方法体,当一个类中包含了抽象方法,那么该类也必学用abstract关键字来修饰,这种类被称为抽象类。
//定义抽象类
[修饰符] abstract class 类名{
// 定义抽象方法
[修饰符]abstract 方法返回值类型 方法名 ([参数列表]);
// 其他方法或属性
}
要注意的是,包含抽象类方法的类必须定义为抽象类,但抽象类中可以不包含任何抽象方法,且抽象方法是不可以被实例化的。如果想调用抽象方法,需要创建一个子类,在子类中实现抽象类中的抽象方法。
定义抽象方法只需要在普通方法前加上abstract关键字,并且把大括号和大括号中的方法体去掉,然后在方法名后面添加分号即可。
接口
接口是一种特殊的抽象类,它不包含普通方法,其内部的都是抽象方法,在JDK8中,对接口进行了重新定于,接口中除了抽象方法,还有普通方法和静态方法。,默认方法用default修饰,静态方法用static修饰,并且这两种方法都允许有方法体。
定义接口时,使用interface关键字来申明
interface 接口名 [extends 父接口1 ,父接口2...]{
[public][static][final]常量类型 常量名=常量值;
[public][abstract]方法返回值类型 方法名([参数列表]);
[public]default 方法返回值类型 方法名([参数列表]){
// 默认方法的方法体
}
[public]static 方法返回值类型 方法名([参数列表]){
// 静态方法的方法体
}
}
抽象方法和默认方法能通过接口实现类对象,静态方法通过“接口名.方法名”的形式来调用,而实现抽象方法则需要定义一个接口的实现类,并实现接口中所有的抽象方法。一个类在继承另一个类的时候可以实现多个接口。
[修饰符] class 类名 [extends 父类名][implements 接口1,接口2,接口3...]{
// 实现接口中的所有抽象方法
}
下面通过案列来学习接口的实现与方法使用以及接口之间的继承关系
package Demo01;
public class Test1 {
public static void main(String[] args) {
System.out.println(Animal.getId());//通过接口名调用类方法
Dog dog = new Dog(); //创建Dog类的实例对象
dog.breathe(); //调用dog对象的breathe()方法
dog.run(); //调用dog对象的run()方法
dog.getType("犬科"); //通过接口实现类Dog的实例化对象,调用接口的默认方法
}
}
interface Animal{
final int ID = 1;
void breathe();
// 定义一个默认方法
default void getType(String type){
System.out.println("该动物属于"+type);
}
// 定义一个静态方法
static int getId(){
return Animal.ID;
}
}
//继承接口
interface landAnimal extends Animal{
void run();
}
//Dog类实现了Animal接口
class Dog implements landAnimal{
@Override
// 实现breathe方法
public void breathe(){
System.out.println("狗在呼吸");
}
public void run(){
System.out.println("狗在陆地上跑");
}
}
//输出结果为
1
狗在呼吸
狗在陆地上跑
该动物属于犬科
对接口的总结
(1)从jdk8开始,接口方法除了包含抽象方法之外,还包含了静态方法和默认的方法,默认方法和静态方法都可以有方法体,并且静态方法可以直接通过“接口名.方法名”来调用。
(2)当一个类实现接口时,如果这个类是抽象类,只需实现接口中的部分抽象方法即可,否则需要实现接口中所有的抽象方法。
(3)一个类可以通过implements关键字同时实现多个接口,被实现的多个接口之间要用英文逗号(,)隔开。
(4)接口之间可以通过extends关键字实现继承,并且一个接口可以同时继承多个接口,接口之间用英文逗号隔开。
(5)一个类在继承另一个类的同时还可以实现接口,此时,extends关键字必须位于implements关键字之前