多态
多态
:完成某个行为,当不同对象去完成时会产生出不同的状态。(同一件事,发生在不同对象身上,产生不同的效果。eg:动物吃粮食这个动作,对于猫是吃猫粮,狗是吃狗粮。)
多态实现条件
继承
体系下 重写
。多态体现在:代码运行时,当传递不同的对象时,会调用对应类中的方法。 |
---|
对比上面Animal和Dog的eat方法我们可得到以下关于方法重写的结论:
向上转型:父类引用 引用了子类的对象。
向上转型是发生多态的条件之一。
动态绑定:方法重写,父类和子类拥有同样的方法(子类通过重写父类的eat方法),(通过父类对象的引用调用此时调用的是子类的方法),如下图所示:我们通过父类的引用animal1来调用子类的eat方法这就是动态绑定。
动态绑定,编译时期无法确定或者确定其他的。我们可以通过下图中的反汇编代码看到在编译期间,我们通过animal1引用调用的eat方法还是Animal的,而在根据运行结果我们可以知道,运行的时候animal1这个引用调用的是Dog的eat方法,这个方法从animal绑定到(dog的eat方法)或其它函数方法执行的过程就叫做动态绑定
。
静态绑定: 重载就是一种静态绑定,编译时期绑定的,根据所传参数的不一样来确定调用哪一个方法。
方法的重载,在编译时根据参数个数就能够自动调用相应的方法。
当父类有构造方法时,子类在进行构造之前需要先帮助父类构造进行初始化
向上转型的第一种传参方式:直接赋值
向上转型的第二种传参方式:通过传参
本来Animal
就是父类类型的引用,然后返回任何一个子类对象,这三种写法本质一样,只是搭配组合的问题。
向上转型的第三种方式:通过返回值
重写
不能进行重写的情况
1.被final
修饰的叫密封方法,是不能够进行重写(@Override,作为注解用来检测是否有重写)的。
2.被static
修饰的方法也不能够进行重写
不同访问修饰符在Java中的访问权限:
访问修饰符 | 同一包中的同类 | 同一包中的不同类 | 不同包中的子类 | 不同包中的非子类 |
---|---|---|---|---|
private | √ | |||
default (no modifier) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
3.子类重写父类的时候,子类的方法访问修饰限定符权限要大于等于父类。有两个比较特殊的
private
修饰的方法不能够进行重写,这是由于private
方法的访问级别最低,他们不能被子类访问,因此也就无法被子类重写。
public
修饰的方法本来权限就已经是最大的了,所以重写的子类方法也得是public
的。4.构造方法
不能够进行重写
能够重写的条件
普通重写
类型之间构成父子关系的重写
同一个引用(animal)调用了同一个方法(eat),但是因为引用的对象(一个是mydog一个是mybird)不一样,所表现的行为不一样(狗吃狗粮鸟吃饲料),我们把这种思想称为多态
。
向上转型
package demo1;
class Aniamal{
public String name;
public int age;
public Aniamal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name+" 正在吃...");
}
}
class Bird extends Aniamal{
//创建Bird的构造方法
public Bird(String name,int age){
super(name,age);
}
public void eat(){
System.out.println(this.name + " 正在吃鸟饲料");
}
public void fly(){
System.out.println(this.name + " 正在飞翔~");
}
}
class Dog extends Aniamal{
public String color;
public Dog(String name , int age, String color){
super(name, age);
this.color = color;
}
public void barks(){
System.out.println(this.name + " 正在汪汪叫!");
}
public void eat(){
System.out.println(this.name + " 正在吃狗粮。");
}
}
public class Test {
public static void main(String[] args) {
Aniamal animal2 = new Bird("妙妙",6);
//向上转型
animal2.eat();}
}
向下转型
package demo1;
class Aniamal{
public String name;
public int age;
public Aniamal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name+" 正在吃...");
}
}
class Bird extends Aniamal{
//创建Bird的构造方法
public Bird(String name,int age){
super(name,age);
}
public void eat(){
System.out.println(this.name + " 正在吃鸟饲料");
}
public void fly(){
System.out.println(this.name + " 正在飞翔~");
}
}
class Dog extends Aniamal{
public String color;
public Dog(String name , int age, String color){
super(name, age);
this.color = color;
}
public void barks(){
System.out.println(this.name + " 正在汪汪叫!");
}
public void eat(){
System.out.println(this.name + " 正在吃狗粮。");
}
}
public class Test {
public static void main(String[] args) {
Aniamal animal2 = new Bird("妙妙",6);
//向下转型 -> 正常版
Bird bird = (Bird) animal2;
bird.fly();
Aniamal animal1 = new Dog("旺旺",7,"red");
//向下转型需要进行条件判断 -> 因为这个fly是鸟的方法
if (animal1 instanceof Bird) {
Bird bird2 = (Bird) animal1;
bird2.fly();
}else{
System.out.println("we can't use this method ");
}
}
}
java
中为了提高向下转型的安全性,引入了instanceof
,如果该表达式为true
,则可以安全转换。避免在构造方法中调用重写方法
package demo1;
class B{
public B(){
//do nothing
func();
}
public void func(){
System.out.println("B.func()");
}
}
class D extends B{
private int num = 1;
public D(){
super();
}
@Override
public void func(){
System.out.println("D.func() ");
}
}
public class Test2 {
public static void main(String[] args) {
D d = new D();
}
}
package demo1;
class B{
public B(){
//do nothing
func();
}
public void func(){
System.out.println("B.func()");
}
}
class D extends B{
private int num = 1;
public D(){
super();
}
@Override
public void func(){
System.out.println("D.func() " + num);
}
}
public class Test2 {
public static void main(String[] args) {
D d = new D();
}
}
func
加上参数num,打印结果居然是0,而不是1,这是为什么呢?下面我们将通过调试看一下它是怎么运行的。private int num = 1
所以此时num的值还是默认为0,因此我们的打印结果是0,然后再往下执行子类D的实例代码块。多态的优缺点
package demo2;
class Shape {
public void draw(){
System.out.println("画图形!");
}
}
class Cycle extends Shape{
@Override
public void draw() {
System.out.println("○");
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("矩形");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("△");
}
}
public class Test {
public static void drawMap(Shape shape){
shape.draw();
}
public static void main(String[] args) {
Rect rect = new Rect();
Cycle cycle = new Cycle();
Triangle triangle = new Triangle();
drawMap(rect);
drawMap(cycle);
drawMap(triangle);
}
}
上面的代码中:通过drawMap()进行向上转型,这个shape引用分别指向rect,cycle,triangle这三个对象,然后通过一个shape这个引用直接调用draw方法,打印出来的结果分别表现出不同的形状,这就体现了多态(都是画,但是画的图案不一样)。
if-else
语句打印○,矩形,○,矩形,△
,其代码如下:package demo2;
class Shape {
public void draw(){
System.out.println("画图形!");
}
}
class Cycle extends Shape{
@Override
public void draw() {
System.out.println("○");
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("矩形");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("△");
}
}
public class Test {
//************************************************
public static void main(String[] args) {
Rect rect = new Rect();
Cycle cycle = new Cycle();
Triangle triangle = new Triangle();
String[] strings = {"○","矩形","○","矩形","△"};
for(String s : strings){
if(s.equals("○")){
cycle.draw();
} else if (s.equals("矩形")) {
rect.draw();
}else {
triangle.draw();
}
}
//************************************************
}
多态
进行打印,其代码如下所示:package demo2;
class Shape {
public void draw(){
System.out.println("画图形!");
}
}
class Cycle extends Shape{
@Override
public void draw() {
System.out.println("○");
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("矩形");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("△");
}
}
public class Test {
//*****************通过多态打印*******************************
public static void main(String[] args) {
Rect rect = new Rect();
Cycle cycle = new Cycle();
Triangle triangle = new Triangle();
//数组当中放的是相同数据类型的元素,这样写相当于向上转型,他和下面的注释代码等价
Shape [] shapes = {cycle,rect,cycle,rect,triangle};
// Shape rect = new Rect();
// Shape cycle = new Cycle();
// Shape triangle = new Triangle();
for(Shape myshape : shapes){
myshape.draw();
}
}
package demo2;
class Shape {
public void draw(){
System.out.println("画图形!");
}
}
class Flower extends Shape{
@Override
public void draw() {
System.out.println("❀");
}
}
class Cycle extends Shape{
@Override
public void draw() {
System.out.println("○");
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("矩形");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("△");
}
}
public class Test {
//*****************通过多态打印*******************************
public static void main(String[] args) {
Rect rect = new Rect();
Cycle cycle = new Cycle();
Triangle triangle = new Triangle();
Flower flower = new Flower();
//数组当中放的是相同数据类型的元素,这样写相当于向上转型,他和下面的注释代码等价
Shape [] shapes = {cycle,rect,cycle,rect,triangle,flower};
// Shape rect = new Rect();
// Shape cycle = new Cycle();
// Shape triangle = new Triangle();
for(Shape myshape : shapes){
myshape.draw();
}
}