I am quite confused about abstract method signitures that Java classes implement.
For example, consider:
interface Programmer {
Object program();
}
class Linus implements Programmer {
public String program() {
return "goto end;";
}
}
public class Main {
public static void main(String[] args) {
System.out.println(new Linus().program());
}
}
This is apparently acceptable, since anything expecting an Object to come from Linus.program() will get one (specifically, a String).
But now consider this:
interface OS {
void run(String code);
}
class Linux implements OS {
public void run(Object code) {
System.out.println("Hello world");
}
}
public class Main {
public static void main(String[] args) {
new Linux().run("print 'Hello world'");
}
}
This fails to compile, and yields the error:
The type Linux must implement the inherited abstract method OS.run(String)
Now, anything could expected to be able to pass a String into any instance of the OS interface, and you could certainly do that with Linux.
I see no reason why the second one fails to compile. Of the consequences of having Java compile the second program, am I missing something that makes this prohibitive?
What you are doing for the second case is method over-loading.
Signature of a method is "method-name" and "number and types of arguments"
In the second case you are changing the type of argument which compiler things is another method, and ask you to implement the abstracted (unimplemented) methods. And if you implement the methods present in the interface public void run(String code) then this method public void run(Object code) will be treated as an overloaded method.
NOTE: Method over-riding is never based on the return type of the method. As return type is not considered as method's signature
You cannot pass an instance of base class Object in place of an instance of class String but the reverse is valid. In your interface OS, the parameter to the run method is of type String and in the implementation class you are generalising the parameter to be of type Object which is not allowed. Hence, the compiler complains.
You say "Now, anything could expected to be able to pass a String into any instance of the OS interface, and you could certainly do that with Linux." => Problem is that you could, but are not required to.
Consider this: as Linux version of the method takes an Object as a parameter, you could try and pass a Collection, for example. Thus you would not respect the interface, which explicitely restricts the parameter to being a String. That is why Linux version of the method is not considered to be the "child" of OS version.
And as each method in the interface needs to have its "child", the compiler complains you did not implement a "child" for OS.run(String)
Related
I was just learning about method refernce concept of java 8.What I found strange is the example where a method reference is assigned to the interface variable without implementing the interface, And calling abstract method of interface is calling the method referenced.
interface Sayable {
void say();
}
public class InstanceMethodReference {
public void saySomething() {
System.out.println("Hello, this is non-static method.");
}
public static void main(String[] args) {
InstanceMethodReference methodReference = new InstanceMethodReference();
Sayable sayable = methodReference::saySomething;
sayable.say();
}
}
Above code prints the message of saySomething method, I am trying to understand how the memory allocation for methods and objects is done here and how overall this works.
Any help appreciated.
This is just a syntactic sugar to an anonymous implementation or a lambda with a closure (referring to a state outside of the definition, in your case the instance of methodReference). Method references and lambdas are treated equally with that respect. So the same memory allocation really.
The use of method references (or lambdas) is possible when an interface has only one non-static method and the signature of that method matches that of the lambda or the method reference. In this case the compiler will know how to wrap it and therefore it will be assignable. It does not matter if it is one of "standard" interfaces such as Function, Consumer or Supplier or a custom one, it should be a functional interface that's all.
The following is quoted from the official Oracle Java documentation:
Arrays.sort(rosterAsArray, Person::compareByAge);
The method reference Person::compareByAge is semantically the same as the lambda expression (a, b) -> Person.compareByAge(a, b). Each has the following characteristics:
Its formal parameter list is copied from Comparator.compare, which is (Person, Person).
Its body calls the method Person.compareByAge.
While your Sayable does not explicitly declare that it is a #FunctionalInterface, it indeed is one, as it has exactly one non-static method.
Any functional interface can be assigned a lambda-like expression (such as () -> printf("bla bla")) or a method reference (such as methodReference::saySomething). That's it.
interface Rideable {
CarRide getCarRide(String name);
}
class CarRide {
private String name;
public CarRide(String name) {
this.name = name;
}
}
public class Test_QN_26 {
public static final int MIN = 1;
public static void main(String[] args) {
//C. (Only one correct):
Rideable rider = CarRide::new;
CarRide vehicle = rider.getCarRide("MyCarRide");
System.out.println("vehicle.toString() "+ vehicle.toString());
enter code here
}
}
public class Test
{
public Test(Object o) {
System.out.println("object");
}
public Test(int[] o) {
System.out.println("array");
}
public static void main(String[] args) {
new Test(null);
}
}
Output :
array
Can somebody please explain me the reason behind this?
The rule is: the more specific method will be called. In this case, it's the method receiving a int[] which is more specific than the one receiving a java.lang.Object parameter.
Here's a link to Java's official documentation referencing to this case. Take a look at section 15.2.2. Quoting an interesting part (section 15.2.2.5):
If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than
another if any invocation handled by the first method could be passed
on to the other one without a compile-time type error.
An another one:
It is possible that no method is the most specific, because there are
two or more methods that are maximally specific. In this case:
If all the maximally specific methods have override-equivalent
(§8.4.2) signatures, then: If exactly one of the maximally specific
methods is not declared abstract, it is the most specific method.
Otherwise, if all the maximally specific methods are declared
abstract, and the signatures of all of the maximally specific methods
have the same erasure (§4.6), then the most specific method is chosen
arbitrarily among the subset of the maximally specific methods that
have the most specific return type. However, the most specific method
is considered to throw a checked exception if and only if that
exception or its erasure is declared in the throws clauses of each of
the maximally specific methods. Otherwise, we say that the method
invocation is ambiguous, and a compile-time error occurs.
It's always subclass would be preferred over the parent class. If you want to call Object one you could do the following:
new goFuncTest((Object) null);
As pablo's answer suggests, the most specific / least generic method will be called. Actually, the classlevel in the class hierarchy is checked to decide which method to call. The method with lower class level is called.
If 2 classes are at the same level, then you will get a compile time error stating - ambiguous method call just like in the below case.
public class Sample {
void someMethod(Object o) {
System.out.println("object");
}
void someMethod(String s) {
System.out.println("String");
}
void someMethod(int[] o) {
System.out.println("int[]");
}
public static void main(String[] args) {
new Sample().someMethod(null); // error ambiguous call both array and String are direct children of Object
}
Case -2 : To prove that the method with lower class level will be called.
public class Sample {
void someMethod(Object o) {
System.out.println("object");
}
void someMethod(OutputStream os) {
System.out.println("OutputStream");
}
void someMethod(FileOutputStream fos) {
System.out.println("FileOutputStream");
}
public static void main(String[] args) {
new Sample().someMethod(null);
}
}
O/P :FileOutputStream
Since FileOutputStream is child of OutputStream which is again a child of Object class (FileOutputStream is also a child of both OutputStream and Object classes). So the compiler goes like this Object --> OutputStream --> FileOutputStream while resolving the method call.
Thumb rule is child first in method call. As Object is parent of all and as null can be assigned to any type of object instance variable, it will first match any java type(which of course is child of object) and then super parent i.e. Object.
up gradation of Null to Array is preferred over casting it to Object. Object is top in the hierarchy while Array is closest to Null.
This is like up gradation of byte to int.
Is there a way to capture the type of an anonymous class?
In the following example, how can i invoke the method g2 of the anonymous class? can't think of a specific case that it would be absolutely useful. and i'm aware that anonymous classes are for "on-the-fly" use. however, wondering.
If i can't invoke it, what's the use of being able to define it (if any-- other than being a helper to other methods of the anonymous class itself) in the anonymous class?
// http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
public class SomeClass {
abstract class HelloWorld { abstract public void greet(); }
public void sayHello() {
class EnglishGreeting extends HelloWorld { // local class
String name = "world";
public void greet() { System.out.println("Heya " ); }
public void gg() { System.out.println("do this as well.. ");} }
HelloWorld englishGreeting = new EnglishGreeting();
HelloWorld frenchGreeting = new HelloWorld() { // anonymous class
public void g2() { System.out.println("do this too.. ");}
public void greet() { System.out.println("Salute "); }
};
englishGreeting.greet();
((EnglishGreeting)englishGreeting).gg();
frenchGreeting.greet();
// ((frenchGreeting.getClass())frenchGreeting).g2(); // gives a checked error
}
public static void main(String... args) {
SomeClass myApp = new SomeClass();
myApp.sayHello();
}
}
Note: saw Can't call anonymous class method & Anonymous Inner Classes Inside Methods along with some other relevant discussions.
TIA.
//==============================================
EDIT:
the below worked-- one step closer to it for whatever its worth. not looking up its reference type when the method is invoked right on the new object.
HelloWorld frenchGreeting = new HelloWorld() {
public HelloWorld g2() { System.out.println("do this too.. "); return this; }
public void greet() { System.out.println("Salute "); }
}.g2();
You can only call it directly, e.g.
new HelloWorld() {
// ...
}.g2();
However, notice that you can't assign the variable and call it directly, and you can't call it elsewhere in the method. Still, this is the closest thing I could think of to answering your question.
no, you cannot call g2. actually, anonymous class in java serves as a short hand to implement an instance of an interface only used in one place. with specified interface, the method you want to be called should be specifically defined by that interface.
the reason to allow you define non-interface method is because designers considered the case when you want to implement helper method.
i think anonymous interface is widely used.
Is there a way to capture the type of an anonymous class?
No. You can only access it for reflection.
If i can't invoke it, what's the use of being able to define it (if any-- other than being a helper to other methods of the anonymous class itself) in the anonymous class?
Since they can only be referenced from within the anonymous type itself, they are of no use outside of it. So, as you say, they may be used to organize the logic within the class, but that's about it. The only exception is the edge case that #bcsb1001 describes, in which you invoke the method directly on the anonymous object creation expression (and not the variable to which it is assigned).
the below worked...
That's because the type of the expression new HelloWorld() { ... } is the type of the anonymous class. Since the creation expression has the actual anonymous class type, you can use it to access any members it declares. However, since the class is anonymous, it has no name, so you cannot declare a variable of the concrete anonymous type. The closest you can get is declaring a variable of HelloWorld. Since the variable is declared as HelloWorld, you can only use it to access members declared on HelloWorld or one of its supertypes.
If Java added support for inferred types in declarations, you could write something like var g = new HelloWorld() { ... }; (C# style) or auto g = new HelloWorld() { ... }; (C++ style), and the type of g would be inferred from the assignment. That would allow you to capture the anonymous type without needing a type name. However, Java has no such capabilities at this time.
Let's say I got the following, I would even call it pseudo-code
public class someClass {
public someClass{
example("Hello Stackoverflow");
}
#Override
public void example(){
System.out.println("Hello World");
}
public void example(String Hello){
System.out.println(Hello);
}
}
In this code the method public void example(String Hello) would be called instead of the public void example() method. How is the compiler working in this case ? The compiler has to decide which method to call in this case, because they got the same name. Is there something like an order e.g. first try #Override method, if that's not working go for the normal one. Or how does that work ?
No, what you've shown isn't overriding at all - it's overloading. (The use of the #Override annotation is obviously to do with overriding, but it's incorrect used here - there's no superclass method to override.)
Overriding is when a method signature is declared in a superclass, and then overridden in a subclass (with the same signature). The method implementation is chosen at execution time based on the execution-time type of the object you call it on.
Overloading is when more than one method is present with the same name, but different signatures. When invoking the method, the correct signature is picked at compile time based on the compile-time types of the arguments to the method.
For example:
public void foo(int x) {}
public void foo(String y) {}
public void foo(Object o) {}
public void foo() {}
foo(50); // Calls the first method
foo("hello"); // Calls the second method
// Calls the third method, because the compile-time type of the argument is
// Object, even though it's actually a reference to a string at execution time
foo((Object) "hello");
foo(); // Calls the fourth method
The #Override annotation tells the compiler: "Please fail to compile me unless I'm overriding an existing method defined in a parent class or an interface I implement."
However, you are doing method overloading - i.e. methods with the same name but different arguments.
Consequently, your code won't compile because your example() method doesn't override a method in a parent class or interface. Instead, it overloads another method in the same class. There is no annotation for that.
An example of a valid override would be adding a toString() method to your class, which would override the method declared in the Object class:
public class someClass {
public someClass{
example("Hello Stackoverflow");
}
public void example(){
System.out.println("Hello World");
}
public void example(String Hello){
System.out.println(Hello);
}
#Override
public String toString() {
return "Hello, World!";
}
}
Because you are calling a function with a parameter
example("Hello Stackoverflow");
that is function overloading study about overloading here
This has nothing at all to do with the #Override annotation.
This has nothing at all to do with the #Override annotation.
You can overload methods: having more than one method with the same name but different types and number of parameters.
The compiler will choose the method with the signature that matches best (the exact rules are a bit complicated since Java5, what with varargs and auto-boxing).
In your case, you call a method with a String parameter.
A method without parameters does not apply, will not be considered.
It's not an #Override since you do not override a parent method and code will not compile.
This is overload.
Here, you have 2 distinct methods. One take a parameter and the other one not.
So it simple:
when you call method with a parameter, it's the example(String hello) which will be called.
when you call method without a parameter, it's the example() method which will be called.
This is not an override.
I have an interface called Functions without any method defined in it. Then I have an implementation class that implements that interface and has also a method defined in the implementation class. If I create a variable of the interface type and assign it with a new instance of the implementation type (which has a method defined in it). Why can't I access that method from the variable? I think I'm missing something here. I was under the impression that if the variable of the interface type has been assigned an instance of the implementation type which has a method defined in it, than that variable can be used to run the method.
Please advise. Thank you in advance.
Conceptually, you are doing the wrong thing here.
If you want to call "that method" then you should use a variable of the implementation type, not the interface type.
Alternatively, if "that method" really does belong in the intended functionality the interface, then you should move it "up" to the interface.
As far as I can understand, your problem is the following:
// Interface with no methods
public interface Functions {
}
// Implementation class with a method defined in it
public class Implementation implements Functions {
public void foo() {
System.out.println("Foo");
}
}
public class Main {
public static void main(String[] args) {
// Create a variable from the interface type and
// assign a new instance of the implementation type
Functions f = new Implementation();
// You try to call the function
f.foo(); // This is a compilation error
}
}
That's the correct behavior, this is not possible. Because the compiler sees that variable f has the (static) type of Functions, it only sees the functions defined in that interface. The compiler is not aware of whether the variable actually contains a reference to an instance of the Implementation class.
To solve the issue you either should declare the method in the interface
public interface Functions {
public void foo();
}
or make your variable have the type of your implementation class
Implementation f = new Implementation();
You are restricted to the methods defined by the Reference type, not the Instance type, for example:
AutoClosable a = new PrintWriter(...);
a.println( "something" );
Here, AutoClosable is the reference type and PrintWriter is the instance type.
This code will give a compiler error because the only method defined in AutoClosable is close().
You cannot do that, consider this example:
interface Foo {
}
And class:
class FooBar implements Foo {
public void testMethod() { }
}
class FooBarMain {
public static void main(String[] args) {
Foo foo = new FooBar();
//foo.testMethod(); this won't compile.
}
}
Because at the compile time, compiler will not know that you are creating a new FooBar();and it has a method called testMethod() which will be determined dynamically. So it expects whatever you are accessing via interface variable should be available in your interface.
What you can do is if you want to access that method via interface variable, it's better to move that method to interface and let clients implement it.
Let me know if you have doubts on this.