Java 8 reference to a static method vs. instance method - java

say I have the following code
public class A {
int x;
public boolean is() {return x%2==0;}
public static boolean is (A a) {return !a.is();}
}
and in another class...
List<A> a = ...
a.stream().filter(b->b.isCool());
a.stream().filter(A::is);
//would be equivalent if the static method is(A a) did not exist
the question is how do I refer to the instance method version using the A::is type notation? Thanks a lot

In your example, both the static and the non-static method are applicable for the target type of the filter method. In this case, you can't use a method reference, because the ambiguity can not be resolved. See ยง15.13.1 Compile-Time Declaration of a Method Reference for details, in particular the following quote and the examples below:
If the first search produces a static method, and no non-static method is applicable [..], then the compile-time declaration is the result of the first search. Otherwise, if no static method is applicable [..], and the second search produces a non-static method, then the compile-time declaration is the result of the second search. Otherwise, there is no compile-time declaration.
In this case, you can use a lambda expression instead of a method reference:
a.stream().filter(item -> A.is(item));
The above rule regarding the search for static and non-static methods is somewhat special, because it doesn't matter, which method is the better fit. Even if the static method would take an Object instead of A, it's still ambiguous. For that reason, I recommend as a general guideline: If there are several methods with the same name in a class (including methods inherited from base classes):
All methods should have the same access modifiers,
All methods should have the same final and abstract modifiers,
And all methods should have the same static modifier

We can not use not static methods or non-global methods by using className::methodName notation.
If you want to use methods of a particular class you have to have an instance of the class.
So if you want to access is() method then you can use :
A a = new A();
a.is();
OR
(new A()).is();
Thanks.

Related

Java - Is it possible to write public void() in Constructor?

I couldn't find information if it is possible to write public void in constructor section. Is it possible?
At the byte code level, a constructor is always void so it would be redundant to specify it. i.e. the constructor is always called <init>V i.e. the V is the return type where V == void. Similarly the static initialiser is <clinit>V You will see this notation if you take a stack trace (e.g. print an exception) while in these methods.
The constructor actually takes the object to be initialised as an argument as the object is created before calling the constructor. Note: you can create the object without calling a constructor with Unsafe.allocateInstance(Class)
I couldn't find information if it is possible to write public void in constructor section. Is it possible?
It is not possible to write it as Java distinguishes a constructor from a method is that it must have the same name as the class, and it must not specify a return type. If you specify a return type, it assumes it's a method.
The notation x = new Clazz() also limits the number of return values to 1 which is the object. There is no easy way to modify this notation to return more than one object. i.e. supporting a return type for constructors would not be easy.
If you want to define a return type, most likely you are thinking of a factor method like this.
public static MyInterface createObject() {
return new MyClass();
}
Note how the return type is different to the class actually created, but there is still only one reference returned.
The constructor syntax is defined in the Java Language Specification. Anything else is incorrect.
The question is unclear. Peter Lawrey answered one interpretation, this is an answer to another.
You cannot declare methods within a constructor. You can, however, declare a class and declare variables.
Because you are able to declare a class within a constructor, you could declare a method inside of a class and then use the class. If the method isn't static you can construct an object of the class.
No, Java only allows a method to be declared within a class, not within another method or constructor.Indirectly you can do something like this :
public A() {
class B {
public void m() {
}
}
}

Implements method of interface, method call and type cast

Consider the followoing code
interface MyInterface{
void method(String s);// if we write static modifier we have compile error
}
class MyClass implements MyInterface{
public static void main(String[] args){
myMethod(new Object());//Compile error
}
static void method(String s){...}// compile error
static void myMethod(Number n){...}
}
Why we cant define static method in interface?
Why we cant implements method() with static modifier?
When we are calling myMethod with reference to Object we have compile error. As i understood, compiler doesnt cast automatically, isnt it?
Consider the following code
Object someObj;
...
Number n= (Number) someObj;
What compiler is doing when we cast to Number in this case?
Why we cant define static method in interface?
All the methods of an interface are by default public abstract. Using static modifier doesn't make sense. Because the invocation of static methods aren't polymorphic. In the sense, you can't override them. You invoke the static methods on the class name only. Well, you can invoke them on some reference too, but that will be ultimately resolved on the basis of the declared type of the reference. Now, since the method is by default abstract, it doesn't make sense to invoke it. It doesn't have any body to do any task.
Why we cant implements method() with static modifier?
When you try to add static modifier to the overridden method, it is not considered as being overriding. So, your class essentially have two different methods, with same name, same parameters, and same return type. That is of course not allowed inside a class.
Note that, you have to explicitly add public modifier to the overriding method in the class, else your code won't compile. The reason being, you can't decrease the visibility of the overridden method in the subclass.
When we are calling myMethod with reference to Object we have compile error. As i understood, compiler doesnt cast automatically, isnt it?
Jave doesn't do automatic narrowing conversion. You need to add cast explicitly. But even if it allowed, how you expect your code to behave, because you are trying to refer a super class object with a subclass reference? You can of course make your code to compile by adding a cast while invoking the method:
myMethod((Number)new Object()); // This will compile, but fail at runtime
The above invocation will result in a ClassCastException at runtime.
However, if you have an Object reference refering to an object of any subclass of Number, you can add an explicit cast, that will be type safe:
Object obj = new Integer(5);
Number num = (Number)obj; // This is fine. Because `obj` is referring to an `Integer`.
And finally, the signature of your main method is not correct. You are missing the public modifier.
Why we cant define static method in interface?
Interfaces are designed to work with polymorphism, basically. Polymorphism How would you know which implementation to call when calling a static method on an interface?
// Should that invoke MyClass.method or MyOtherImplementation.method?
MyInterface.method("foo");
Next:
Why we cant implements method() with static modifier?
The idea is that the method is called on some object which implements the interface - which makes it an instance method.
When we are calling myMethod with reference to Object we have compile error. As i understood, compiler doesnt cast automatically, isnt it?
No, the compiler doesn't cast automatically. There's no implicit conversion from Object to Number, so you can't call a method with a parameter of type Number with an argument of type Object.
What compiler is doing when we cast to Number in this case?
It's validating that the value of someObj is either null or a reference to an instance of Number or a subclass.
until JDK7:
because static methods are bound to the class. you normaly invoke them like this:
MyClass.method("");
you can not override them.
see 1 and all interface method are public abstract you can not change that!
no the compiler does not cast automatically
he tries to cast and fails

final static methods exam

I have been studying for my Software Development course and came across the question from a sample:
"Why does it make no sense to have both the static and final modifiers in front of a Java method?"
I have had a bit of a research and everywhere I go it says it is not bad practice and there are good reasons for doing so - for example, this stackoverflow question:
Is it a bad idea to declare a final static method?
So, is this question itself nonsensical or is there a legitimate answer to this question?
(There are no given solutions to this sample paper)
static methods cannot be overriden since they're associated not with an instance of class, but with the class itself. For example, this is how you'd usually call static method:
MyClass.myStaticMethod()
And this is how you call an instance method:
new MyClass().myInstanceMethod()
final modifier is used with methods to disallow their override in extending classes.
Because a static method cannot be overridden. There is therefore no point in marking it final.
Note however that static final variables (which are, oddly, therefore NOT variables because they cannot change) are very useful because their values can be inlined by the compiler.
Static methods can be sort of overridden (though that's not the technical term), since it is resolved at runtime, searching upwards in class chain until it's found. But this "feature" is probably a mistake; people don't use it, people don't know about it, we should pretend it doesn't exist.
From the Java Language Spec:
A class method is always invoked without reference to a particular
object. It is a compile-time error to attempt to reference the current
object using the keyword this or the keyword super.
So you cannot override a static method because it does not belong to an instance. So, the keywords this and super are not avaliable and you cannot use virtual method invocation. And if you cannot use virtual method invocation then the final keyword is of no use.
I like to think that the compiler sees method declarations like this:
public class SomeClass{
// public static classMethod() becomes
public static [final] void classMethod(){
//...
}
// and public void instanceMethod() becomes
public void instanceMethod(SomeClass this, Object super){
//....
}
}
public class SomeOtherClass extends SomeClass{
// overrides
#Override
public void instanceMethod(SomeOtherClass this, SomeClass super){
//...
}
}
And you call SomeClass instance = new SomeOtherClass().instanceMethod(); then its called the instanceMethod() of SomeOtherClass.
So the compiler does not need to copy method bodys and just pass the reference to the current object in the thread. So, when you use virtual method invocation, in fact you are calling the instanceMethod with a reference to the current object (this) and the body method of the current class is what is called.

Why can a Java static method call a constructor, but not refer to this?

My Assumptions:
Static method cannot cannot call non-static methods.
Constructors are kind of a method with no return type.
Given this example...
public class Main {
public static void main(String[] args) {
Main p = new Main(); // constructor call
k(); // [implicit] `this` reference
}
protected Main() {
System.out.print("1234");
}
protected void k() {
}
}
this line prints 1234: Main p = new Main()
this line throws an Exception: k()
Why did the example code do those two things? Don't they conflict with my above Assumptions? Are my Assumptions correct?
1 - Static method cannot cannot call non-static methods.
Sure they can, but they need an object to call the method on.
In a static method, there's no this reference available, so foo() (which is equivalent to this.foo()) is illegal.
2 - Constructors are kind of a method with no return type.
If they should be compared to methods, I would say constructors are closer to non-static methods (since there is indeed a this reference inside a constructor).
Given this view, it should be clear to you why a static method can call a constructor without any problems.
So, to sum it up:
Main p = new Main();
is okay, since new Main() does not rely on any existing object.
k();
is not okay since it is equivalent to this.k() and this is not available in your (static) main method.
No. Constructors aren't ordinary methods in this respect. The whole point of the constructor is to, well, construct a new instance of the class.
So it can be invoked in static scope too. Just think about it: if you needed an existing instance of your class in order to create a new instance of it, you would simply never be able to instantiate it ever.
A few clarifications:
Static method cannot cannot call non-static methods.
Not quite. You can call a nonstatic method from inside a static method, just you need to scope it to a specific object of that class. I.e.
p.k();
would work perfectly in your code sample above.
The call
k();
would be fine inside an instance (nonstatic) method. And it would be equivalent to
this.k();
The implied this refers to the current instance of the class. Whenever the compiler sees an unqualified call like k() within an instance method, it will automatically scope it with this. . However, since static methods aren't tied to any instance of the class, you (and the compiler) can't refer to this inside a static method. Hence you need to explicitly name an instance of the class to call an instance method on.
Rules are simple:
1 - Static method cannot cannot call non-static methods.
That's simply not true. A static method can call a non-static method, just via a "target" reference. For example, this is fine in a static method:
Integer x = Integer.valueOf(10);
int y = x.intValue(); // Instance method!
The real point is "there's no this reference within a static method".
2 - Constructors are kind of a method with no return type.
That's not a really useful model, to be honest. It makes more sense (from the caller's point of view) to consider a constructor as a static method with a return type that's the same as the declaring class, but even that's not a perfect model by any means.
I suggest you think of a constructor as a different type of member. Embrace the differences between constructors and methods, instead of trying to hide them.

A call to a static method within the parameter list of super() is valid in Java. Why?

Let's look at the following code snippet in Java.
package trickyjava;
class A
{
public A(String s)
{
System.out.println(s);
}
}
final class B extends A
{
public B()
{
super(method()); // Calling the following method first.
}
private static String method()
{
return "method invoked";
}
}
final public class Main
{
public static void main(String[] args)
{
B b = new B();
}
}
By convention, the super() constructor in Java must be the first statement in the relevant constructor body. In the above code, we are calling the static method in the super() constructor parameter list itself super(method());.
It means that in the call to super in the constructor B(), a method is being
called BEFORE the call to super is made! This should be forbidden by the compiler but it works nice. This is somewhat equivalent to the following statements.
String s = method();
super(s);
However, it's illegal causing a compile-time error indicating that "call to super must be first statement in constructor". Why? and why it's equivalent super(method()); is valid and the compiler doesn't complain any more?
The key thing here is the static modifier. Static methods are tied to the class, instance methods (normal methods) are tied to an object (class instance). The constructor initializes an object from a class, therefore the class must already have been fully loaded. It is therefore no problem to call a static method as part of the constructor.
The sequence of events to load a class and create an object is like this:
load class
initialize static variables
create object
initialize object <-- with constructor
object is now ready for use
(simplified*)
By the time the object constructor is called, the static methods and variables are available.
Think of the class and its static members as a blueprint for the objects of that class. You can only create the objects when the blueprint is already there.
The constructor is also called the initializer. If you throw an exception from a constructor and print the stack trace, you'll notice it's called <init> in the stack frame. Instance methods can only be called after an object has been constructed. It is not possible to use an instance method as the parameter for the super(...) call in your constructor.
If you create multiple objects of the same class, steps 1 and 2 happen only once.
(*static initializers and instance initializers left out for clarity)
Yep, checking the JVM spec (though admittedly an old one):
In the instance init method, no reference to "this" (including the implicit reference of a return) may occur before a call to either another init method in the same class or an init method in the superclass has occurred.
This is really the only real restriction, so far as I can see.
The aim of requiring the super constructor to be invoked first is to ensure that the "super object" is fully initialized before it is used (It falls short of actually enforcing this because the super constructor can leak this, but that's another matter).
Calling a non-static method on this would allow the method to see uninitialized fields and is therefore forbidden. A static method can only see these fields if it is passed this as argument. Since accessing this and super is illegal in super constructor invocation expressions, and the call to super happens before the declaration of any variables that might point to this, allowing calls to static methods in super constructor invocation expressions is safe.
It is also useful, because it allows to compute the arguments to the super constructor in an arbitrarily complex manner. If calls to static methods weren't allowed, it would be impossible to use control flow statements in such a computation. Something as simple as:
class Sub extends Super {
Sub(Integer... ints) {
super(Arrays.asList(ints));
}
}
would be impossible.
This is one situation where the java syntax hides what's really going on, and C# makes it a bit clearer.
In C# your B would look like
class B : A {
public B() : base(method()) {
}
private static String method() {
return "method invoker";
}
}
Although the java syntax places super(method) within the constructor it's not really called there: All the parent initialization is run before your subclass constructor. The C# code shows this a little more clearly; by placing super(method()) at the first line of the java constructor you're simply telling java to use the parameterized constructor of the super class rather than the parameterless version; this way you can pass variables to the parent constructor and they'll be used in the initialization of the parent level fields before your child's constructor code runs.
The reason that super(method()) is valid (as the first line in a java constructor) is because method() is being loaded with the static elements--before the non-static ones, including the constructors--which allows it to be called not only before B(), but before A(String) as well. By saying
public B() {
String s = method();
super(s);
}
you're telling the java compiler to initialize the super object with the default constructor (because the call to super() isn't the first line) and you're ready to initialize the subclass, but the compiler then becomes confused when it sees that you're trying to initialize with super(String) after super() has already run.
A call to super is a must in java to allow the parent to get initalized before anything with child class starts.
In the case above, if java allows String s= method(); before the call to super, it opens up flood gate of things that can be done before a call to super. that would risk so many things, essentially that allows a half baked class to be used. Which is rightly not allowed. It would allow things like object state (some of which may belong to the parent) being modified before it was properly created.
In case of super(method()); call, we still adhere to the policy of completing parent initialization before child. and we can use a static member only, and static member of child classes are available before any child objects are created anyways. so the method is avilable and can be called.
OK..i think, this one could be relevant that, if we are calling some member with Super, then it first try to invoke in super class and if it doesn't find same one then it'll try to invoke the same in subclass.
PS: correct me if i'm wrong

Categories

Resources