什么是多态:
多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状 态。 可能不太懂是什么意思,那首先来简单实现一个:(看效果!!)class Anamals{
String name;
String color;
public void barks(){
System.out.println("动物叫");
}
}
class Cat extends Anamals{
@Override
public 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、父类被static、private修饰的方法、构造方法都不能被重写。
例如:
如果是以上两种情况时:
子类重写会报错:
重写与重载的区别:
方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
重写的设计原则:
对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容,并且添加或者改动新的内容。
静态绑定:
也称为前期绑定 ( 早绑定 ) ,即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表 函数重载 。动态绑定:
也称为后期绑定 ( 晚绑定 ) ,即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。(代表: 函数重写 )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{
@Override
public void draw(){
System.out.println("▲");
}
}
class Circle extends Graph{
@Override
public void draw(){
System.out.println("
标签:Java,void,多态,Cat,cat,父类,重写,public
From: https://blog.csdn.net/m0_75235246/article/details/142070659