Think in Java——多态

版权声明:本文为博主原创文章,转载注明出处即可。 https://blog.csdn.net/bskfnvjtlyzmv867/article/details/86647879

多态调用

  1. 一个方法调用一个方法主体 关联起来被称作绑定。绑定分为前期绑定与后期绑定,多态方法的具体调用依靠前期绑定是不行的,编译器不知道对象的具体类型无法具体调用,所以只能依靠后期绑定,也叫动态绑定、运行时绑定;
  2. Java除了 final 方法和 static 方法(private 方法属于 final 方法)之外,其他方法的调用默认就是后期绑定。final 方法意味着不想被子类覆盖,这样可以有效的“关闭”动态绑定,或者说告诉编译器不需要对其动态绑定,这样编译器会对 final 方法调用生成更有效的代码(但实际上有效不到哪去,所以不要以优化性能特意加 final);
  3. 子类是不继承父类的 static 变量和方法的,因为这是属于类本身的,所以说没有多态这一特性,但是子类是可以访问的。子类和父类中同名的 static 变量和方法都是相互独立的,并不存在任何的重写的关系。
    public class Main {
        public static void haha() {
            System.out.println("hehe");
        }
    }
    
    public class ExtendMain extends Main {
    	// 不是重写
        public static void haha() {
            System.out.println("haha");
        }
    
        public static void main(String[] args) {
            Main h = new ExtendMain();
            h.haha();
            ExtendMain hh = new ExtendMain();
            hh.haha();
        }
    }
    // 输出
    // hehe
    // haha
    
  4. 子类覆盖父类的方法,加上 final 也是覆盖,对于父类方法的调用是动态绑定,而对于子类 final 方法的调用则直接前期绑定即可;
    public class Main {
        public void haha() {
            System.out.println("hehe");
        }
    }
    
    public class ExtendMain extends Main {
        @Override
        public final void haha() {
            System.out.println("haha");
        }
    
        public static void main(String[] args) {
            Main h = new ExtendMain();
            h.haha();  // 动态绑定
            ExtendMain hh = new ExtendMain();
            hh.haha(); // 前期绑定
        }
    }
    // 输出
    // haha
    // haha
    
  5. 子类不会覆盖父类的私有方法,私有相当于 final,因为对子类不可见,所以即使子类看似定义了像覆盖父类的方法,也不会发生多态;
  6. 对于成员变量/域,也是没有多态的,任何域的访问操作都将由编译器解析,因此不会多态

构造器与多态

  1. 构造函数其实相当于 static 的,因此也没有多态一说;
  2. 子类对象构造器的调用顺序为:先自顶向下调用父类的构造器,然后按照声明顺序调用成员的初始化方法,最后再调用构造器的主体。当然,在第一步调用父类构造器的时候也要按着三步走;
  3. 看一个例子:
    class Glyph {
    	void draw() {
    		System.out.println("Glyph draw");
    	}
    	Glyph() {
    		System.out.println("Glyph before draw");
    		draw();
    		System.out.println("Glyph after draw");
    	}
    }
    
    class SubGlyph {
    	private int radius = 1;
    	SubGlyph(int r) {
    		radius = r;
    		System.out.println("SubGlyph radius = " + radius);
    	}
    	void draw() {
    		System.out.println("SubGlyph.draw radius = " + radius);
    	}
    	
    	public static void main(String[] args) {
            new SubGlyph(5);
        }
    }
    
    // 输出
    // Glyph before draw
    // SubGlyph.draw radius = 0 为什么等于0?
    // Glyph after draw
    // SubGlyph radius = 5
    

猜你喜欢

转载自blog.csdn.net/bskfnvjtlyzmv867/article/details/86647879