
多态
多态:完成某个行为,当不同对象去完成时会产生出不同的状态。(同一件事,发生在不同对象身上,产生不同的效果。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();
}
}