{"id":600,"date":"2009-02-13T11:18:10","date_gmt":"2009-02-13T16:18:10","guid":{"rendered":"http:\/\/unitstep.net\/?p=600"},"modified":"2009-02-13T14:09:37","modified_gmt":"2009-02-13T19:09:37","slug":"java-polymorphism-and-overriding-methods","status":"publish","type":"post","link":"https:\/\/unitstep.net\/blog\/2009\/02\/13\/java-polymorphism-and-overriding-methods\/","title":{"rendered":"Java Polymorphism and Overriding Methods"},"content":{"rendered":"
Most Java developers will be familiar with polymorphism – we’ve all seen the example of the <\/p>\n First, we define a simple class with one instance method and one static method.<\/p>\n Then we extend that class with one that has identical method signatures.<\/p>\n Sorry for the funky variable names in The first two are fairly straightforward, since for variables The short answer is this: When instance methods are invoked, they will always be called on the instantiated type, regardless of the declared type. When static or class methods are invoked, they will be called on the declared type.<\/strong><\/p>\n You can think of the declared type as a “window” into the actual instantiated type. This “window” provides a view as to what methods are available for invocation and provides these hints to the compiler. This is why you cannot call a method that exists on an instantiated type unless it has been declared or exists on the declared type. (The use of interfaces provides the best example of this)<\/p>\n When an instance method<\/em> is invoked, the JVM will then determine the runtime<\/em> type of the variable and then call the appropriate method on that object. This is why for the last two examples, the output was However, when a static or class method<\/em> is invoked, it will always be invoked from the declared type<\/em>, regardless of what the runtime or instance type is. This is because static methods are per-class<\/em> rather than per-instance<\/em> and thus the exact method invoked can be determined at compile time from the declared type. This is why for the last two examples, the output is from the the method defined on class Dog<\/code> and
Cat<\/code> classes inheriting from some abstract Animal<\/em> class and having their
say()<\/code> methods produce different results. But it’s still worthwhile to look at a few simple examples to reinforce the concepts.<\/p>\n
public class A\r\n{\r\n public String getName()\r\n {\r\n return \"I am A\";\r\n }\r\n\r\n public static String getStaticName()\r\n {\r\n return \"Statically A!\";\r\n }\r\n}<\/code><\/pre>\n
public class B extends A\r\n{\r\n \/\/ Note: @Override only makes sense for instance methods.\r\n \/\/ The annotation is not needed but makes for best practices, since if the\r\n \/\/ method DOES NOT override a superclass, a compile-time error will be\r\n \/\/ generated, limiting damage. (@Override was added in Java 1.5)\r\n @Override\r\n public String getName()\r\n {\r\n return \"I am B\";\r\n }\r\n\r\n public String onlyOnB()\r\n {\r\n return \"Only available on B\";\r\n }\r\n\r\n \/\/ Cannot @Override, generates a compile error. Instead, this methods\r\n \/\/ `hides` the one in the super class.\r\n public static String getStaticName()\r\n {\r\n return \"Statically B!\";\r\n }\r\n\r\n public static void main( String[] args )\r\n {\r\n A a = new A();\r\n B b = new B();\r\n\r\n A b_as_a = new B();\r\n A b_as_a_copied_from_reference = b;\r\n\r\n System.out.println(a.getName());\r\n System.out.println(a.getStaticName() + \"\\n\");\r\n\r\n System.out.println(b.getName());\r\n System.out.println(b.getStaticName() + \"\\n\");\r\n\r\n System.out.println(b_as_a.getName());\r\n System.out.println(b_as_a.getStaticName() + \"\\n\");\r\n\r\n System.out.println(b_as_a_copied_from_reference.getName());\r\n System.out.println(b_as_a_copied_from_reference.getStaticName() + \"\\n\");\r\n }\r\n}<\/code><\/pre>\n
main()<\/code>, but camelCase just didn’t look good. Anyway, can you guess the output of the program? It’s actually quite interesting:<\/p>\n
I am A\r\nStatically A!\r\n\r\nI am B\r\nStatically B!\r\n\r\nI am B\r\nStatically A!\r\n\r\nI am B\r\nStatically A!<\/code><\/pre>\n
a<\/code> and
b<\/code>, the declared type matches the instantiated type, so there can be no doubt. But what happens when the declared type does not match the instantiated type, as in the second two examples?<\/p>\n
Declared type vs. instantiated type<\/h2>\n
I am B<\/code>, even though the declared type was
A<\/code>. This is what allows polymorphism to work in Java.<\/p>\n
A<\/code>, the declared type of the two variables.<\/p>\n
What Sun has to say<\/h2>\n