Java——继承、多态、抽象类

本文详细介绍了Java中的继承、多态和抽象类。通过讲解`extends`关键字、向上转型与向下转型、多态的概念及其实现、`instanceof`关键字的应用,以及抽象方法和抽象类的特性,帮助读者深入理解Java面向对象编程的核心概念。同时,文中还探讨了在构造器中调用重写方法的潜在问题及其原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继承(is a的关系)

首先请看这两个代码:
eg:

class Student{
	String name;
	int age;
	
	public Student(){
	}
	//getXxx()/setXxx()
	public void eat(){
	System.out.println("吃饭");
	}
}

class Teacher{
	String name;
	int age;
	
	public Teacher(){
	}
	//getXxx()/setXxx()
	public void eat(){
	System.out.println("吃饭");
	}
}
  • 上面两个代码的name、age、getXxx()/setXxx()、eat()等都是相同的,如果后面继续定义的类也具备这些内容,每一次定义类都要将这些重复的内容重新定义一次,使得代码变的很冗杂;
    为了解决这一问题,Java中提出了继承这一概念。

继承:多个类中存在相同属性和行为时,将这些内容抽取到单独的一个类中,那么多个类无需再定义这些属性和行为,只需要继承那个类即可;

class 父类名 {
}//父类、基类、超类
class 子类名 extends 父类名{
}//子类、派生类
//类2继承于类1
extends 是关键字;

由此,前面的两个代码就可以写为:

class Person{
	String name;
	int age;
	
	public Person(){
	}
	
	//getXxx()/setXxx()
	
	public void eat(){
	System.out.println("吃饭");
	}
}
class Student extends Person{
	public Student(){
	}
}
class Teacher extends Person{
	public Teacher(){
	}
}

继承的优点:

  • 提高了代码的复用性;
  • 提高了代码的维护性;
  • 让类与类之间产生关系,是多态的前提;
extends 关键字
  • final class Animal —>类被final修饰后不能被继承
  • final可以修饰常量、属性、类
class Animal{
    public String name;
    public int age;
    public Animal(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void eat(){
        System.out.println(this.name + "eat()");
    }
}Animal为父类/基类/超类

class Cat extends Animal{   //关键字extends
    public String sex;
    public Cat(String name,int age,String sex){
        super(name,age);   //super显示调用父类的构造方法
        this.sex= sex;
    }
    public void jump(){
        System.out.println(this.name + "跳");
    }
}Cat为子类/派生类

public class TestDemo {
    public static void main(String[] args){
		Animal animal = new Animal("动物",10);
        Cat cat = new Cat("豆豆",1,"women");
        cat.jump();
        cat.eat();
    }
}

多态

向上转型

三种方式:

  • 直接赋值
	Animal animal = new Animal("动物",10);
    Cat cat = new Cat("豆豆",1,"women");
	animal = cat;  //将子类对象赋值给父类对象
可以写成:
	Animal animal = new Cat("豆豆",1,"women");
	//父类引用 子类对象 ---》向上转型
  • 方法传参
public static void func(Animal animal){
		animal.eat();
	}
public static void main(String[] args){
		Cat cat = new Cat();
		func(cat);
	}
  • 方法返回
public static Cat func(){
		Cat cat = new Cat();
		return cat;
	}
public static void main(String[] args){
		Animal animal = func();
	}
  • Animal只能调用父类自己的方法或者成员属性;
  • 如果子类中重写了父类中的方法,调用的依然是父类的该方法,但是由于在该过程中会发生运行时多态,所以运行的结果为子类中该方法的结果;

invokespecial:调用构造方法
invokevirtual:调用非静态方法 实例方法

class Animal{
    public String name;
    public int age;
    public Animal(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void eat(){
        System.out.println(this.name + "Animal::eat()");
    }
}
class Cat extends Animal{   //关键字extends
    public String sex;
    public Cat(String name,int age,String sex){
        super(name,age);   //super显示调用父类的构造方法
        this.sex= sex;
    }
    public void jump(){
        System.out.println(this.name + "跳");
    }
    public void eat(){
        System.out.println(this.name + "Cat::eat()");
    }//重写
}

重写:方法名相同 参数列表相同 返回值相同 ——》override
重写的注意事项

  • 方法不能是private;
  • 子类的方法权限一定要大于父类方法的权限;
  • 不能是一个静态的方法;

重写和重载的区别:

  • 重载是方法名相同,参数列表不同;重写是方法名相同,返回值类型相同,参数列表相同;
  • 重载是一个类中,重写是继承关系上;
  • 重载没有权限要求,重写有权限要求;

this 和 super 的区别:

  • this访问本类中的属性和方法,super由子类访问父类中的属性和方法;
  • this先查找本类,如果本类没有就调用父类;super不查找本类,直接调用父类;
  • this表示当前对象的引用;

发生多态——运行时多态:
  • 继承——》父类需要引用子类对象(向上转型);
  • 通过父类的引用去调用子类和父类同名的覆盖方法;
  • 一个类型就有一个方法表和class对象;
    (反射:获取class对象; 三种方式)

向下转型
class Bird extends Animal{
	public String color;
	public void fly(){
	}
	
public static void main(String[] args){
		Animal animal = new Bird();
		animal.eat();
		Bird bird = (Bird)animal;  //将父类对象给子类对象,需要强转
		animal.fly();
	}

向下转型的前提是必须先进行一次向上转型;

Animal animal = new Cat("小猫"); 
	Bird bird = (Bird)animal; 
	bird.fly(); 
执行结果, 抛出异常:Exception in thread"main"java.lang.ClassCastException: Cat cannot be cast to Bird at 	Test.main(Test.java:35)
(animal本质上引用的诗意个Cat对象,运行时就会抛出异常;)

为了让向下转型更安全,我们需要先判断animal是不是一个Bird实例再进行转换;


instanceof 关键字

Animal animal = new Cat("小猫"); 
	if (animal instanceof Bird) { 
	Bird bird = (Bird)animal; 
	bird.fly(); 
}//如果是Bird的实例,进入if语句

在构造器中调用重写的方法(这是一个大坑)
class B { 
	public B() { 
	// do nothing 
	func(); 
	} 
	public void func() { 
		System.out.println("B.func()"); 
	} 
} 

class D extends B { 
	private int num = 1; 
	@Override 
	public void func() { 
		System.out.println("D.func() " + num); 
	} 
} 

public class Test { 
	public static void main(String[] args) { 
	D d = new D(); 
	} 
} 
执行结果:D.func() 0 
  • 构造 D 对象的同时,会调用 B 的构造方法.
  • B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
  • 此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0.

  • Q:构造方法内是否能够发生动态绑定?
  • 可以;

抽象类

abstract 抽象方法
  • 包含抽象方法的类叫做抽象类;
  • 抽象类不能被实例化;
  • 抽象类当中可以有抽象方法,也可以有非抽象方法或者成员变量;
  • 抽象类的产生就是为了继承;
public abstract void Shape{
}//抽象类	

如果一个类里面的方法没有具体的实现,可以将它作为一个抽象方法,一旦这个抽象方法放到这个类中,此类必须是一个抽象类;

abstract class Shape{
	public abstract void draw();
}
  • 抽象类只要被继承,一定要重写抽象方法;
  • 如果抽象类A继承了抽象类B,那么抽象类A可以选择重写或者不重写抽象类B中的方法;

注意:

  • 抽象类不能直接实例化;(只能创建该抽象类的子类,然后让子类重写抽象方法)
  • 抽象类不能是 private 的;
  • 抽象类中可以包含其他的非抽象方法,也可以包含字段;

Q:普通的类也可以被继承, 也可以被重写, 为啥非得用抽象类和抽象方法呢?
使用抽象类相当于多了一重编译器的校验。

### Java 中封装、继承多态和抽象的概念解释 #### 封装 (Encapsulation) 封装是指将数据(属性)和操作这些数据的方法绑定在一起作为一个单元处理,并尽可能隐藏对象内部的具体工作细节。这样做的好处是可以保护数据的安全性和完整性,防止外部直接访问或修改对象的状态。 在Java中,可以通过设置成员变量为`private`私有化来实现这一目的;如果其他类想要获取或更改该字段,则需借助于公共的getter/setter方法[^1]。 ```java public class Person { private String name; public void setName(String newName){ this.name = newName; } public String getName(){ return this.name; } } ``` #### 继承 (Inheritance) 继承是面向对象编程中的一个重要概念,它允许创建一个新的类基于已有的类定义。新类称为子类(Subclass),原有被扩展的类叫做超类(Superclass) 或者基类(Base Class) 。 子类会自动拥有父类所有的非私有属性以及行为,从而实现了代码复用的目的[^4]。 需要注意的是,在Java里并不支持多重继承——即不允许一个类同时派生自两个以上的直接祖先类型。不过这个问题可通过引入接口机制得到解决。 #### 多态 (Polymorphism) 多态意味着同一个实体能够表现出多种形式的能力。对于Java而言,主要体现在运行期动态绑定方面:即使编译阶段指定了某种特定类型的引用指向某实例,但在执行过程中却能依据实际情况调用相应最合适的函数版本[^2]。 这种灵活性不仅限于普通的方法覆盖(Override),还包括构造器链式调用等情况下的表现差异。更重要的是,得益于向上转型(upcasting) 的存在,使得程序员可以在不知道确切子类别的情况下依然正常操纵它们[^5]。 ```java // 基础动物类 abstract class Animal{ abstract void makeSound(); } // 宠物狗类 class Dog extends Animal{ @Override void makeSound(){System.out.println("汪!");} } // 测试程序片段 Animal myPet=new Dog(); // 向上转换 myPet.makeSound(); // 输出 "汪!" ``` #### 抽象 (Abstraction) 抽象是对复杂系统的简化描述过程,旨在忽略不必要的细节而专注于核心功能。具体到Java语言层面表现为: - 使用 `interface` 关键字声明完全由未实现签名组成的纯虚接口; - 利用 `abstract` 类型修饰符标记那些至少含有一个无主体定义成员函数的半成品模板[^3]。 两者都强制要求任何具体的衍生后代必须提供完整的实现方案才能正常使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值