During navigation of the java.lang.reflect.Method class I came across the method isBridge. Its Javadoc says that it returns true only if the Java spec declares the method as true.
Please help me understand what this is used for! Can a custom class declare its method as a bridge if required?
A bridge method may be created by the compiler when extending a parameterized type whose methods have parameterized arguments.
You can find in this class BridgeMethodResolver a way to get the actual Method referred by a 'bridge method'.
See Create Frame, Synchronize, Transfer Control:
As an example of such a situation, consider the declarations:
class C<T> { abstract T id(T x); }
class D extends C<String> { String id(String x) { return x; } }
Now, given an invocation
C c = new D();
c.id(new Object()); // fails with a ClassCastException
The erasure of the actual method being invoked, D.id(String) differs in its signature from that of the compile-time method declaration, C.id(Object). The former takes an argument of type String while the latter takes an argument of type Object. The invocation fails with a ClassCastException before the body of the method is executed.
Such situations can only arise if the program gives rise to an unchecked warning (§5.1.9).
Implementations can enforce these semantics by creating bridge methods. In the above example, the following bridge method would be created in class D:
Object id(Object x) { return id((String) x); }
This is the method that would actually be invoked by the Java virtual machine in response to the call c.id(new Object()) shown above, and it will execute the cast and fail, as required.
See also Bridge:
as mentioned in the comment, bridge methods are also needed for covariant overriding:
In Java 1.4, and earlier, one method can override another if the signatures match
exactly.
In Java 5, a method can override another if the arguments match exactly but the return type of the overriding method, if it is a subtype of the return type of the other method.
Typically, a method Object clone() can be overridden by a MyObject clone(), but a bridge method will be generated by the compiler:
public bridge Object MyObject.clone();
The example shown there (quoted from the JLS) makes it sound like bridge methods are only used in situations where raw types are used. Since this is not the case, I thought I'd pipe in with an example where bridge methods are used for totally type-correct generic code.
Consider the following interface and function:
public static interface Function<A,R> {
public R apply (A arg);
}
public static <A, R> R applyFunc (Function<A,R> func, A arg) {
return func.apply(arg);
}
If you use this code in the following way, a bridge method is used:
Function<String, String> lower = new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
};
applyFunc(lower, "Hello");
After erasure, the Function interface contains the method apply(Object)Object (which you can confirm by decompiling the bytecode). Naturally, if you look at the decompiled code for applyFunc you'll see that it contains a call to apply(Object)Object. Object is the upper bound of its type variables, so no other signature would make sense.
So when an anonymous class is created with the method apply(String)String, it doesn't actually implement the Function interface unless a bridge method is created. The bridge method allows all generically typed code to make use of that Function implementation.
Interestingly, only if the class implemented some other interface with the signature apply(String)String and only if the method was called via a reference of that interface type would the compiler ever emit a call with that signature.
Even if I have the following code:
Function<String, String> lower = ...;
lower.apply("Hello");
The compiler still emits a call to apply(Object)Object.
There is actually one other way to get the compiler to call apply(String)String, but it takes advantage of the magical type assigned to an anonymous class creation expression which cannot otherwise be written down:
new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
}.apply("Hello");
Another case I stumbled across has nothing to do with generics:
protected abstract class Super {
public void m() {}
}
public class Sub extends Super {}
assert Sub.class.getMethod("m").isBridge();
Related
I do not understand one thing, should not the type of the method reference be a functional interface? So how do we pass System.out::println as a parameter to forEach?in the following code :
1-is System.out::println a Consumer?
2-if yes what is its generic type? I do not mean the type of list that is calling the method, but the generic type of the method reference that passed to the forEach.
Consumer<Integer> consumer=System.out::println;
numbers.forEach(consumer);
The type of System.out.println is not a functional interface, since System.out.println is a method, not an interface.
However, the method reference System.out::println can be used as an implementation of a functional interface. Since println accepts an argument and returns nothing, you can say that it "consumes" the argument you pass to it. Therefore it fits as an implementation of the Consumer<T> functional interface.
Note the there are multiple variants of println, which can be used to implement different functional interfaces.
For example:
A method reference to public void println(int x) can implement IntConsumer.
A method reference to public void println(double x) can implement DoubleConsumer.
A method reference to public void println(Object x) can implement Consumer<T>.
This part of code:
Consumer<Integer> consumer=System.out::println;
is equal to this lambda expression:
Consumer<Integer> consumer=i->System.out.println(i);
and above code block could be written in this way as an anonymous inner class using Consumer interface:
Consumer<Integer> consumer=new Consumer<Integer>(){
public void accept(Integer i){
System.out.println(i);
}
}
So "System.out.println" itself it is not a functional interface, but when you use :: you implicitly implement the Consumer interface.
System.out.println is method not an interface
System.out::println can be treated as an impl of interface since it takes an argument and returns nothing
I was trying to fix a Problem with an unknown Comparator (no Source access).
So I've wrote some Reflection Code to see what Types that Comparator accepts.
Surprisingly, Reflection tells me, there are two compare-Methods, one with the real type and one with Object:
Comparator<Integer> comp = new Comparator<Integer>()
{
#Override
public int compare(Integer o1, Integer o2)
{
return 0;
}
};
Method[] methods = comp.getClass().getMethods();
for (Method method : methods)
{
if(method.getName().equals("compare")){
System.out.println(method);
}
}
Output:
public int de.hinneLinks.stackoverflow.MyClass$1.compare(java.lang.Integer,java.lang.Integer)
public int de.hinneLinks.stackoverflow.MyClass$1.compare(java.lang.Object,java.lang.Object)
Where is that second compare Method coming from?
But its not usable, why?:
comp.compare(1, 2); //Compiles
comp.compare((Object)1,(Object)2); //Does not Compile
I can however call those Methods with Reflection, if i call both Methods with new Object(), i'll get two different Exceptions:
compare(java.lang.Object,java.lang.Object)
java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.Integer
compare(java.lang.Integer,java.lang.Integer)
java.lang.IllegalArgumentException: argument type mismatch
If define my Comparator with Object, then there is only one Method.
The other method (compare(Object obj1, Object2) is a bridge method generated by the compiler to preserve binary compatibility after type erasure:
When compiling a class or interface that extends a parameterized class or implements a parameterized interface, the compiler may need to create a synthetic method, called a bridge method, as part of the type erasure process. You normally don't need to worry about bridge methods, but you might be puzzled if one appears in a stack trace.
You can add a check on the method to see if it's a bridge method:
for (Method method : methods) {
if (method.getName().equals("compare") && !method.isBridge()) {
System.out.println(method);
}
}
This is due to Type Erasure, which was a design decision (preserving backwards-compatibility) in the implementation of Generics in Java.
During the type erasure process, the Java compiler erases all type parameters and replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.
This allows your class to be accessed from pre-Java-5 JVMs, where Comparator<Integer> isn't visible but Comparator is (where it supplies compare(Object, Object)). The implementation of compare(Object, Object) simply casts each argument to an Integer and calls compare(Integer, Integer), which is why you get your exceptions.
I'm reading about type inference for generics, and this code was provided as an example that fails to compile.
import java.io.*;
class LastError<T> {
private T lastError;
void setError(T t){
lastError = t;
System.out.println("LastError: setError");
}
}
class StrLastError<S extends CharSequence> extends LastError<String>{
public StrLastError(S s) {
}
void setError(S s){
System.out.println("StrLastError: setError");
}
}
class Test {
public static void main(String []args) {
StrLastError<String> err = new StrLastError<String>("Error");
err.setError("Last error");
}
}
And the explanation given in the book was:
"(It looks like the setError() method in StrLastError is overriding setError() in the LastError class. However, it is not the case. At the time of compilation, the knowledge of type S is not available. Therefore, the compiler records the signatures of these two methods as setError(String) in superclass and setError(S_extends_CharSequence) in subclass—treating them as overloaded methods (not overridden). In this case, when the call to setError() is found, the compiler finds both the overloaded methods matching, resulting in the ambiguous method call error."
I really don't understand why type S can't be inferred at compile time.
String is passed when invoking the constructor of class StrLastError,
and from the API docs, String does implement interface CharSequence,
so doesn't that mean that S for <S extends CharSequence> actually is of type String?
I've read the Java online tutorial on the topic of generics several times. I've checked "Type Inference", and Inheritance, I just don't know how the whole thing works. I really need an explanation on this question.
The points I'm stuck at are:
If the subtype can't decide S, how come the super type can decide T, because the superclass does not have an upper bound? Or does it infer that T is String because the subtype calls the supertype's constructor first?
I understand that if the Constructor is invoked as:
StrLastError<CharSequence> err = newStrLastError<>((CharSequence)"Error");
there will be no ambiguity, since it's plain method overriding then. (Or am I even wrong here?)
However, like I said in the beginning, if String is passed, why can't S be inferred to be String?
You have to remind yourself that the classes are compiled one by one. Java generics are not templates as in other languages. There will only be one compiled class and not one class per type it is used with.
This way you can see that the class StrLastError will need to be compiled in a way such that it can also be used with other classes implementing CharSequence as generic type S.
Thats why the compiler gets you two different methods instead of an overridden one. Now it would be a runtime-job to see that the subclass may have wanted to override the method in the parent just in those cases where the types suggest it. Since this behaviour is hard to understand for the developer and would possibly lead to programming mistakes, it raises an exception.
If you use CharSequence as the generic type parameter of the class StrLastError, you will call the setError method in the parent class, since the type of "Last Error" is String, which is more specific than CharSequence and Java always chooses the most specific method in case it is overloaded. (I hope it is clear the the method was not overridden in this case either)
If the subtype can't decide S, how come the super type can decide T, because the superclass does not have an upper bound? Or does it infer that T is String because the subtype calls the supertype's constructor first?
The super type isn't deciding or inferring what T is; you're explicitly telling it what T is by this declaration:
class StrLastError<S extends CharSequence> extends LastError<String>
T is now bound to String for LastError, which makes every reference to T in the parent class a concrete String.
Your child class now has a bound S extends CharSequence attached to it, but this is independent to the bounds applied to the parent class.
What happens now is that Java will compile your child class, and the result of your child class is that two methods with a signature that matches String will be created. (Key note here: A String is-a CharSequence.)
In your child class, setError(Ljava/lang/CharSequence;)V is generated as the signature for setError. Because of the way generics work, LastError#setError will be treated as if it has a signature of setError(Ljava/lang/String;)V. This is also why when you go to actually override the method, it will place a String type as your parameter instead of anything else.
So, what we arrive at are two methods that have override-equivalent signatures.
void setError(CharSequence s)
void setError(String s)
JLS 8.4.8.4. applies here.
It is possible for a class to inherit multiple methods with
override-equivalent signatures (§8.4.2).
It is a compile-time error if a class C inherits a concrete method
whose signature is a subsignature of another concrete method inherited
by C. This can happen if a superclass is generic, and it has two
methods that were distinct in the generic declaration, but have the
same signature in the particular invocation used.
I understand that if the Constructor is invoked as StrLastError err = new StrLastError<>((CharSequence)"Error"); there will be no ambiguity, since its plain method overriding then.(Or I'm even wrong here)
No, now you're messing with raw types. Interestingly enough it will work, primarily because the signatures for the two methods has become:
void setError(Object s)
void setError(String s)
You want to use generics to avoid a scenario like this; you may want to invoke the super class method at some point, but in this scenario with these bindings, it's very difficult to accomplish.
This is a tricky example, to fix it you need to change the following line:
class StrLastError<S extends CharSequence> extends LastError<S>
The following code is considered invalid by the compiler:
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
#Override
void foo(Object foo) { ... }
}
I think that this is described in the JLS 8.4.8.1: "The signature of m1 is a subsignature (§8.4.2) of the signature of m2." and in 8.4.2: "the bounds of corresponding type variables are the same".
My question is: why can't the parameter in the subtype (Bar) be a supertype of the parameter in the supertype (Foo). In the example Object is a supertype of String. As far as I can see allowing this wouldn't violate the Liskov Substitution Principle.
Is there a scenario in which allowing this would break the code or is it a limitation of the current JLS?
Suppose you could do that. Now your superclass looks like this:
class Foo {
void foo(String foo) { ... }
void foo(Number foo) { ... }
}
and your subclass now:
class Bar extends Foo {
#Override
void foo(Object foo) { ... }
}
The language probably could allow such a thing (and just dispatch both Foo.foo(String) and Foo.foo(Number) to Bar.foo(Object)), but apparently the design decision for Java here is that one method only can override exactly one other method.
[Edit]
As dasblinkenlight said in his answer, one can have a foo(Object) without the #Override, but this just overloads the foo functions, and does not override them. When calling, java chooses the most specific method, so foo("Hello World") would always get dispatched to the foo(String) method.
(A rewrite, from a different angle ... my original answer contained an error. :( )
why can't the parameter in the subtype (Bar) be a supertype of the parameter in the supertype (Foo).
I believe that technically it could, and it wouldn't break ancestor contracts following type substition (Liskov Substitution Principle).
Types are passed-by-value (including reference types).
The caller can never be forced to deal with different parameter types than what it passes in.
A method body can swap a parameter type, but can't return it back to the caller (no such thing as 'output parameter types').
If your proposal was allowed, and a call was made to the ancestor method signature, a decendent class could override the method with broader types, but it's still impossible to return a broader type than what the caller sets.
The override could never break a client that uses the narrow ancestor method contract.
From my analysis below, I surmise/guess the rationale for not allowing your scenario:
Performance-related: allowing broader types in override would impact runtime performance, a major issue
Functionality-related: it only adds a minor amount of functionality. As it stands, you could add your 'broader method' as an overloaded method without overriding. Then you could additionally override the original method with an exact signature match. The net result: you achieve something quite similar, functionally.
Compiler Requirements for Method Override - JLS 7
The compiler's required to act accordancing to your experience. 8.4 Method Declarations:
A method in a subclass can override a method in an ancestor class iff:
the method names are identical (8.4.2 and 8.4.8.1)
the method parameters have identical types, after erasure of generic type parameters (8.4.2 and 8.4.8.1)
the return type is type-substitutable for the return type in the ancestor class, i.e. the same type or narrower (8.4.8.3)
Note: subsignature does not mean the overriding method uses subtypes of the overridden method. The overriding method is said to have a subsignature of the overridden method when the overriding method has exactly the same type signature except that generic types and the corresponding raw types are considered equivalent.
Compiler v Runtime Processing for Method Matching & Invocation
There's a performance hit matching method signatures via polymorphic type matching. By restricting override method signatures to exact match of ancestor, the JLS moves much of this processing to compile time. 15.12 Method Invocation Expressions - summarised:
Determine Class or Interface to Search (Compile-Time Determination)
Obtain the base type T, on which the method is being invoked.
This is the reference type declared to the compiler and not the runtime type (where a subtype may be substituted).
Determine Method Signature (Compile-Time Determination)
Search the compile-time base type T, for applicable methods matching the name and parameter & return types consistent with the call.
resolve generic parameters for T, either explicitly passed or implicitly inferred from the types of invocation method arguments
stage 1: methods applicable via consistent types/subtypes ('subtyping')
stage 2: methods applicable via automatic boxing/unboxing plus subtyping
stage 3: methods applicable via automatic boxing/unboxing plus subtyping plus variable 'arity' parameters
determine the most specific matching method signature (i.e. the method signature that could successfully be passed to all other matching method signatures); if none: compiler/ambiguity error
Check: Is the Chosen Method Appropriate? (Compile-Time Determination)
Evaluation of Method Invocation (Runtime Determination)
Determine runtime target reference type
Evaluate arguments
Check accessibility of method
Locate method - an exact signature match against the compile-time matched signature
Invoke
Performance Hit
The breakdown, in terms of text in the JLS:
Step 1: 5%
Step 2: 60%
Step 3: 5%
Step 4: 30%
Not only is Step 2 volumous in text, it's surprisingly complex. It has complex conditions and many expensive test conditions/searches. It's advantageous to maximise the compiler's execution of the more complex and slower processing here. If this was done at runtime, there would be a drag on performance, because it would occur for each method invocation.
Step 4 still has significant processing, but it is as streamlined as possible. Reading through 15.12.4, it contains no processing steps that could be moved to compile time, without forcing the runtime type to exactly match the compile-time type. Not only that, but it does a simple exact match on the method signature, rather than a complex "ancestor type match"
Java annotations cannot change the way the compiler generates byte code from your classes. You use annotations to tell the compiler how you think your program should be interpreted, and report errors when compiler's interpretation does not match your intentions. However, you cannot use annotations to force the compiler to produce code with different semantics.
When your subclass declare a method with the same name and parameter count as in its superclass, Java must decide between two possibilities:
You want the method in the subclass to override the method in the superclass, or
You want the method in the subclass to overload the method in the superclass.
If Java allowed foo(Object) to override foo(String) the language would have to introduce an alternative syntax for indicating an intent to overload a method. For example, they could have done it in a way similar to C#'s new and override in method declarations. For whatever reason, however, the designers decided against this new syntax, leaving the language with the rules specified in JLS 8.4.8.1.
Note that the current design lets you implement the functionality of an override by forwarding the call from the overloaded function. In your case, that would mean calling Bar.foo(Object) from Foo.foo(String) like this:
class Foo {
public void foo(String foo) { ... }
}
class Bar extends Foo {
#Override
public void foo(String foo) { this.foo((Object)foo); }
public void foo(Object foo) { ... }
}
Here is a demo on ideone.
The answer is plain simple, in Java, for method overriding, you must have the exact signature of the super type. However, if you remove the #Override annotation, your method would be overloaded and your code won't break. This is a Java implementation that ensures that you mean the method implementation should override the implementation of the super type.
Method overriding works in the following way.
class Foo{ //Super Class
void foo(String string){
// Your implementation here
}
}
class Bar extends Foo{
#Override
void foo(String string){
super(); //This method is implied when not explicitly stated in the method but the #Override annotation is present.
// Your implementation here
}
// An overloaded method
void foo(Object object){
// Your implementation here
}
}
The methods shown above are both correct and their implementation can vary.
I hope this helps you.
To answer the question in the title of the post What is the reasoning behind not allowing supertypes on Java method overrides?:
The designers of Java wanted a simple object oriented language and they specifically rejected features of C++ where, in their opinion, the complexity/pitfalls of the feature wasn't worth the benefit. What you describe may have fallen into this category where the designers chose to design/specify out the feature.
The problem with your code is that you are telling compiler that foo method in Bar class is overridden from parent class of Bar, i.e. Foo. Since overridden methods must have same signature, but in your case, according to syntax it is an overloaded method as you have changed the parameter in foo method of Bar class.
If you can override with superclasses, why not with subclasses as well?
Consider the following:
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
#Override
void foo(Object foo) { ... }
}
class Another extends Bar {
#Override
void foo(Number foo) { ... }
}
Now you have succesfully overriden an method whose original parameter was a String to accept a Number. Inadvisable to say the least...
Instead, the intended results may be replicated by using overloading and the following, more explicit, code:
class Foo {
void foo(String foo) { ... }
}
class Bar extends Foo {
#Override
private void foo(String foo) { ... }
void foo(Object foo) { ... }
}
class Another extends Bar {
#Override
private void foo(Object foo) { ... }
void foo(Number foo) { ... }
}
How to call a Custom Generic method by reflection in java?
class Person
{
public <T> void print(T t)
{
System.out.println(t.toString());
}
}
Generics are erased at compile time, they only provide extra information to the compiler to determine errors. They do not actually change the signature of the method in the .class file.
This means that you call a generic method by reflection in Java exactly the same way as you would call a non-generic method in Java, except that instead of specifying a type of T, you would specify a type of Object.
There are so many tutorials on how to call a regular method by reflection that I hesitate to add yet another; however, if you really need direction on how to call a method by reflection, please add a comment below and I'll add the necessary code.
If you find that things are not working as expected, you can always run javap on the compiled class file to verify that you are using the right objects in the argument list. It might be possible that if you specify a <T extends List> type generic signature, the resulting parameter object might actually be a List object.
This works for me.
Method method = Person.class.getMethod("print", Object.class);
method.invoke(new Person(), "this is a string");
method.invoke(new Person(), 273);
method.invoke(new Person(), new Object());
printing
this is a string
273
java.lang.Object#addbf1
Of course the theory behind this is explained beautifully in #Edwin's answer.
To highlight the point given in Edwin's answer, where we are using extends in a generic type: if you have a class like
GenericHibernateDao<T extends Serializable>
, and a method
public T save( T entity ) {};
to invoke the method save using reflection you have to use the Serializable class, i.e., you need to use:
Method method = GenericHibernateDao.class.getMethod(methodName, Serializable.class);
and not the Object.class as the parameter, since we are using
<T extends Serializable>