ClassCastException occurs when migrating from Java7 to Java8 ~ Generics and overload ~


Self-introduction

LT at Nagoya Java User Group April 2018!


Execution environment


table of contents

  1. Problems that have occurred
  2. Investigate the cause
  3. Survey results

1. Problems that have occurred


What happens when you run it?

Main.java



public class Main {

	public static void main(String[] args) {
		String.valueOf(hoge());
	}

	static <E> E hoge() {
		return (E) "hoge";
	}

}

Java7 ends normally, Java8 causes ClassCastException

Console


Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to [C
	at jp.co.sample.Main.main(Main.java:13)

[C is a char array https://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html#jls-10.8


What is this source in the first place?


Problems with this source

Don't worry about this announcement.


2. Investigate the cause


Check with Eclipse

The compiler is ECJ (Eclipse Java Compiler), which is different from the JDK, but the result is the same.

image


In Java 7, the hoge type parameter is ʻObject`

Java7


In Java8 the hoge type parameter is char []

Java8

char [] comes from String.valueOf.


String.valueOf is overloaded

Can accept char array type or Object type arguments

String.valueOfのオーバロード


Situation arrangement


Checking generic methods

MainGenericsMethod.java


public class MainGenericsMethod {

	public static void main(String[] args) {
		String.valueOf(fuga("fuga"));
	}

	/**The type parameter is determined from the argument*/
	static <E> E fuga(E arg) {
		return (E) arg;
	}
}

image


Check for overload

The result of executing in Java 8 by changing the combination of overloaded methods.

The problem is an overloaded method that accepts an Object or array type.

MainOverload.java


public class MainOverload {

	public static void main(String[] args) {
		overload(hoge());
	}

	static <E> E hoge() {
		return (E) "hoge";
	}

	static void overload(Object arg) {}
	static void overload(char[] arg) {} //Change the argument type
}

image


3. Survey results


Summary


[Supplement] Ambiguous overload

When I call an overloaded method that receives an ʻint [] or char [] `, I get a compile error that says" Method overload (Object) is of type MainOverload is ambiguous "

        //Compile error
	static void overload(int[] arg) {}
	static void overload(char[] arg) {}

Articles that may be related to this issue

So, whereas before Java 8 the method argument site did not receive any inference, defaulting to Object, in Java 8 the most specific applicable type is inferred, in this case String.


[Supplement] I tried disassembling with Java 8 javap -verbose

Classfile /C:/Users/yuji3/Desktop/java-test/java8/Main.class
  Last modified 2018/04/14; size 476 bytes
  MD5 checksum 409af5d1b1986da6e0c4cd431dc50b59
  Compiled from "Main.java"
public class Main
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#20         // java/lang/Object."<init>":()V
   #2 = Methodref          #6.#21         // Main.hoge:()Ljava/lang/Object;
   #3 = Class              #22            // "[C"
   #4 = Methodref          #23.#24        // java/lang/String.valueOf:([C)Ljava/lang/String;
   #5 = String             #14            // hoge
   #6 = Class              #25            // Main
   #7 = Class              #26            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               main
  #13 = Utf8               ([Ljava/lang/String;)V
  #14 = Utf8               hoge
  #15 = Utf8               ()Ljava/lang/Object;
  #16 = Utf8               Signature
  #17 = Utf8               <E:Ljava/lang/Object;>()TE;
  #18 = Utf8               SourceFile
  #19 = Utf8               Main.java
  #20 = NameAndType        #8:#9          // "<init>":()V
  #21 = NameAndType        #14:#15        // hoge:()Ljava/lang/Object;
  #22 = Utf8               [C
  #23 = Class              #27            // java/lang/String
  #24 = NameAndType        #28:#29        // valueOf:([C)Ljava/lang/String;
  #25 = Utf8               Main
  #26 = Utf8               java/lang/Object
  #27 = Utf8               java/lang/String
  #28 = Utf8               valueOf
  #29 = Utf8               ([C)Ljava/lang/String;
{
  public Main();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 2: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=1, args_size=1
         0: invokestatic  #2                  // Method hoge:()Ljava/lang/Object;
         3: checkcast     #3                  // class "[C"
         6: invokestatic  #4                  // Method java/lang/String.valueOf:([C)Ljava/lang/String;
         9: pop
        10: return
      LineNumberTable:
        line 4: 0
        line 5: 10

  static <E extends java.lang.Object> E hoge();
    descriptor: ()Ljava/lang/Object;
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: ldc           #5                  // String hoge
         2: areturn
      LineNumberTable:
        line 8: 0
    Signature: #17                          // <E:Ljava/lang/Object;>()TE;
}
SourceFile: "Main.java"

[Supplement] I tried disassembling with Java 7 javap -verbose

Classfile /C:/Users/yuji3/Desktop/java-test/java7/Main.class
  Last modified 2018/04/14; size 481 bytes
  MD5 checksum 72c2eee8d5b013579f81dc56f53458d0
  Compiled from "Main.java"
public class Main
  SourceFile: "Main.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:
   #1 = Methodref          #6.#19         //  java/lang/Object."<init>":()V
   #2 = Methodref          #5.#20         //  Main.hoge:()Ljava/lang/Object;
   #3 = Methodref          #21.#22        //  java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   #4 = String             #13            //  hoge
   #5 = Class              #23            //  Main
   #6 = Class              #24            //  java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               hoge
  #14 = Utf8               ()Ljava/lang/Object;
  #15 = Utf8               Signature
  #16 = Utf8               <E:Ljava/lang/Object;>()TE;
  #17 = Utf8               SourceFile
  #18 = Utf8               Main.java
  #19 = NameAndType        #7:#8          //  "<init>":()V
  #20 = NameAndType        #13:#14        //  hoge:()Ljava/lang/Object;
  #21 = Class              #25            //  java/lang/String
  #22 = NameAndType        #26:#27        //  valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  #23 = Utf8               Main
  #24 = Utf8               java/lang/Object
  #25 = Utf8               java/lang/String
  #26 = Utf8               valueOf
  #27 = Utf8               (Ljava/lang/Object;)Ljava/lang/String;
{
  public Main();
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return        
      LineNumberTable:
        line 2: 0

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC

    Code:
      stack=1, locals=1, args_size=1
         0: invokestatic  #2                  // Method hoge:()Ljava/lang/Object;
         3: invokestatic  #3                  // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
         6: pop           
         7: return        
      LineNumberTable:
        line 4: 0
        line 5: 7

  static <E extends java/lang/Object> E hoge();
    flags: ACC_STATIC

    Code:
      stack=1, locals=0, args_size=0
         0: ldc           #4                  // String hoge
         2: areturn       
      LineNumberTable:
        line 8: 0
    Signature: #16                          // <E:Ljava/lang/Object;>()TE;
}

Recommended Posts

ClassCastException occurs when migrating from Java7 to Java8 ~ Generics and overload ~
How to write and notes when migrating from VB to JAVA
Precautions when migrating from VB6.0 to JAVA
[Opens aml] NoClassDefFoundError occurs when migrating from Tomcat to weblogic
What I thought about when I started migrating from Java to Kotlin
Changes when migrating from Spring Boot 1.5 to Spring Boot 2.0
Changes when migrating from Spring Boot 2.0 to Spring Boot 2.2
Update JAVA to the latest version to 1.8.0_144 (when downloading from the web and updating)
[Java] Tips and error issues when converting from double to Big Decimal
Summary of points I was worried about when migrating from java to kotlin
Changes from Java 8 to Java 11
Sum from Java_1 to 100
From Java to Ruby !!
[Java] Overload and override
Convert Java enum enums and JSON to and from Jackson
Migration from Cobol to JAVA
[Java] Generics classes and generics methods
New features from Java7 to Java8
Migrating from vargrant to docker
Connect from Java to PostgreSQL
From Ineffective Java to Effective Java
Notes on character encoding when migrating from windows to Mac
[Java] Shallow copy and deep copy when converting an array to List
From fledgling Java (3 years) to Node.js (4 years). And the impression of returning to Java
[Java] How to convert from String to Path type and get the path
Introduction to Scala from a Java perspective, decompiled and understood (basic)
Java to be involved from today
From Java to VB.NET-Writing Contrast Memo-
Java overload constructor starting from beginner
Java, interface to start from beginner
Notes on migrating from CircleCI 1.0 to 2.0
[Java] Try to implement using generics
Java generics (defines classes and methods)
The road from JavaScript to Java
[Java] Conversion from array to List
What to do when javax.batch.operations.JobStartException occurs
[Ruby / Refactoring] From Ruby iterative processing like Java and C language to Ruby-like iterative processing
What to do and how to install when an error occurs in DXRuby 1.4.7
I translated the grammar of R and Java [Updated from time to time]
Java starting from beginner, variables and types
What to do when a javax.el.PropertyNotWritableException occurs
Convert from java UTC time to JST time
Java implementation to create and solve mazes
[Java] How to output and write files!
From installing Eclipse to executing Java (PHP)
[Rails] [Memo] When to add = to <%%> and when not
Java: How to send values from Servlet to Servlet
When calling API with java, javax.net.ssl.SSLHandshakeException occurs
[Java] Flow from source code to execution
Introduction to monitoring from Java Touching Prometheus
[Introduction to Java] Variable declarations and types
Soaring tech skills and declining tech skills from 2014 to 2019
Memo for migration from java to kotlin
Type conversion from java BigDecimal type to String type
Java to C and C to Java in Android Studio
[Easy-to-understand explanation! ] How to use Java overload
Troubleshooting when raising Mastodon from v3.0.x to v3.1.x
Summary of good points and precautions when converting Java Android application to Kotlin
[Promotion of Ruby comprehension (1)] When switching from Java to Ruby, first understand the difference.
[Java] Program example to get the maximum and minimum values from an array
Summary when trying to use Solr in Java and getting an error (Solr 6.x)