多态
多态
概念:
- 多态:某一个事物,在不同时刻下的不同状态
- 实现多态有3个前提:
1、必须要有继承关系
2、要有方法的实现
3、要有父类的引用指向子类对象 - 1.面向对象三大特征:封装 继承 多态
2.怎么学:
a.不要从字面意思上理解多态这两个字,要从使用形式上掌握
b.要知道多态的好处
c.要知道多态的前提 - 1.前提:
a.必须有子父类继承或者接口实现关系
b.必须有方法的重写(没有重写,多态没有意义),多态主要玩儿的是重写方法
c.new对象:父类引用指向子类对象
Fu fu = new Zi() -> 理解为大类型接收了一个小类型的数据 ->比如 double b = 10
2.注意:
多态下不能直接调用子类特有功能
- 实现多态有3个前提:
例子:
水:气态的水,固态的水,液态的水
水果:苹果,香蕉,哈密瓜
动物:狗,猫
*/
class Animal{
String name;
int age;
Animal(){
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println("🐕吃🥩");
}
@Override
public void sleep(){
System.out.println("🐕侧着睡");
}
}
class Demo1{
}
public class DuoTaiDemo1 {
public static void main(String[] args) {
//要有父类的引用指向子类对象
Animal a1 = new Dog(); //多态 //必须要存在继承关系,或者待会要说的实现关系
// Dog d1 = new Dog();
// Demo1 a2 = new Dog();
}
}
多态的条件下成员的访问特点
多态访问成员的特点:
1、成员变量: 编译看左,运行看左
2、成员方法: 编译看左,运行看右
3、静态成员方法: 编译看左,运行看左
例子:
class Fu1{
int a = 10;
public void fun1(){
System.out.println("这是父类中的fun1方法");
}
public static void show1(){
System.out.println("这是父类中的静态成员方法show1");
}
}
class Zi1 extends Fu1{
int a = 20;
// @Override
// public void fun1(){
// System.out.println("这是子类中的fun1方法");
// }
public void fun1(){
System.out.println("这是子类中的fun1方法");
}
public static void show1(){
System.out.println("这是子类中的静态成员方法show1");
}
}
public class DuoTaiDemo2 {
public static void main(String[] args) {
Fu1 f1 = new Zi1();
// System.out.println(f1.a); // 10
// f1.fun1();
f1.show1();
}
}
多态的好处于与弊端
多态的好处
提高了程序的维护性(由继承保证)
提高了程序的扩展性(由多态保证)
使用多态的弊端:无法使用子类中特有的成员方法
例子:
class Animal2 {
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
class Dog2 extends Animal2 {
@Override
public void eat() {
System.out.println("🐕吃🥩");
}
@Override
public void sleep() {
System.out.println("🐕侧着睡");
}
}
class Cat2 extends Animal2 {
@Override
public void eat() {
System.out.println("🐱吃🐟");
}
@Override
public void sleep() {
System.out.println("🐱蜷着睡");
}
}
class Pig extends Animal2 {
@Override
public void eat() {
System.out.println("🐖吃米");
}
@Override
public void sleep() {
System.out.println("🐖趴着睡");
}
}
class Tiger extends Animal2{
@Override
public void eat() {
System.out.println("🐅吃🐏");
}
@Override
public void sleep() {
System.out.println("🐅趴着睡");
}
}
class AnimalTool {
private AnimalTool() {
}
// 将来当你看到一个类作为方法的参数类型的时候,也可以传入该类的子类对象形成多态
public static void useAnimal(Animal2 animal2) { //Animal2 animal2 = new Tiger()
animal2.eat();
animal2.sleep();
}
// public static void useCat(Cat2 c){
// c.eat();
// c.sleep();
// }
//
// public static void useDog(Dog2 d){
// d.eat();
// d.sleep();
// }
//
// public static void usePig(Pig p){ //Pig p = new Pig()
// p.eat();
// p.sleep();
// }
}
public class DuoTaiDemo3 {
public static void main(String[] args) {
//我想养一只🐕
Dog2 d1 = new Dog2();
// d1.eat();
// d1.sleep();
// useDog(d1);
AnimalTool.useAnimal(d1); // new Dog2()
Dog2 d2 = new Dog2();
// d2.eat();
// d2.sleep();
// useDog(d2);
AnimalTool.useAnimal(d2);
//养🐱
Cat2 c1 = new Cat2();
// c1.eat();
// c1.sleep();
// useCat(c1);
AnimalTool.useAnimal(c1);
Cat2 c2 = new Cat2();
// c2.eat();
// c2.sleep();
// useCat(c2);
AnimalTool.useAnimal(c2);
//随着我养动物的种类越来越多,首先
//具体动物类必须定义,其次按照之前的写法,也会在当前类中写一个有关动物的使用方法
//我们可以单独使用一个类,将有关动物使用的功能方法放到一个类中,定义成工具类
Pig p1 = new Pig();
AnimalTool.useAnimal(p1); // new Pig()
//我们虽然可以实现新的动物,并且测试类中不会有新的方法添加
//但是工具类一般来说不会频繁的进行修改
//可以使用多态改进传参特点
Tiger tiger = new Tiger();
AnimalTool.useAnimal(tiger); // new Tiger()
}
}
向上转型
父类引用指向子类对象
好比是: double b = 1;
向下转型
1.向下转型:好比强转,将大类型强制转成小类型
2.表现方式:
父类类型 对象名1 = new 子类对象() -> 向上转型 -> double b = 1
子类类型 对象名2 = (子类类型)对象名1 -> 向下转型 -> int i = (int)b
3.想要调用子类特有功能,我们就需要向下转型
例子:
小故事例子:
曹操和曹植的故事:
class 曹操{
fun1(){
带兵打仗
}
}
class 曹植 extends 曹操{
fun1(){
下棋
}
show(){
绘画
}
}
有一天,曹操带兵外出打仗,这时,邻国的敌人攻打过来了,需要战士们抵抗,但是战士只听从曹操的指挥
于是曹植想到一个办法,于是开始装爹。换上爹的衣服,粘上假胡子等等
曹操 c1 = new 曹植(); //向上转型
c1.fun1();
//c1.show();
当爹回来的时候,脱下爹的衣服,撕掉假胡子
曹植 c2 = (曹植)c1; // 向下转型
c1.fun1();
c1.show();
*/
抽象类abstract关键字
在此之前,我们写的动物类,水果类,人类等等,这些类在实际生活中其实就是一个概念的集合
而概念性的东西,在生活中是看不见摸不着的,这样的类,方法也不应该有具体的实现
java针对这种现实场景,提供了一个关键字:abstract用于表示抽象的概念
可以修饰类和方法
abstract关键字使用注意事项:
1、被abstract关键字修饰的类,称之为抽象类,抽象类无法实例化【不能创建对象】
2、抽象类可以借助具有的子类【没有被abstract关键字修饰的类】来创建对象
3、被abstract关键字修饰的方法,称之为抽象方法,抽象写法不能有大括号方法体
4、当一个具体的子类继承一个抽象类的话,必须要重写抽象父类中所有的抽象方法
5、抽象类中既可以存在具体实现的方法【有大括号的】,也可以存在抽象方法
6、当一个抽象类继承一个抽象类的话,可以选择性的重写方法,也可以都不重写
7、具体的类中不能存在抽象方法【有抽象方法的类一定是抽象类】
*/
特点
-
抽象类中的成员特点: 成员变量:既可以存在变量,也可以存在常量 构造方法:抽象类是有构造方法,但是抽象类无法实例化,那么抽象类中的构造方法的意义是什么? 要想初始化子类,必须先初始化其父类 具体子类中构造方法的第一句话,默认是super() 成员方法:既可以是具体的实现方法,也可以是抽象方法
关键字与abstract的关系
关键字:
static:被static修饰的成员属于类成员,可以修饰变量,方法
final:修饰类,变量,方法
abstract:修饰类和方法
与abstract不合法的关键字组合:
abstract final
abstract static
private abstract
二:接口
接口的定义以及使用
1.接口:是一个引用数据类型,是一种标准,规则
2.关键字:
a.interface 接口
public interface 接口名{}
b.implements 实现
实现类 implements 接口名{}
3.接口中可以定义的成员:
a.jdk7以及之前:
抽象方法: public abstract -> 即使不写public abstract,默认也有
成员变量:public static final 数据类型 变量名 = 值-> 即使不写public static final,默认也有
final是最终的,被final修饰的变量不能二次赋值,所以我们一般将final修饰的变量视为常量
b.jdk8:
默认方法:public default 返回值类型 方法名(形参){}
静态方法:public static 返回值类型 方法名(形参){}
c.jdk9开始:
私有方法:
private的方法
接口中的成员
抽象方法
1.定义格式:
public abstract 返回值类型 方法名(形参);
2.注意:
不写public abstract 默认也有
3.使用:
a.定义实现类,实现接口
b.重写抽象方法
c.创建实现类对象,调用重写的方法
abstract class Animal4{
public abstract void eat();
public abstract void sleep();
}
class Dog4 extends Animal4{
@Override
public void eat() {
System.out.println("🐕吃🥩");
}
@Override
public void sleep() {
System.out.println("🐕侧着睡");
}
}
//定义一个接口
interface ByCycle{
// public void cycle(){
// System.out.println("骑车");
// }
public abstract void cycle();
}
class ByBikeDog extends Dog4 implements ByCycle{
@Override
public void cycle() {
System.out.println("狗会骑车!");
}
}
public class InterfaceDemo1 {
public static void main(String[] args) {
// ByCycle byCycle = new ByCycle();
//创建一个普通的小狗
Dog4 dog4 = new Dog4();
dog4.eat();
dog4.sleep();
// dog4.cycle();
System.out.println("-----------------------------");
//创建一个会骑车的小狗
ByBikeDog byBikeDog = new ByBikeDog();
byBikeDog.eat();
byBikeDog.sleep();
byBikeDog.cycle();
}
}
接口中成员的特点:
接口中成员的特点:
1、接口中不能有构造方法,自己写都不允许,接口不能实例化
2、接口中的方法只能是抽象方法
3、一个类要想实现一个接口的话,需要使用关键字implements
class A implements 接口1{
}
4、当一个具体的类实现一个接口的时候,必须实现接口中所有的抽象方法
5、接口中的方法默认会被public abstract关键字组合修饰,现在学习阶段写上,后面工作时不要写
6、接口中只能存在常量,不能有变量,默认会被public static final修饰
类与类,类与接口以及接口与接口的关系
类与类是继承关系,使用extends关键字进行连接,只能单继承,不能一次性继承多个,抽象类也符合这个规则
类与接口是实现关系,使用implements关键字连接,一个类可以一次同时实现多个接口,也可以继承一个类的同时实现接口
接口与接口是继承关系,使用extends关键字进行连接,可以多继承
*/
interface Inter2{
void fun1();
void fun2();
}
interface Inter3{
void show1();
}
interface Inter4 extends Inter2,Inter3{
// void fun1();
// void fun2();
// void show1();
void show2();
}
//abstract class Demo6 implements Inter2{
// // public abstract void fun1();
// // public abstract void fun2();
//}
class Demo6 extends A implements Inter2,Inter3{
@Override
public void fun1() {
}
@Override
public void fun2() {
}
@Override
public void show1() {
}
}
public class InterfaceDemo3 {
public static void main(String[] args) {
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!