继承
1. 继承的概念
在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关联体系。
在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称为子类,现有类被称作父类或基类,子类会自动拥有父类所有可继承的属性和方法。
在程序中,如果想声明一个类继承另一个类,需要使用extends关键字
[修饰符] class 子类名 extends 父类名{
//代码
}
class Animal{
String name;
void speak(){
System.out.println("发出声音");
}
}
class Dog extends Animal{
void printName(){//打印名字
System.out.println("名字是:" + name);
}
}
public class testji {
public static void main(String[] args) {
Dog dog = new Dog();
//子类会自动拥有父类所有可继承的属性和方法
dog.name = "二哈";
dog.printName(); //调用dog对象的printName()方法
dog.speak(); //调用Dog类继承来的speak()方法
}
}
2. 注意
2.1 Java中类只支持单继承,一个类只能有一个直接父类
2.2 多个类可以继承同一个父类
class A{}
class B extends A{}
class C extends B{}
2.3 Java中允许多层继承
class A{}
class B extends A{}
class C extends B{}//类C继承类B,类C是类B的子类,也是类A的子类
2.4 子类和父类是一种相对的概念
一个类是某个类的子类的同时,也可以是另一个类的父类
3.重写父类方法
在继承关系中,子类会自动继承父类中公共的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写
子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表和返回值类型
class Animal{
void speak(){
System.out.println("发出声音");
}
}
class Dog extends Animal{
void speak(){
System.out.println("汪 汪 汪");
}
}
public class testji {
public static void main(String[] args) {
Dog dog = new Dog();
dog.speak();//调用Dog类重写的speak()方法
}
}
4. 注意
子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限
5.super 关键字
当子类重写父类的方法后,子类对象将无法直接访问父类被重写的方法。因此,Java中提供了一个 super 关键字来访问父类的成员,例如访问父类的成员变量、成员方法和构造方法。
5.1 调用父类的成员变量和成员方法
class Animal{
String name = "小动物";
void speak(){
System.out.println("发出声音");
}
}
class Dog extends Animal{
String name = "小狗";
void speak(){
super.speak();
}
void printName(){
System.out.println(super.name);
}
}
public class testji {
public static void main(String[] args) {
Dog dog = new Dog();
dog.printName();
dog.speak();
}
}
5.2 调用父类的构造方法
class Animal{
public Animal(String name){
System.out.println("我是一只:" + name);
}
}
class Dog extends Animal{
String name = "小狗";
public Dog(){
super("二哈");
}
}
public class testji {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
6. 注意
6.1 super 调用父类构造方法的代码必须位于子类构造方法的第一行
6.2 子类在构造的时候,需要先帮助父类来进行构造
6.3 父类有构造方法时,子类也要有,如果子类没有,系统会默认有一个
6.3 字段重名时,优先访问自己内部的
7. Object类
在Java中提供了一个Object类,它是所有类的父类,即每个类都直接或间接继承自该类。当定义一个类时,如果没有使用 extends 关键字为这个类显式地指定父类,那么该类会默认继承 Object 类
方法声明 | 功能描述 |
---|---|
boolean equals(Object obj) | 判断某个对象与此对象是否相等 |
final Class<?> getClass() | 返回此Object的运行时类 |
int hashCode() | 返回该对象的哈希码值 |
String toString() | 返回该对象的字符串表示 |
void finalize() | 垃圾回收器调用此方法来清理没有被任何引用变量所引用对象的资源 |
在实际开发中,可以重写Object的toString() 方法来返回一些特有的信息
8. final 关键字
final关键字可用于修饰类、变量和方法,被final修饰的类、变量和方法将具有以下特性:
- final 修饰的类不能被继承
- final 修饰的方法不能被子类重写
- final 修饰的变量(成员变量和局部变量)是常量,只能赋值一次
8.1 修饰类 —— final 修饰的类不能被继承
8.2 修饰方法 —— final 修饰的方法不能被子类重写
8.3 修饰变量 —— final 修饰的变量(成员变量和局部变量)是常量,只能赋值一次
- final 修饰局部变量时,可以先声明再进行一次赋值
- final 修饰成员变量时,必须在声明的同时进行赋值,否则编译出错
9.抽象类和接口
9.1抽象类
当定义一个类时,常常需要定义一些方法来描述该类的行为特征,但有时这些方法的实现方式无法确定。
因此Java提供了抽象方法,抽象方法必须使用 abstract 关键字来修饰,并且在定义方法时不需要实现方法体。当一个类中包含了抽象方法,那么该类也必须使用 abstract 关键字来修饰,这种使用 abstract 关键字修饰的类就是抽象类。
abstract class Animal{
//定义抽象方法
abstract void speak();
}
class Dog extends Animal{
void speak(){
System.out.println("汪 汪 汪");
}
}
class Cat extends Animal{
void speak(){
System.out.println("喵 喵 喵");
}
}
public class testji {
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
cat.speak();
dog.speak();
}
}
注意:
- 包含抽象方法的类必须定义为抽象类,但抽象类中可以不包含任何抽象方法
- 抽象类不可以被实例化,因为抽象类中可能包含抽象方法,而抽象方法没有方法体,不可以被调用
- 抽象类不能被实例化,所以这个抽象类只能被继承
- 什么是抽象方法 , 是一个没有具体实现的方法,被 abstract 修饰
- 抽象类不能被 final 修饰,抽象方法也不能被 final 修饰
9.2 接口
如果一个抽象类中的所有方法都是抽象的,就可以将这个类定义为另一种形式 —— 接口。接口:是一种特殊的抽象类,它不包含普通方法,内部的所有方法都是抽象方法
在JDK 8 中,对接口进行了重新定义,接口中除了抽象方法外,还可以有默认方法和静态方法,默认方法使用 default 修饰,静态方法使用 static 修饰,并且这两种方法都允许有方法体
定义接口时,使用 interface 关键字来声明
9.2.1 类与接口
1. 定义常量,定义时必须初始化赋值
2. 静态方法通过 接口名.方法名 形式来调用
3. 抽象方法、默认方法通过接口实现类的实例对象来调用
4. 一个类可以在继承另一个类的同时实现多个接口,并且多个接口之间用逗号(,)隔开
5. 当一个类实现接口的时候,如果这个类是抽象类,只需要实现接口的部分抽象方法即可,否则需要实现接口中的所有抽象方法
interface Animal{
int Id = 1;//定义全局常量,定义时必须初始化赋值
void eat();//抽象方法,无方法体
default void getType(String type){//默认方法
System.out.println("属于:"+ type +"科");
}
static int getId(){//静态方法
return Animal.Id;
}
}
class Dog implements Animal{
@Override
public void eat() {//接口的实现类,必须实现接口中的所有抽象方法
System.out.println("小狗在吃狗粮");
}
}
public class testji {
public static void main(String[] args) {
System.out.println(Animal.getId());//静态方法通过 接口名.方法名 形式来调用
Dog dog = new Dog();
System.out.println(dog.Id);
dog.eat();//抽象方法、默认方法通过接口实现类的实例对象来调用
dog.getType("犬");
}
}
9.2.2 接口与接口
接口之间可以通过 extends 关键字实现继承
interface Animal{
int Id = 1;
void eat();
default void getType(String type){//默认方法
System.out.println("属于:"+ type +"科");
}
static int getId(){//静态方法
return Animal.Id;
}
}
interface LandAnimal extends Animal{
void run();
}
class Dog implements LandAnimal{
@Override
public void eat() {
System.out.println("小狗在吃狗粮");
}
public void run() {
System.out.println("小狗跑过来了");
}
}
public class testji {
public static void main(String[] args) {
System.out.println(Animal.getId());
Dog dog = new Dog();
System.out.println(dog.Id);
dog.eat();
dog.getType("犬");
dog.run();//调用dog对象的run()方法
}
}
总结:
- JDK 8 之前,接口中的方法都必须是抽象的,并且方法不能包含方法体。从JDK 8 开始,接口中除了抽象方法外,还可以有默认方法和静态方法,并且这两种方法都允许有方法体
- 当一个类实现接口时,如果这个类是抽象类,只需要实现接口的部分抽象方法即可,否则需要实现接口中的所有抽象方法
- 一个类可以通过 implements 关键字同时实现多个接口
- 接口之间可以通过 extends 关键字实现继承,并且一个接口可以同时继承多个接口
- 一个类在继承另一个类的同时还可以实现接口,此时, extends 关键字必须位于 implements 关键字之前
class A extends B implements C{//先继承,再实现
...
}