Java面向对象——继承(extends)
继承的概念:如果一个类A“继承自”另一个类B,就把这个类A称为类B的子类,而把B类称为A类的父类也可以称A是B的派生类
继承的优点:继承可以使得子类获得父类的一些属性和方法,从而不需要再次编写相同的代码,减少代码的重复,便于维护,在生活角度来看的,继承相当于儿子继承了父亲的一些特征和能力
注意事项:
- 子类拥有父类的属性和方法,而父类没有子类的独有的属性和方法
- 父类中public,protected修饰的属性,方法可以继承,private修饰的属性和方法不能被继承,如果父类的属性均为private修饰,则可以通过共有的getter,setter方法来调用
- java中的类只能单继承,而接口是可以多继承
- 在创建子类对象的时候,首先调用的是父类的无参构造方法创建一个父类对象,也就是说在子类对象生成前,事先会默认生成一个父类对象
类继承的格式与写法
单继承
语法示例:
class 父类 { }
class 子类 extends 父类 { }
public class TestExtends {
public static void main(String[] args) {
}
class Father{} //编写父类
class Son extends Father{} //创建子类继承父类
}
多层继承
语法示例:
class 父类 { }
class 子类 extends 父类 { }
class 孙子类 extends 子类{}
public class TestExtends {
//父类方法
public class Father {
public int age;
}
//子类方法
public class Son extends Father{}
//孙子类方法
public class Grandson extends Son{}
public static void main(String[] args) {
Grandson grandson = new Grandson();
System.out.println(grandson.age);
}
}
此时孙子类继承了子类的属性而子类又继承了父类的属性age,所以孙子类也可以访问父类的age
不同子类继承父类
public class TestExtends{
//创建父类
class Father(){
public int age; //公开的父类属性以便于其他子类访问
}
class Son1 extends Father{
public Son1(int age){ //定义Son1构造器访问父类属性age
this.age = age;
}
}
class Son2 extends Father{
public Son2(int age){ //定义Son2构造器访问父类属性age
this.age = age;
}
}
}
此时的两个子类都可以访问父类的属性
方法的重写(Override)
概念
在Java和其他一些高级面向对象的编程语言中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。 如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
前提要求:
- 必须要有继承
- 子类的要重写的方法必须与父类的方法相同
- 构造方法不能被重写。
重写的好处
增强了代码的灵活性和复用性,在已有的基础上创建自己想要改变的和自己需要改变的,从而不需要再次编写相同类型的方法,使代码有更好的扩展性
public class Test {
public static void main(String[] args) {
Son son = new Son();
son.print(); //输出子类的方法
}
}
//父类方法
class Father{
public void print() { //父类的输出方法
System.out.println("父类");
}
}
//子类方法
class Son extends Father{
public void print() { //子类重写父类的输出方法
System.out.println("子类");
}
}
输出结果:
super关键字
概念
super可以理解为是指向父类对象的一个指针,从而获得父类的方法,在子类重写了父类的方法时,并没有改变父类原有的方法,所以当我们需要用到父类原有的方法时,我们就可以使用super关键字,来获取父类的成员方法和变量(包括构造方法)
super的使用
- 直接使用,访问父类的属性
public class Test {
public static void main(String[] args) {
Son son = new Son();
son.print();
}
}
//父类
class Father{
int age = 12;
}
//子类
class Son extends Father{
public void print() {
System.out.println(super.age); //访问父类age属性
}
}
运行结果
- 调用被子类覆盖的父类属性
public class Test {
public static void main(String[] args) {
Son son = new Son(); //创建子类对象
son.print();
son.method();
}
}
class Father{
int age = 12; //父类属性
public void method() { //父类方法
System.out.println("这是父类的方法");
}
}
//继承父类father
class Son extends Father{
int age = 23; //子类覆盖父类的属性
public void print() { //输出父类和子类的属性
System.out.println("父类的age属性:"+super.age+"\t子类的age属性:"+age);
}
//重写父类方法
@Override
public void method() {
System.out.print("使用super访问父类的方法:");
super.method(); //使用super关键字访问父类方法
System.out.print("子类的方法:");
System.out.println("这里重写父类的方法");
}
}
- 调用构造器,子类的构造方法的第一句一定是super,在子类对象生成前会先调用父类的构造方法
public class Test {
public static void main(String[] args) {
System.out.println("开始创建第一个对象");
new Son(); //构造方法
}
}
//父类
class Father{
//父类构造器
public Father() {
System.out.println("创建父类对象");
}
}
//子类
class Son extends Father{
//子类构造器
public Son() {
super(); //每个子类的构造器都会默认在第一句加上super(调用父类构造器),写与不写都会有,用于调用对应父类的构造方法
System.out.println("创建子类对象");
}
}
运行结果:
instanceof
判断左边的对象是否从属于右边的这个类,是则返回true,不是则返回false
package com.jmit.work4;
public class Test {
public static void main(String[] args) {
Son son = new Son(); //构造方法
Father father = new Father();
//判断Father是否属于Son
if(father instanceof Son) {
System.out.println("father对象是属于Son类的");
}else {
System.out.println("father对象是不属于Son类的");
}
//判断son是否属于Son
if(son instanceof Son) {
System.out.println("son对象是属于Son类的");
}
//判断son是否属于Father
if(son instanceof Father) {
System.out.println("son对象是属于Father类的");
}
//判断son是否属于Object
if(son instanceof Object) {
System.out.println("son对象是属于Object类的");
}
}
}
//父类
class Father{}
//子类
class Son extends Father{}
运行结果:
上述例子中,因为子类是继承于父类的,所以他的子类对象也属于父类,而在java中,所有类的父类是Object,所以,子类的对象也从属于Object。