一.类的继承
类的继承是指在现有类的基础上去构建一个新的类,构建出来的新类被称作子类。现有类被称作父类或者是基类,子类也被称作派生类。子类可自动拥有父类所有可继承的属性和方法。
1.基本概念
/*
* 类的继承中需要注意的问题:
* 1.类只支持单继承,不允许多重继承
* 2.多个类可以继承同一个父类
* 3.多层继承是可以的,即一个类的父类可以再去继承另外的父类。
* 4.子类和父类是一对相对的概念,也就是说一个类是某个类父类的同时,也可以是另一个类的子类。例如B类是A类的子类,同时又是C类的父类。
*/
//定义Animal类
class Animal {
String name;
void shout() {
System.out.println("动物发出叫声");
}
}
//定义Dog类继承Animal类
class Dog extends Animal {
public void printName() {
System.out.println("name=" + name);
}
}
public class Demo01 {
public static void main(String[] args) {
Dog dog = new Dog();// 创建一个Dog类的实例对象
dog.name = "沙皮狗";// 为dog类对象的name属性进行赋值
dog.shout();// 调用Dog类对象的printName方法
dog.printName();// 调用Dog类继承的shout()方法
}
}
运行结果:
2.重写父类方法
/*
* 重写父类方法:
* 在继承关系中,子类会自动继承父类中公共的方法,但有时也需要对继承的方法进行一些修改,及对父类的方法进行重写。
* 注意:(子类重写的方法需要和父类被重写的方法具有相同的)
* 1.方法名
* 2参数列表
* 3.返回值
*/
/*
* 在调用Dog类对象的shout()方法时,只会调用子类重写的方法,并不会调用父类的shout()方法 注意:
* 子类重写父类方法时,不能使用比父类中被重写的方法更为严格的访问权限。如父类中方法的访问权限是public,子类重写父类方法的权限就不能是private
*/
class Animal {
// 定义动物叫的方法
void shout() {
System.out.println("动物发出叫声");
}
}
//定义Dog类继承动物类
class Dog extends Animal {
// 定义狗叫的方法
void shout() {
System.out.println("狗发出叫声:汪汪~~~");
}
}
public class Demo02 {
public static void main(String[] args) {
Dog dog = new Dog();// 创建Dog类的实例对象
dog.shout();// 调用Dog类重写的shout()方法
}
}
运行结果:
3.super关键字
* super关键字:
* 引入super关键字的原因:
* 当子类重写父类的方法后,子类对象将无法直接访问父类被重写的方法。
* 因此,提供了super关键字来访问父类的成员。例如访问父类的成员变量、成员方法和构造方法。
3.1使用super关键字调用父类的成员变量和成员方法
//定义Animal类
class Animal {
String name = "动物";
void shout() {
System.out.println("动物发出叫声");
}
}
//定义Dog类继承动物类
class Dog extends Animal {
String name = "犬类";
// 重写父类的shout()方法
void shout() {
super.shout();// 访问父类的成员方法
}
void printName() {
System.out.println("name=" + super.name);// 访问父类的成员变量
}
}
public class Demo03 {
public static void main(String[] args) {
Dog dog = new Dog();// 创建一个dog对象
dog.shout();// 调用dog对象重写shout()方法
dog.printName();// 调用dog对象的printName()方法
}
}
运行结果:
3.2使用super关键字调用父类的构造方法
//定义Animal类
class Animal {
// 定义Aniaml类有参构造方法
public Animal(String name) {
System.out.println("我是一只" + name);
}
}
//定义Dog类继承Animal类
class Dog extends Animal {
public Dog() {
super("沙皮狗");// 调用父类有参的构造方法
}
}
public class Demo04 {
public static void main(String[] args) {
Dog dog = new Dog();// 创建Dog类的实例对象
}
}
运行结果:
错误用例:
//super("沙皮狗");// 调用父类有参的构造方法 将这一行注释掉
会出现报错信息:
Implicit super constructor Animal() is undefined. Must explicitly invoke another constructor
分析:
在子类的构造方法中一定会调用父类的某个构造方法,如果没有指定,在实例化子类对象时,会默认调用父类无参的构造方法,而错误用例中,父类Animal类无无参的构造方法,所以在子类默认调用父类无参构造方法时会出错。
修改:
在子类中显式地调用父类中已有的构造方法,或者在父类中定义无参的构造方法。
结论:
在定义一个类时,如果没有特殊需求,当定义了有参构造方法后,尽量在类中再显示地定义一个无参构造方法,这样可以避免该类被继承时出现错误。
4.Object类
在Java中提供了一个Object类,它是所有类的父类,即每个类都直接或者间接继承自该类,因此Object类通常被称为超类、基类或根类。当定义一个类时,如果没有使用extends关键字为这个类显式地指定父类,那么该类会默认继承Object类。
//定义Animal类
class Animal {
// 重写Object类的toString方法
public String toString() {
return "这是一只动物";
}
}
public class Demo05 {
public static void main(String[] args) {
Animal animal = new Animal();// 创建Animal对象
System.out.println(animal.toString());// 打印Aniaml的toString()
}
}
运行结果:
二.final关键字
特性:
1.final修饰的类不能被继承
2.final修饰的方法不能被子类重写
3.final修饰的变量(成员变量和局部变量)是常量,只能赋值一次
public class Example{
//final修饰的成员变量,必须在声明的同时进行赋值,否则编译错误
final int m;//报错
public static void main(String[] args) {
//final修饰的局部变量,可以先声明,再进行一次赋值
final int n;
n=4;
}
}
三.抽象类和接口
3.1抽象类
* ——当定义一个类时,常常需要定义一些方法来描述该类的行为特征,但有时这些方法的实现方式是无法确定的。
* 针对这种情况,Java提供了抽象方法来满足这种需求。
* 抽象方法必须使用abstract关键字来修饰,并且在定义方法时不需要实现方法体。
* 当一个类中包含的抽象方法,那么该类也必须使用abstract关键字来修饰.
* 这种使用abstract关键字修饰的类就是抽象类。
*
* 注意:
* 包含抽象方法的类必须定义为抽象类,但抽象类中可以不包含任何抽象方法。
* 另外,抽象类是不可以被实例化的,因为抽象类中有可能包含抽象方法,抽象方法是没有方法体的,不可以被调用。
* 如果想要调用抽象类中定义的抽象方法,需要创建一个子类,在子类中实现抽象类中的抽象方法。
//定义抽象类Animal
abstract class Animal {
// 定义抽象方法shout()
public abstract void shout();
}
//定义Dog类继承Animal类
class Dog extends Animal {
// 实现抽象方法shout(),编写方法体
public void shout() {
System.out.println("汪汪~~~");
}
}
public class Demo01 {
public static void main(String[] args) {
Dog dog = new Dog();// 创建Dog类的实例对象
dog.shout();// 调用Dog对象的shout()方法
}
}
运行结果:
3.2接口
* 接口是一种特殊的抽象类,它不能包含普通方法,其内部的所有方法都是抽象方法,它将抽象进行的更为彻底。
* 接口中除了抽象方法外,还可以有默认方法和静态方法(也叫类方法)。
* 默认方法使用default修饰,静态方法使用static修饰,并且这两种方法都允许有方法体。
* 与定义类不同的是,在定义接口时,不再使用static关键字,而是使用interface关键字来声明。
*
* 提示:
* 在接口中定义常量时,可以省略“public static final”修饰符,此时,接口会默认为常量添加“public static final”修饰符。
* 与此类似,在接口中定义抽象方法时,也可以省略“public abstract”修饰符。
* 定义default默认方法和static静态方法时,可以省略“public”修饰符,这些修饰符系统会默认进行添加。
*
* 调用格式:
* 静态方法可以通过“接口名.方法名”的形式来调用,而抽象方法和默认方法只能通过接口实现类的实例对象来调用。
* 一个类可以在继承另一个类的同时实现多个接口,并且多个接口之间需要使用英文,分隔。
*
*接口的实现类,必须实现接口中所有的抽象方法,否则程序编译报错。
//定义Aniaml接口
interface Animal {
int ID = 1;
void breathe();
// 定义一个默认方法
default void getType(String type) {
System.out.println("该动物属于:" + type);
}
// 定义一个静态方法
static int getID() {
return Animal.ID;
}
}
//Dog类实现了Aniaml接口
class Dog implements Animal {
// 实现breathe()方法
public void breathe() {
System.out.println("狗在呼吸");
}
}
public class Demo02 {
public static void main(String[] args) {
System.out.println(Animal.getID());// 通过接口名调用类方法
Dog dog = new Dog();// 创建Dog类的实例对象
System.out.println(dog.ID);// 在实现类中获取接口全局变量
dog.breathe();// 调用dog对象的breathe()方法
dog.getType("犬科");// 通过接口实现Dog的实例化对象,调用接口默认方法
}
}
运行结果:
接口和接口之间可以是继承关系,接口中的继承同样使用extends关键字来实现。
接口的特点:
1.当一个类实现接口时,如果这个类是抽象类,只需实现接口中的部分抽象方法即可,否则需要实现接口中的所有抽象方法。
2.一个类在继承一个类的同时还可以实现接口,此时,extends关键字必须位于implements关键字之前。
//定义Animal接口
interface Animal {
int ID = 1;// 定义全局变量
void breath();// 定义抽象方法breathe()
// 定义一个默认方法
default void getType(String type) {
System.out.println("该动物属于:" + type);
}
// 定义一个静态方法
static int getID() {
return Animal.ID;
}
}
//定义了LandAnimal接口,并继承了Aniaml接口
interface LandAnimal extends Animal {
void run();// 定义抽象方法run()
}
class Dog implements LandAnimal {
public void breathe() {
System.out.println("狗在呼吸");
}
public void run() {
System.out.println("狗在陆地上跑");
}
}
public class Demo03 {
public static void main(String[] args) {
System.out.println(Animal.getID());// 通过接口名调用类方法
Dog dog = new Dog();// 创建Dog类的实例对象
System.out.println(dog.ID);// 在实现类中获取接口全局变量
dog.breathe();// 调用Dog对象的breathe()方法
dog.getType("犬科");// 通过Dog对象,调用接口默认方法
dog.run();// 调用dog对象的run()方法
}
}
运行结果: