当前位置: 首页 > news >正文

Java——多态

什么是多态:

        多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状 态。
可能不太懂是什么意思,那首先来简单实现一个:(看效果!!)
        
class Anamals{String name;String color;public void barks(){System.out.println("动物叫");}
}
class Cat extends Anamals{@Overridepublic void barks(){System.out.println(name+"喵喵~");}
}
public class Test2 {public static void main(String[] args) {Cat cat = new Cat();cat.name = "xiaoxiao";Anamals anamals = cat;anamals.barks();}
}

这就是多态!!

多态的特征:

1、必须是继承关系。(cat与anamals是继承关系)。

2、需要引用父类的类行初始化子类对象。

3、必须重写父类中的方法。

4、当访问父类中的重写的方法时,调用的确实子类中重写的方法!

以上的特征都会一一解答。

重写:

        想要做到多态,重写是必要条件,那么什么是重写?

        重写的意思就是,同一个方法,返回值相同,方法名相同,参数列表相同。

         返回值和形参都不能改变即外壳不变,核心重写!
当然如下总结了方法重写的规则:
1、子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 ( 参数列表 ) 要完全一致
2、被重写的方法返回值类型可以不同,但是必须是具有父子关系的
3、访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被 public 修饰,则子类中重写该方法就不能声明为 protected
4、父类被 static private 修饰的方法、构造方法都不能被重写。
5、重写的方法 , 可以使用 @Override 注解来显式指定 . 有了这个注解能帮我们进行一些合法性校验 . 例如不小心将方法名字拼写错了 ( 比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法 , 就会编译报错 , 提示无法构成重写.

咋们一个规则一个规则分析:
 1、子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致。

例如:

父类中:

子类中:

此时子类中重写了父类中的方法:是符合规矩的。

如果此时改变返回值类型,会不会报错呢?

报错啦!

如果改变参数列表呢?

同样报错啦!

 2、被重写的方法返回值类型可以不同,但是必须是具有父子关系的(但是必须是父类返回值的派生类)。

例如:

class Anamals{String name;String color;public Anamals barks(){Anamals anamals = new Anamals();System.out.println("动物叫");return anamals;}
}
class Cat extends Anamals{@Override
//Cat类是Anamals的派生类public Cat barks(){Cat cat = new Cat();System.out.println(name+"喵喵~");return cat;}
}

此时虽然返回值类型不同,但是还是可以的。

因为Cat类行是Anamals的派生类。

 3、访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected。

例如:

父类:

子类:

这个是可以的。

但是如果交换两个访问权限,那就会报错!!

 4、父类被staticprivate修饰的方法、构造方法都不能被重写。

例如:

如果是以上两种情况时:

子类重写会报错:

重写与重载的区别:

方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

重写的设计原则:

对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容,并且添加或者改动新的内容。

静态绑定

也称为前期绑定 ( 早绑定 ) ,即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表 函数重载

动态绑定

也称为后期绑定 ( 晚绑定 ) ,即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。(代表: 函数重写 )
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. 如果具备多态性, num 的值应该是 1.

 

 向上转型:

在进行多态时,有一个特征:

需要引用父类的类行初始化子类对象。

这个其实发生的就是向上转型!

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。 

语法格式:父类类型 对象名 = new 子类类型()  

 向上转型的方式:

1. 直接赋值
2. 方法传参
3. 方法返回

直接赋值:

public class Test2 {public static void main(String[] args) {Anamals anamals = new Cat();;//直接赋值法}
}

方法传参:

public static void anamalsBarks(Anamals a){a.barks();
}
public static void main(String[] args) {Cat cat = new Cat();anamalsBarks(cat);
}

 方式返回:

============================================================================
public static Cat anamalsBarks( ){Cat cat = new Cat();return cat;
}
public static void main(String[] args) {Anamals anamals = anamalsBarks( );anamals.barks();
}

================================================================

向下转型:

        将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换

 

// 向上转型
        Animal animal = cat ;
        animal . eat ();
        animal = dog ;
        animal . eat ();
// 编译失败,编译时编译器将 animal 当成 Animal 对象处理
// Animal 类中没有 bark 方法,因此编译失败
// animal.bark();
// 向上转型
// 程序可以通过编程,但运行时抛出异常 --- 因为: animal 实际指向的是狗
// 现在要强制还原为猫,无法正常还原,运行时抛出: ClassCastException
        cat = ( Cat ) animal ;
        cat . mew ();
// animal 本来指向的就是狗,因此将 animal 还原为狗也是安全的
        dog = ( Dog ) animal ;
        dog . bark ();

大家可以试试这段代码:

class Animals{int age;String name;public void barks(){System.out.println(name+"hahaha");}public Animals(){System.out.println(" public Animals()");}
}
class Cat extends Animals{public void barks(){System.out.println(name+"喵喵~");}public void eat(){System.out.println(name+"正在吃");}public Cat(String name,int age) {super();this.name = name;this.age = age;System.out.println(" public Cat(String name,int age) ");}
}
public class Test1 {public static void main(String[] args) {Animals cat = new Cat("lala",2);System.out.println(cat.name+" "+cat.age);Cat cat1 = (Cat) cat;cat1.barks();}
}

安全的向下转型:

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。 Java 中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为 true ,则可以安全转换。

例如:

==================================================================

public class Test1 {public static void main(String[] args) {Animals cat = new Cat("lala",2);System.out.println(cat.name+" "+cat.age);//将Animals类行转换为Cat类型的判断if(cat instanceof Cat) {Cat cat1 = (Cat) cat;cat1.barks();}}
}

==================================================================

 多态的有点(作用):

        认识了多态,那多态是干嘛的,有啥用?

任务:利用继承关系打印图形:

class Graph{public void draw(){System.out.println("画图形");}
}
class Triangle extends Graph{@Overridepublic void draw(){System.out.println("▲");}
}
class Circle extends Graph{@Overridepublic void draw(){System.out.println("🔘");}
}
class Square extends Graph{@Overridepublic void draw(){System.out.println("⏹");}
}
public class Test2 {//画图形public static void main(String[] args) {//画出▲⏹⏹🔘🔘图形,不用多态Triangle triangle = new Triangle();Circle circle = new Circle();Square square = new Square();int[] arr = {1,2,2,3,3};for(int x:arr){if(x == 1){triangle.draw();}else if(x == 2){circle.draw();}else{square.draw();}}}
}

用多态打印:

Graph[] arr = {triangle,circle,circle,square,square};
for (Graph graph:arr) {graph.draw();
}

 

 

 


http://www.mrgr.cn/news/24415.html

相关文章:

  • MySQL内置函数
  • F-32产生了额外的行项目
  • 开放式耳机和骨传导耳机哪个对耳朵好?开放式耳机哪个牌子好?
  • ctfshow-web入门-sql注入(web244-web247)error 报错注入
  • 想报考pmp,一定得经过培训机构吗?
  • 从零到一,数字文创IP是如何在基地中孵化成长的?
  • 一文搞懂EureKa原理
  • postgresql 导出CSV格式数据
  • Android Studio新建工程(Java语言环境)
  • 从基础到进阶:直播美颜API集成主播美颜SDK的开发指南
  • P1308 [NOIP2011 普及组] 统计单词数
  • C++——智能指针
  • Go 语言中SplitByChars 方法
  • 下班后做小红书第7个月,涨粉7w,累计变现5w+,我只用到五个点
  • 拒稿后另投他刊,仍旧被判定“一稿多投”?
  • 【路径规划】APF算法、Vortex APF算法、Safe APF算法和动态Windows方法的比较
  • 让AI成为打光工具人(Stable Diffusion进阶篇:Imposing Consistent Light)
  • WinRAR下载安装完整教程
  • 微信小程序接收蓝牙数据超过20字节断包解决方案
  • 77-java 装饰器模式和适配器模式区别