Java source code type value assigned to getClss () method for generic type

public class Box<T> { private T t; public Box(T t){ this.t = t; } public void add(T t) { this.t = t; } public T get() { return t; } public static void main(String[] args) { Box<Integer> b = new Box(new String("may be")); System.out.println(b.get()); // successfully print out "may be" System.out.println(b.get().getClass()); // error } } 

This code gives a runtime error:

 exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
  • Why b.get() not b.get() a runtime error?
  • Why does a runtime error occur only when I try to get a class of a class variable?

More precisely: why does the compiler insert a checkcast into the bytecode for only the second get() (which leads to an exception)?

+5
source share
4 answers

Note:

  • in the first case, the result of get() used for println(Object) : in other words: the receiving side expects an object and that the "condition" will always be true.
  • in the second case, the method will be called on the returned object. And now it makes a huge difference possible if the return type is expected . Therefore, the compiler adds this check to ensure that the next method call is sound .

As a background, you can study the Java language specification, chapter 5.52:

Cast - proven cast.

Such a cast requires validation at run time. If the value at run time is null, then the stock is allowed. Otherwise, let R be the class of the object indicated by the runtime reference value, and let T be erased (ยง4.6) of the name type in the litas operator. The cast transformation must verify at run time that the class R is an assignment compatible with type T through the algorithm in clause 5.5.3.

accordingly chapter 5.53 Checked throws at runtime .

+2
source

This variable declaration is incompatible.

  Box<Integer> b = new Box(new String("may be")); : 

The instantiated object is unprocessed, so the compiler gives a warning about this, but allows you to assign an unprocessed type to a common variable: Box<Integer> .

b.get() not interrupted since you are not assigning the result to a variable.
Thus, the compiler should not throw it on anything.

Try the following:

 Integer value = b.get(); 

It will compile fine, but at runtime you will get the same exception as the JVM will try to pass an Integer value:

 java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 

When called:

 System.out.println(b.get().getClass()); // error 

Things are close to.

Why is the Integer class expected here?

At compile time, b declared as Box<Integer> b .
Therefore, the compiler knows that b parameterized by type Integer .
So yes, after compilation, the generic files are erased, but the compiler adds, however, some discards according to the declared code.

And here it is. You call getClass() on a variable parameterized with Integer .
But Class is a generic class: Class<T> .
So the cast to Integer was added by the compiler to match the Class<Integer> .

Of course, using generics both to declare variables and to instantiate:

  Box<Integer> b = new Box<>(new String("may be")); 

such inconsistency is not possible because the compiler is stopping you right now.

+2
source

Aside from the answers here, the byte command checkcast is called on typechecks that are not a specific type of Object . for instance

  public static void main(String[] args) { Box<Integer> b = new Box(new String("may be")); doStuff(b.get()); // no checkcast needed - works fine doIntegerStuff(b.get()); // run-time error with checkcast doStringStuff(b.get()); // compile error } public static void doStuff(Object object){} public static void doStringStuff(String integer){} public static void doIntegerStuff(Integer integer){} 
+1
source

In the line of code Box<Integer> b = new Box(new String("may be")); When creating a new Box object, information about the Info type is missing and is assumed to be the default Object class.

Box<String> b = new Box<>(new String()); this is the right way to do it

-------- added --------

In Object the class method getClass() returns a Class runtime object. and when you return your code, Box<Integer> returns the getClass() method of the Class<Integer> not Class<String> .

You passed a raw type with new B(new String()); so that the compiler passes the syntax, but when getClass() called, it discards the internal String object in Integer and throws a RuntimeException

-1
source

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


All Articles