美文网首页
Java's Dynamic Method Selection

Java's Dynamic Method Selection

作者: Kulbear | 来源:发表于2018-08-04 01:42 被阅读0次

    This article is fairly under-construction...

    Java's dynamic method selection is painful to understand if you don't get its design methodology.

    We're gonna go through a few simple code snippets to make sure we can understand it with keeping some really simple principles in mind.

    Suppose we have the following interface and class implementation:

    public interface Animal {
        default void greet(Animal a) {
            System.out.println("greet :: Animal!");
        }
    
        default void sniff(Animal a) {
            System.out.println("sniff :: Animal!");
        }
    
        default void flatter(Animal a) {
            System.out.println("flatter :: Animal!");
        }
    }
    
    public class Dog implements Animal {
        public void sniff(Animal a) {
            System.out.println("sniff :: Dog!");
        }
    
        public void flatter(Dog d) {
            System.out.println("flatter :: Dog!");
        }
    }
    

    Let's assume we have the following lines of code in a valid main function that can be run directly. What is the expected output for the program?

    Animal a = new Dog();
    Dog d = new Dog();
    a.greet(d);
    

    It should be not hard for you to convince yourself a line with greet :: Animal! will be printed out. OK, what about the following line?

    d.flatter(d);
    d.flatter(a);
    

    The answer is

    flatter :: Dog!
    flatter :: Animal!
    

    You should be able to notice that the flatter method in class Dog is actually overloading the flatter method in interface Animal rather than overriding it (the method signatures are different!). But how does Java handle all these complicated things?

    Be relaxed, let's understand and remember the following principles:

    • If we have a variable has static type X and dynamic type Y, then if Y overrides the method, Y's method is used instead.
    • At compile time, the compiler will verify X has a method that can handle the given parameter. If multiple methods can handle, it records the most specific one.
    • At runtime, if Y overrides the recorded signature, use the overridden method.

    We provide a more concrete example and comments for a better understanding of these principles.

    public class Main {
        public static void main(String[] args) {
            // static: Animal
            // dynamic: Dog
            Animal a = new Dog();
            // static: Dog
            // dynamic: Dog
            Dog d = new Dog();
    
            // compile: Animal's `greet(Animal a)` is recorded
            // run: not found Dog's `greet(Animal a)`
            // result: Animal.greet
            a.greet(d);
            // compile: Animal's `sniff(Animal a)` is recorded
            // run: found Dog's `sniff(Animal a)`
            // result: Dog.sniff
            a.sniff(d);
            // compile: Dog's `sniff(Animal a)` is recorded
            // run: keep Dog's `sniff(Animal a)`
            // result: Dog.sniff
            d.sniff(a);
            // compile: Animal's flatter(Animal a) is recorded
            // run: not found Dog's flatter(Animal a)
            // result: Animal.flatter
            a.flatter(d);
            // compile: Animal's flatter(Animal a) is recorded
            // run: not found Dog's flatter(Animal a)
            // result: Animal.flatter
            a.flatter(a);
            // compile: Dog's flatter(Dog d) is recorded
            // run: keep Dog's flatter(Dog d)
            // result: Dog.flatter
            d.flatter(d);
            // compile: Animal's flatter(Animal a) is recorded,
            // as Dog does have a flatter method but not with the same signature.
            // run: not found Dog's flatter(Animal a)
            // result: Animal.flatter
            d.flatter(a);
        }
    }
    

    It worth to note that although in the example above Animal is an interface, the exact same idea can be applied for extends as well. Another example is provided here for a practice purpose.

    public class Main {
        public static void main(String[] args) {
            // static: Bird
            // dynamic: Falcon
            Bird bird = new Falcon();
            // static: Falcon
            // dynamic: Falcon
            Falcon falcon = (Falcon) bird;
    
            // compile: Bird's `gulgate(Bird b)` is recorded
            // run: not found Falcon's `gulgate(Bird b)`
            // result: Bird.gulgate
            bird.gulgate(bird);
    
            // compile: Bird's `gulgate(Bird b)` is recorded
            // run: not found Falcon's `gulgate(Bird b)`
            // result: Bird.gulgate
            bird.gulgate(falcon);
    
            // compile: Bird's `gulgate(Bird b)` is recorded
            // as Falcon does have a gulgate method but not with the same signature.
            // run: not found Falcon's `gulgate(Bird b)`
            // result: Bird.gulgate
            falcon.gulgate(bird);
    
            // compile: Falcon's `gulgate(Falcon f)` is recorded
            // run: keep Falcon's `gulgate(Falcon f)`
            // result: Falcon.gulgate
            falcon.gulgate(falcon);
        }
    }
    
    
    class Bird {
        public void gulgate(Bird b) {
            System.out.println("Bird Gul!");
        }
    }
    
    class Falcon extends Bird {
        public void gulgate(Falcon f) {
            System.out.println("Falcon Gul!");
        }
    }
    

    Reference

    相关文章

      网友评论

          本文标题:Java's Dynamic Method Selection

          本文链接:https://www.haomeiwen.com/subject/vbdpvftx.html