一日,代码突然报错,类型转换错误 ClassCastException。查看代码,原来是在mybatis xml文件中指定的返回类型与 mybatis mapper 中接口定义的返回类型不一致导致。于是乎,本人将其修改,使其返回值一样,代码报错问题得以解决。
可是解决的也只是代码运行时报错问题。当时自己改完后,前去告诉编码人员,要求 mybatis xml 中返回的类型要与 mybatis mapper 中的返回类型一致时,有一个帅小伙说道:“我的两个对象都差不多,字段一样,我用一个少一些字段的类型来接收一个字段多的对象为啥不可以呢?”他这一说,沉迷在他的帅气中的我,才从失神中再度迷失,自己也问为什么呢,代码运行这么久都没有报错呢。我不知道Java是怎么规定的,只好强忍着,从他的酷酷凝望眼神中溃逃,回到位置上思考、查询资料“Java 强转的要求与安全转型”。

参考:
Java类型转换
java类型转换详解(自动转换和强制转换)

基本数据类型

  • byte、short、int、long
  • float、double
  • char
  • boolean

从低位类型到高位类型可以自动转型,从高位类型到低位类型需要强制转换。注意前提,目标类型需要与源类型兼容。

  • 布尔类型和其它基本数据类型间不可相互转换;
  • char 可以转换为 int、long、float、double,其它类型不能转换为 char。
  • 其它六种类型从低到高的排序为: byte、short、int、long、float、double;
  • 算数运算中,基本类型会被转换为高位数据类型,然后参与运算,结果得高位的数据类型。

特殊情况

  • 如果采用的是 +=、-=、*=、/=等缩略形式的运算符,系统会自动强转为左边对象的类型;
  • 当运算符为自增自减时,不会强转。 ```java package com.demo.activiti7.inherit;

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.junit.Test;

public class TestDynamicProxy {

  1. // 静态代理
  2. @Test
  3. public void testStaticProxy() {
  4. Demo demo = new DemoImpl();
  5. demo.hello("Bruce");
  6. }
  7. // 动态代理
  8. @Test
  9. public void testDynamic() {
  10. InvocationHandler invocationHandler = new InvocationHandler() {
  11. @Override
  12. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  13. System.out.println("proxy class:" + proxy.getClass());
  14. String name = method.getName();
  15. System.out.println("method:" + name);
  16. System.out.println("args:" + (Objects.isNull(args) ? 0 : args.length));
  17. if ("hello".equals(name)) {
  18. System.out.println("proxy invoke hello: hello " + args[0]);
  19. }
  20. return null;
  21. }
  22. };
  23. Demo demo = (Demo) Proxy.newProxyInstance(
  24. Demo.class.getClassLoader(),
  25. new Class[]{Demo.class},
  26. invocationHandler
  27. );
  28. demo.hello("Bruce Bruces");
  29. try {
  30. invocationHandler.invoke(new DemoImpl(),
  31. DemoImpl.class.getDeclaredMethod("hello", String.class),
  32. new Object[]{"name"});
  33. } catch (Throwable throwable) {
  34. throwable.printStackTrace();
  35. }
  36. int i = demo.getClass().getName().length() > 1 ? new Integer(1) : new Short((short) 2);
  37. }
  38. @Test
  39. public void testCast() {
  40. boolean bool = false;
  41. byte b = (byte) 1;
  42. short s = (short) 2;
  43. int i = 3;
  44. long l = 4L;
  45. float f = 1.23456F;
  46. double d = 6.78901D;
  47. char c = 'A';
  48. // char 类型可以转为数字进行运算,赋值给数字类型
  49. int a = c + b;
  50. a = c;
  51. double dd = c;
  52. // a = bool + s; // 编译报错
  53. float ff = f + l;
  54. ff = (float) (d + c);
  55. // 结果还是 short 类型,与左侧保持一致
  56. s += 1;
  57. // 右侧结果变为高位类型 int,左侧为 short 需要强转
  58. s = (short) (s + 1);
  59. // ++ 运算不会改变类型
  60. s = s++;
  61. }

}

interface Demo {

  1. void hello(String name);

}

class DemoImpl implements Demo {

  1. @Override
  2. public void hello(String name) {
  3. System.out.println("hello " + name);
  4. }

}

```

引用类型

  • 基本类型与包装类型可以自动转换(自动拆箱装箱);
  • 子类能够直接转换为父类或接口类型(向上转型,子类就是一个特殊的父类)。
  • 父类转换为子类,需要强制转型;要注意,只要不是对应对象的类型(待转型的对象不是转换到的类型),会报错,抛出 ClassCastException 运行时异常。

    小结

  • 基本类型转型,由高到低,需要强转(注意,只有兼容的类型间才可以进行转换),由低到高,自动转型;

  • 引用类型,向上转型(存在继承关系的)自动可实现(直接使用,不需强转),向下转型成功与否,取决于对象的实际类型与转换的类型是否相同,相同则成功,不相同则运行时异常 ClassCastException。所以说,跟两个类是否存在相同字段,字段包含情况无关。