Is Java generation generated based on return type?

The following code is from the Android library called ButterKnife. I figure out how it works.

@SuppressWarnings("unchecked") // That the point. public <T> T castParam(Object value, String from, int fromPosition, String to, int toPosition) { try { return (T) value; } catch (ClassCastException e) { throw new IllegalStateException("Parameter #" + (fromPosition + 1) + " of method '" + from + "' was of the wrong type for parameter #" + (toPosition + 1) + " of method '" + to + "'. See cause for more info.", e); } } 

I tried to recreate the behavior of this function:

  @SuppressWarnings("unchecked") public static <T> T cast(Object o){ try { return (T) o; } catch (ClassCastException e){ throw new AssertionError("Error"); } } 

And use:

 Object o = new String("test"); Double d = cast(o); 

But the exception never occurs; it is called on the line when the method is called. Why is this?

Also, how does it work? How does the method know what to do?

+5
source share
2 answers

As SJuan67 explained, you cannot use translations with generic types, as the Java compiler will

Replace all type parameters in generic types with their boundaries or object, if the type parameters are not limited. Thus, the obtained bytecode contains only ordinary classes, interfaces, and methods.

Additional information on all generator limitations is here .

So, ButterKnife code will look like this:

  public Object castParam(Object paramObject, String paramString1, int paramInt1, String paramString2, int paramInt2) { return paramObject; } 

So, to your questions:

Q: But an exception never occurs; it is thrown into a string when a method is called. Why is this?

A: Well, it's not even in bytecode.

Q: Also, how does it work? How does the method know what to do?

A: That is not so. At least not the way you think. In practice, it will throw a ClassCastException not an IllegalStateException or AssertionError, as you noticed. You can even try it with the ButterKnife sample application and bind the famous TextView to the CheckBox:

 @Bind(R.id.title) CheckBox title; 

Q: How does the library work?

A: Well, IllegalStateException is simply not being thrown, and you have a ClassCastException. Why this is so, I'm not quite sure. However, since ButterKnife generates code, this may be intended to prevent compilation errors.

eg:

 public interface Some { } public static void weWantSome(Some d) { } public static void test() { String o = "test"; weWantSome((Some)o); //<-- compile error weWantSome(Main.<Some>cast(o)); //<-- runtime error } 

That is why in the previous example, the code compiles, but does not start.

+2
source

Generalization types are checked only at compile time, due to type erasure. This is because it was not possible to introduce generics at run time in Java 5 without breaking backward compatibility and forcing recompilation of all existing libraries.

In short, when you define a β€œgeneric” class or method, the actual code compiles as Object instead of the type that you associate with this method. All type checks are performed at compile time.

Thus, your method code does not actually list in the return , as it assigns something (a String ) to the returned value of Object . The actual ClassCastException is returned by the caller because this is the place where the reference variable is actually typed.

+7
source

Source: https://habr.com/ru/post/1245764/


All Articles