JAVA

admin 2025年3月26日08:54:58评论9 views字数 7335阅读24分27秒阅读模式

在 Java 中,数据类型转换是一个常见的操作,主要分为 自动类型转换(隐式转换) 和 强制类型转换(显式转换)。Java 的数据类型可以分为两大类:

  1. 基本数据类型:如 byteshortintlongfloatdoublechar 和 boolean
  2. 引用数据类型:如类、接口、数组等。

以下是关于 Java 中所有数据类型的转换规则和示例。

一、基本数据类型的转换

1. 自动类型转换(隐式转换)

当从小范围的数据类型赋值给大范围的数据类型时,Java 会自动进行类型转换(隐式转换),不会丢失精度。

转换规则:

  • byte → short → int → long → float → double
  • char → int

示例代码:

publicclassImplicitConversion{
publicstaticvoidmain(String[] args){
byte b = 100;
short s = b; // 自动从 byte 转为 short
int i = s;   // 自动从 short 转为 int
long l = i;  // 自动从 int 转为 long
float f = l; // 自动从 long 转为 float
double d = f;// 自动从 float 转为 double

        System.out.println("Byte: " + b);
        System.out.println("Short: " + s);
        System.out.println("Int: " + i);
        System.out.println("Long: " + l);
        System.out.println("Float: " + f);
        System.out.println("Double: " + d);
    }
}

2. 强制类型转换(显式转换)

当从大范围的数据类型赋值给小范围的数据类型时,需要手动进行强制类型转换。这种转换可能会导致数据溢出或精度丢失

转换规则:

  • double → float → long → int → short → byte
  • int → char

示例代码:

publicclassExplicitConversion{
publicstaticvoidmain(String[] args){
double d = 123.456;
float f = (float) d; // 强制将 double 转为 float
long l = (long) f;   // 强制将 float 转为 long
int i = (int) l;     // 强制将 long 转为 int
short s = (short) i; // 强制将 int 转为 short
byte b = (byte) s;   // 强制将 short 转为 byte

        System.out.println("Double: " + d);
        System.out.println("Float: " + f);
        System.out.println("Long: " + l);
        System.out.println("Int: " + i);
        System.out.println("Short: " + s);
        System.out.println("Byte: " + b);
    }
}

注意事项:

  • 如果数值超出目标类型的范围,会导致溢出。例如:

    int num = 129;
    byte b = (byte) num; // 溢出,结果为 -127
    System.out.println(b); // 输出 -127

int j=(int)10000000000L; //上面的代码相当于把long强制转换为int类型 //int 4个字节 一个字节8个比特位 那就是32位 //将10000000000转为2进制为10 0101 0100 0000 1011 1110 0100 0000 0000->34位,所以我们要将前面两位去掉->0101 0100 0000 1011 1110 0100 0000 0000->1410065408



byte,short定义时如果右边是整数常量,不超过他们的精度,不需要我们强转,jvm自动转型如果右边有变量参与,byte、short自动提升为int,然后结果再次赋值给byte或short变量,需要我们自己手动强转
---

### 3. **布尔类型(`boolean`)**
`boolean` 类型不能与其他任何数据类型进行转换,包括隐式和显式转换。

---

### 4. **字符类型(`char`)**
- `char` 是无符号的 16 位整数类型,表示 Unicode 字符(范围是 `0` 到 `65535`)。
- 可以与整数类型(如 `int`、`short` 等)互相转换。

#### 示例代码:
```java
public class CharConversion {
  public static void main(String[] args) {
      char c = 'A'; // 字符 'A' 的 ASCII 值是 65
      int asciiValue = c; // 自动将 char 转为 int
      System.out.println("Char to Int: " + asciiValue);

      int num = 66;
      char convertedChar = (char) num; // 强制将 int 转为 char
      System.out.println("Int to Char: " + convertedChar);
  }
}

二、引用数据类型的转换

1. 向上转型(隐式转换)

子类对象可以自动转换为父类类型,称为向上转型。这是安全的,因为子类对象始终包含父类的所有成员。

示例代码:

classAnimal{
voideat(){
        System.out.println("Animal is eating");
    }
}

classDogextendsAnimal{
voidbark(){
        System.out.println("Dog is barking");
    }
}

publicclassUpcastingExample{
publicstaticvoidmain(String[] args){
        Dog dog = new Dog();
        Animal animal = dog; // 向上转型:Dog -> Animal
        animal.eat(); // 调用父类方法
// animal.bark(); // 错误:无法调用子类特有的方法
    }
}

2. 向下转型(显式转换)

父类对象可以强制转换为子类类型,称为向下转型。需要注意的是,只有当父类对象实际上是子类实例时,向下转型才是安全的。

示例代码:

publicclassDowncastingExample{
publicstaticvoidmain(String[] args){
        Animal animal = new Dog(); // 向上转型
        Dog dog = (Dog) animal;    // 向下转型:Animal -> Dog
        dog.bark();                // 调用子类方法
    }
}

注意事项:

  • 如果父类对象不是子类实例,则向下转型会抛出 ClassCastException
  • 使用 instanceof 检查类型是否兼容:

    if (animal instanceof Dog) {
        Dog dog = (Dog) animal;
        dog.bark();
    else {
        System.out.println("Not a Dog instance");
    }

三、字符串与其他数据类型的转换

1. 基本数据类型转字符串

使用 String.valueOf() 或直接拼接字符串。

示例代码:

int num = 123;
String str1 = String.valueOf(num); // 方法 1
String str2 = "" + num;           // 方法 2
System.out.println(str1); // 输出 "123"
System.out.println(str2); // 输出 "123"

2. 字符串转基本数据类型

使用包装类的 parseXxx() 方法。

示例代码:

String str = "123";
int num = Integer.parseInt(str);    // 将字符串转为 int
double d = Double.parseDouble(str); // 将字符串转为 double
System.out.println(num); // 输出 123
System.out.println(d);   // 输出 123.0

注意事项:

  • 如果字符串格式不正确,会抛出 NumberFormatException

进制运算

进制的分类

  • 十进制
    • 数字组成:0~9
    • 进位规则:满十并不区分进一
  • 二进制
    • 数字组成:0-1
    • 进位规则:满二进一,以0b或0B开头
  • 八进制
    • 数字组成:0-7
    • 进位规则:满八进一,以数字0开头
  • 十六进制
    • 数字组成:0-9、a-f
    • 进位规则:满十六进一,以0x或0X开头表示,此处a-f不区分大小写

电脑打印出来统一转换为10进制

计算机数据的存储使用二进制补码形式存储

二进制转十进制

二进制如何表示整数

  • 计算机数据的存储使用二进制补码形式存储,并且最高位是符号位

    • 正数:最高位是0
    • 负数:最高位是1
  • 规定

    • 负数的原码:把十进制转为二进制,然后最高位设置为1
    • 负数的反码:在原码的基础上,最高位不变,其余位按位取反
    • 负数的补码:反码+1
    • 正数的补码和反码、原码一样,称为三码合一
    • 负数的补码反码、原码不一样

十进制转二进制

除二取余的逆

二进制与八进制

三个二进制数代表一个八进制数(整数部分前面添0,小数小数点旁边添0) 8421规则

二进制与十六进制

四个二进制代表一个十六进制数(整数部分前面添0,小数小数点旁边添0)

位运算符

位运算符用于直接对整数的二进制表示进行操作,它们在处理底层数据、优化性能以及特定算法实现中有重要作用。结合之前提到的按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移(<<)、右移(>>),再加上无符号右移(>>>),这里总结一下所有这些位运算符:

  1. 按位与(&)

    • 对两个操作数的每一位执行与操作。只有当两个相应的二进制位都为1时,结果位才为1。
    • 示例:5 & 3 结果是 1。因为 (0101_2) 和 (0011_2) 按位与得到 (0001_2)。
  2. 按位或(|)

    • 对两个操作数的每一位执行或操作。只要两个相应的二进制位有一个为1,结果位就为1。
    • 示例:5 | 3 结果是 7。因为 (0101_2) 和 (0011_2) 按位或得到 (0111_2)。
  3. 按位异或(^)

    • 对两个操作数的每一位执行异或操作。当且仅当两个相应的二进制位不相同时,结果位为1。
    • 示例:5 ^ 3 结果是 6。因为 (0101_2) 和 (0011_2) 按位异或得到 (0110_2)。
  4. 按位取反(~)

    • 对操作数的每一位执行取反操作,即把1变为0,把0变为1。
    • 示例:~5 在考虑有符号整数和补码表示的情况下,会将正数转换为其负数形式的补码表示。

左移运算符 (<<)

左移运算符将一个数的所有位向左移动指定的位数,并在右边用0填充。无论操作数是正数还是负数,左移操作的行为基本一致,但需要注意的是,左移可能会导致数值超出其数据类型所能表示的最大范围,从而导致溢出。

  • 正数:对于正数来说,左移n位相当于乘以2n2n。
    • 示例:假设我们有一个8位系统,5 << 1(即 000001012000001012 左移一位)得到 000010102000010102,也就是十进制的10。
  • 负数:对于使用补码表示的负数,左移同样会按照规则执行,但由于符号位(最高位)也被参与了计算,因此可能导致符号变化或数值溢出。
    • 示例:在8位系统中,-5 << 1 (即 111110112111110112 补码形式的-5)左移一位后变为 111101102111101102,如果考虑溢出,这可能不再直接对应于某个特定的负数值,而是取决于具体环境如何处理溢出情况。

右移运算符

右移分为两种:带符号右移(>>)和无符号右移(>>>)。

带符号右移 (>>)

带符号右移保留了数字的符号位,这意味着它执行算术右移。对于正数和负数,其行为有所不同:

  • 正数:对于正数,右移n位相当于除以2n2n(向下取整)。
    • 示例:8 >> 1(即 000010002000010002 右移一位)得到 000001002000001002,即4。
  • 负数:对于负数,右移n位时,左边用符号位(通常是1)填充,保持数值为负。
    • 示例:在8位系统中,-8 >> 1(即 111110002111110002 补码形式的-8)右移一位后变为 111111002111111002,这是补码形式的-4。

无符号右移 (>>>)

无符号右移不考虑符号位,总是用0填充左边被移出的高位,无论原数的最高位是什么。这对于处理无符号整数特别有用。

  • 正数:对于正数,无符号右移与带符号右移效果相同,因为它不会改变数值的正性。
    • 示例:8 >>> 1 结果同样是4。
  • 负数:对于负数,由于左边总是用0填充,这会导致原本代表负数的位模式变成一个很大的正数。
    • 示例:在8位系统中,-8 >>> 1(即 111110002111110002 补码形式的-8)无符号右移一位后变为 011111002011111002,这是一个非常大的正数(具体值取决于系统的字长和如何处理超出的位)。

1. 左移 (<<)

假设我们有一个8位系统,为了简化示例,我们将使用8位来表示数值。

  • 正数的例子5 << 1

    • 原始的二进制形式: 00000101 (即十进制的5)
    • 左移一位后: 00001010 (即十进制的10)
    • 解释: 左移相当于乘以2(对于每次左移)。
  • 负数的例子-5 << 1

    • 原始的二进制形式(补码表示): 11111011 (即十进制的-5)
    • 左移一位后: 11110110 (如果考虑溢出,具体值取决于系统如何处理溢出)
    • 解释: 注意到符号位也被移动了,因此结果可能不再是简单的原数乘以2,特别是当涉及到溢出时。

2. 带符号右移 (>>)

  • 正数的例子8 >> 1

    • 原始的二进制形式: 00001000 (即十进制的8)
    • 右移一位后: 00000100 (即十进制的4)
    • 解释: 对于正数,右移一位相当于除以2并向下取整。
  • 负数的例子-8 >> 1

    • 原始的二进制形式(补码表示): 11111000 (即十进制的-8)
    • 右移一位后: 11111100 (即十进制的-4,因为左边用1填充保持负号)
    • 解释: 负数右移时,左边用符号位(这里是1)填充,确保结果仍然为负数。

3. 无符号右移 (>>>)

  • 正数的例子8 >>> 1

    • 原始的二进制形式: 00001000 (即十进制的8)
    • 无符号右移一位后: 00000100 (与带符号右移相同,在这种情况下)
    • 解释: 对于正数,无符号右移和带符号右移的结果是一样的。
  • 负数的例子-8 >>> 1

    • 原始的二进制形式(补码表示): 11111000 (即十进制的-8)
    • 无符号右移一位后: 01111100 (在8位系统中,这代表一个大正数,具体值取决于系统的解释)
    • 解释: 对于负数,由于左边总是用0填充,原本代表负数的位模式变成了一个非常大的正数。

总结

  • 左移:对正数和负数都适用,主要影响是数值大小的变化;需要注意潜在的溢出问题。
  • 带符号右移:适用于需要保留数值符号的情况,特别是处理负数时;左边用符号位填充。
  • 无符号右移:适用于不需要考虑符号的场景,例如处理无符号整数;左边总是用0填充。

在计算机科学中,整数的二进制表示通常涉及三种编码方式:原码、反码和补码。这三种编码方式主要用于处理有符号整数(即包括正数、负数和零)。以下是每种编码方式的详细解释:

1. 原码(Sign-Magnitude)

  • 定义:原码是最直观的表示法,首位(最左边的位)表示符号,0代表正数,1代表负数;其余位表示该数的绝对值。
  • 示例
    • 对于 +5(假设8位系统),原码为 00000101
    • 对于 -5,原码为 10000101

2. 反码(One's Complement)

  • 定义:对于一个给定的数值,其反码是通过将原码中的每个位取反得到的(即将1变为0,将0变为1)。特别地,对于正数,其反码与原码相同;对于负数,则需要对其非符号位进行取反操作。
  • 示例
    • 对于 +5(假设8位系统),反码为 00000101 (与原码相同)
    • 对于 -5,反码为 11111010 (对 +5 的原码除符号位外的所有位取反)

3. 补码(Two's Complement)

  • 定义:补码是目前大多数计算机系统用来表示有符号整数的方法。它是基于反码的一个简单变体,即在反码的基础上加1。这种编码方式允许使用相同的硬件来执行加法和减法运算,并且解决了反码中存在的“正零”和“负零”的问题。
  • 计算方法
    • 正数的补码与其原码相同。
    • 负数的补码可以通过对其对应正数的原码先求反码再加1得到。
  • 示例
    • 对于 +5(假设8位系统),补码为 00000101
    • 对于 -5,补码为 11111011 (首先对 +5 的原码求反得到 11111010,然后加1)

特点与优势

  • 补码的优势在于它简化了加法和减法运算的实现,因为可以使用同样的电路设计来处理这两种运算。此外,它还唯一地表示了零(即不存在+0和-0的区别),并且使得数值范围更高效地覆盖整个可能的表示范围。
  • 在n位的二进制补码系统中,可以表示的数值范围是从 (-2^{n-1}) 到 (2^{n-1}-1)。

运算符优先级

  1. 后缀运算符:如后缀自增 i++ 和后缀自减 i--
  2. 一元运算符(前缀):如前缀自增 ++i、前缀自减 --i、正号 +、负号 -、逻辑非 !、按位非 ~
  3. 算术运算符
    • 乘法 *、除法 /、取模 % (乘性)
    • 加法 +、减法 - (加性)
  4. 移位运算符:左移 <<、带符号右移 >>、无符号右移 >>>
  5. 关系运算符:小于 <、大于 >、小于等于 <=、大于等于 >=instanceof
  6. 相等运算符:等于 ==、不等于 !=
  7. 按位与 &
  8. 按位异或 ^
  9. 按位或 |
  10. 逻辑与 &&
  11. 逻辑或 ||
  12. 条件运算符(三元运算符)?: 如 boolean ? valueIfTrue : valueIfFalse
  13. 赋值运算符:简单赋值 =、复合赋值 +=-=*=/=&=^=|=<<=>>=>>>=

原文始发于微信公众号(安全泡泡鱼):JAVA

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年3月26日08:54:58
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JAVAhttps://cn-sec.com/archives/3885307.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息