JAVA类型强制转换

1.背景

在 Java 中,之所以需要强制类型转换是为了防止程序员在不知情的情况下把A类型数据错当成B类型的数据。将一种类型的值赋给另一个类型的变量是很常见的,如果这两种是兼容的,那么 Java 将执行自动转换,例如 int 和 long,将int类型赋值给 long 类型的变量,总是可行的。但不是所有的类型都兼容。例如,没有将 double 类型转换为 byte 型的定义。但是不兼容的类型之间的转换仍然是可能的。达到这个目的,就需要使用强制类型转换。完成两个不兼容类型的强制转换。

数值型大小排序:byte<short<int<long<float<double

字符型可以自动转化为int型,即char<int<long<float<double

每一位的二进制位称之为一个比特位,记作bit

每八位二进制位称之为一个比特,记作byte。1byte = 8 bit

byte型底层实现:左边第一位代表符号位,此外1000 0000 不代表-0而代表-128,所以范围-128~127

float底层实现:左边第一位代表符号位,左边第二位代表整数位,后面七位代表幂次,后面23位代表小数位

2.自动类型转换和强制类型转换

在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需要强制转换。因为子类拥有比父类更多的属性、更强的功能,所以父类转换为子类需要强制。

当我们用一个类型的构造器构造出一个对象时,这个对象的类型就已经确定的,也就说它的本质是不会再发生变化了。在Java中我们可以通过继承、向上转型的关系使用父类类型来引用它,这个时候我们是使用功能较弱的类型引用功能较强的对象,这是可行的。但是将功能较弱的类型强制转功能较强的对象时,就不一定可以行了。

Father father = new Son();
Son son = (Son)father;
//编译出错,ClassCastException
Father father = new Father();
Son son = (Son) father;

在第一个例子中,father被指向一个子类对象,子类也可以指向子类对象。而第二个例子中,father被传给一个父类对象,子类引用不能指向父类对象。即很重要的概念是:父类引用指向子类对象。将父类转换为子类之前,应该用instanceof检查。

static class One {
   public void foo() {
       System.out.println("One");
   }
}
static class Two extends One {
   public void foo() {
       System.out.println("Two");
   }
   public void dosth(){
       System.out.println("Two again");
   }
}
public static void main(String[] args) throws Exception{
   One t = new Two(); //向上转型,即父类引用指向子类对象,此时子类对象的类型为父类的类型
   t.foo();
   t.dosth();//编译错误
   t = (Two)t; 
   t.dosth();//编译错误 
   ((Two) t).dosth();//编译成功
}

向上转型是安全的,但是会有些子类特性会丢失,向下转型可以成功。

总结:父类引用可以指向子类对象,子类引用不能指向父类对象。把子类对象直接赋给父类引用叫做向上转型,向上转型不用强制转型,如Father f1=new Son(),把指向子类对象的父类引用赋给子类引用叫做向下转型,要强制转型,如Son s1 = (Son)f1。向上转型会丢失子类特有的方法,但是子类overriding父类的方法,子类方法有效。

将一种类型的数据赋给另外一种类型变量时,满足下列两种要求将执行自动类型转换:1.两种类型是兼容的;2.目的类型的范围比来源类型大。

数据值类型按照范围从小到大为:byte,short,int,long,float,double

例如int类型比所有byte合法类型大,因此不要求显式强制类型转换。对于数值类型,整型和浮点型都是彼此兼容的,但是数值类型和字符类型和布尔类型是不兼容的,字符类型和布尔类型也不是互相兼容的。

自动类型转换不能满足所有的转换需求,比如int型变量赋值给byte型变量,这种转换不会自动进行,因为byte型比int型范围小。为了完成两种不兼容类型转换,需要用到强制类型转换。

目标类型指定了要转换成为的类型。例如果将int型转为byte型,int型取值范围大于byte型,它的值将堆byte型范围进行取模。而把浮点型赋值给整数型,就会出现截断,截取掉小数部分。从其他数值类型转换为char类型时,必须进行强制转换。将char类型转换为其他数值类型时,除了byte、short必须强制转换之外,int、long、float、double都不用强制转换。

byte b;
int i = 257;
double d = 32.13;
b = (byte) i;
System.out.println("i and b = " + i + " " + b);
i = (int)d;
System.out.println("d and i = " + d + " " + i);
b = (byte)d;
System.out.println("d and b = " + d + " " + b);
byte e=(byte)130; 
System.out.println(e);

输出:

i and b = 257 1
d and i = 32.13 32
d and b = 32.13 32
-126

当257要转换为byte时,byte的范围是256,所以取模的结果是1。浮点值赋给整数型,截断了小数部分。

short s = 1;
s= s + 1;//编译错误
short s1 = 1;
s1 += 1;

上述陷阱是s = s + 1,s + 1会隐式转换为int型,把int型号赋给short,会造成类型缺失。而s1 += 1相当于s1 = (short)(s1 + 1)会把s1 + 1强制转换为short类型,就不会报错。涉及到写代码的严谨性。

对于自动装箱和自动拆箱,将一个基本数据类型转换为对应的引用类型时,不必强制转换。将一个基本数据类型的引用类型转换为基本数据类型时,也不必要强制转换。

int i1 = 10;
Integer iObj1 = i1;
Integer iObj2 = new Integer(10);
int i2 = iObj2;

在三目运算符中,会按照算术类型中的提升原则将两端操作提升至统一类型,如果两端有一个操作数是引用类型,则整个表达式结果用Object型表示。

byte b = 10; 
short s = 20; 
int i = (b == 10) ? b : s; 
int i1 = 10; 
String str = "Hello"; 
Object obj = (i1 == 10) ? i1 : str;  // 在这里变量i进行了自动装箱操作

int 和 String 互转,两种方法

String s = "12345";
int i ;
i=Integer.parseInt(s);
i=Integer.valueOf(s).intValue();

第一种方法直接使用静态方法。
第二种方法相当于new Integer(Integer.parseInt(s)),会多产生一个对象。

3.JVM级别原理

对于强制类型转换,且是引用类型,如果是父类向子类转换,这种只牵扯到引用名义类型的转换,具体的内存没有什么变化。

而基本类型转换不同,数据发生了变化。但是基本数据类型不是对象,如果涉及到自动装箱和拆箱,实际上是调用类似Integer.parseInt()和Integer.valueOf()实现。

父类向子类强制转换,如果成功不会有任何数据丢失,如果不是子类,那么会报错。基本类型之间的转换,如果是大范围向小范围的转换,有可能发生数据丢失或者精确丢失。

  • 9
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值