-
在Java中,存在多种锁机制和类型,每种锁都有其特定的使用场景。以下是Java中常见的锁类型及其使用场景的列举:内置锁(synchronized)类型:内置于Java语言中的关键字,用于提供互斥访问。使用场景:适用于简单的情况,为方法或代码块提供互斥访问。在需要细粒度锁定的场景中使用,例如保护特定代码段的执行。显示锁(如ReentrantLock)类型:Java标准库中的Lock接口的一个实现,提供了更多的锁定功能。使用场景:需要更高级功能的场景,如尝试锁定、定时锁定和可中断锁定。在需要更细粒度控制锁或需要在等待锁时提供更多控制的情况下使用。读写锁(ReadWriteLock)类型:允许同时读取多个线程,但只允许一个线程进行写操作的锁。使用场景:读多写少的场景,允许多个线程同时读取共享资源,但在写入时提供独占访问。在数据库操作、缓存读取等场景中特别有用。乐观锁与悲观锁类型:乐观锁:认为一个线程去拿数据时不会有其他线程对数据进行更改,适合读操作多的场景。悲观锁:认为一个线程去拿数据时一定会有其他线程对数据进行更改,适合写操作多的场景。使用场景:乐观锁:CAS机制、版本号机制等实现,如AtomicBoolean、AtomicInteger等原子操作类。悲观锁:通过加锁来实现,如synchronized关键字和Lock的实现类。公平锁与非公平锁类型:公平锁:按照请求锁的顺序来获取锁。非公平锁:不保证按照请求锁的顺序来获取锁。使用场景:公平锁:适用于需要确保线程按照请求顺序访问共享资源的场景。非公平锁:在性能要求高且对公平性要求不高的场景下使用。可重入锁与不可重入锁类型:可重入锁:同一个线程可以多次获取同一把锁而不会发生死锁。不可重入锁:一个线程在持有锁的情况下,不能再次获取该锁。使用场景:可重入锁:适用于递归方法或嵌套方法调用中需要加锁的场景。自旋锁类型:尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁。使用场景:适用于同步代码块中的内容执行时间较短的场景,可以减少线程上下文切换的消耗。分段锁类型:将一个大的对象分割成多个小的部分,每个部分独立加锁。使用场景:在处理大数据结构(如哈希表)时,为了提高并发性能,可以使用分段锁来减少锁的竞争。偏向锁类型:针对加锁对象的一种优化手段,当一个线程第一次访问一个对象时,会将该对象设置为偏向自己的状态,后续访问时无需再进行加锁操作。使用场景:在只有一个线程长时间持有锁的情况下,偏向锁可以提高性能。这些锁类型各有特点,选择哪种锁取决于具体的应用场景和需求。在编写多线程程序时,正确选择和使用锁机制对于确保线程安全和提高程序性能至关重要。
-
在Java中,synchronized和Lock都是用于实现线程同步的机制,但它们之间存在一些显著的区别。以下是关于它们的主要区别和速度对比的详细解释:区别实现方式:synchronized是Java的一个关键字,它可以应用于方法或代码块。当使用synchronized时,Java会自动为你管理锁的获取和释放。Lock是Java的一个接口(通常使用ReentrantLock实现),它需要你手动创建锁对象,并显式地调用lock()和unlock()方法来获取和释放锁。粒度:synchronized通常锁定的是整个对象,即当一个线程获得了某个对象的锁后,其他线程无法获得该对象的任何锁。Lock可以实现更细粒度的锁定,例如可以对对象的某个属性或者某一段代码块进行加锁,从而提高并发性能。错误处理:在synchronized块中,如果发生异常,锁会在异常抛出后自动释放。在Lock中,如果发生异常,你需要确保在finally块中手动调用unlock()来释放锁,否则可能导致死锁。锁的类型和特性:synchronized只有一种类型的锁,即互斥锁,它是非公平锁。Lock提供了多种类型的锁,包括公平锁和非公平锁,以及更高级的特性,如可重入性、中断等待获取锁等。性能:synchronized在Java的实现中已经做了很多优化,如偏向锁、轻量级锁和重量级锁,这些优化使得它在低竞争情况下的性能几乎与Lock相当。Lock通常在高竞争环境下表现得更高效,因为它提供了更精细的锁控制,减少了不必要的线程上下文切换和资源浪费。速度对比速度对比的结果可能因具体的测试环境和场景而有所不同。但一般来说,以下是一些可能的结论:在低竞争环境下,synchronized和Lock的性能相差不大,因为synchronized的优化使得它在这种情况下表现得很好。在高竞争环境下,Lock通常比synchronized更高效,因为它提供了更精细的锁控制和更少的线程上下文切换。例如,在参考文章3中,通过一系列测试,作者发现:在单线程环境下,synchronized和Lock的性能相差不大。在多线程环境下,如果竞争复杂,则使用Lock的效率更高;如果竞争简单,则可使用synchronized。总结选择使用synchronized还是Lock取决于具体的应用场景和需求的复杂程度。如果你只需要简单的线程同步,并且竞争不激烈,那么synchronized可能是一个更好的选择,因为它使用起来更简单,且性能也足够好。但如果你需要更复杂的同步机制,如可重入锁、公平锁等,或者在高竞争环境下需要提高性能,那么Lock可能是更好的选择。
-
在Spring Boot中,ThreadLocal 是一个Java提供的类,它允许我们创建线程局部变量。这些变量与线程绑定,并且每个线程对其自己的实例拥有其自己的初始值副本。这意味着在一个线程中对该变量的修改不会影响其他线程中的变量。ThreadLocal 的函数声明ThreadLocal 类中有很多方法,但以下是最常用的几个:构造方法:ThreadLocal():创建一个线程局部变量。设置值:public void set(T value):设置当前线程的线程局部变量的值。获取值:public T get():返回此线程局部变量的当前线程的值。如果此线程局部变量是第一次被当前线程访问,并且还没有值,那么将调用其 initialValue() 方法(除非它已经被其他线程设置过值)。移除值:public void remove():移除此线程局部变量的值。如果此线程局部变量再次被当前线程访问,那么它将重新调用其 initialValue() 方法(除非它已经被其他线程设置过值)。初始值:protected T initialValue():返回此线程局部变量的初始值。此方法通常只会被 ThreadLocal 类本身调用,在 get() 方法被首次调用但变量尚未设置时。默认情况下,此方法返回 null,但可以通过继承 ThreadLocal 并重写此方法来自定义初始值。为什么要用到 ThreadLocalThreadLocal 主要用于解决多线程环境中数据共享和隔离的问题。在多线程编程中,有时我们需要在不同线程之间传递数据,但又不想使用线程不安全的共享变量或复杂的同步机制。在这种情况下,ThreadLocal 可以为每个线程提供一个独立的变量副本,从而避免了线程之间的数据竞争和同步问题。实战中的用法假设我们有一个Web应用程序,其中每个请求都需要访问一些与请求相关的数据(如用户ID、语言设置等)。我们可以使用 ThreadLocal 来存储这些数据,以便在请求处理过程中方便地访问它们。以下是一个简单的示例:public class RequestContext { private static final ThreadLocal<String> userIdThreadLocal = new ThreadLocal<>(); public static void setUserId(String userId) { userIdThreadLocal.set(userId); } public static String getUserId() { return userIdThreadLocal.get(); } public static void clear() { userIdThreadLocal.remove(); } } // 在某个过滤器或拦截器中设置用户ID @Component public class UserIdFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String userId = // 从请求中提取用户ID的逻辑 RequestContext.setUserId(userId); try { chain.doFilter(request, response); } finally { RequestContext.clear(); // 确保在请求处理完成后清除ThreadLocal中的数据 } } } // 在服务层或其他组件中访问用户ID @Service public class SomeService { public void doSomething() { String userId = RequestContext.getUserId(); // 获取当前线程的用户ID // ... 执行一些与用户ID相关的操作 ... } }请注意,在使用 ThreadLocal 时要小心内存泄漏。由于 ThreadLocal 的生命周期与线程的生命周期相同,如果线程长时间运行并且 ThreadLocal 变量没有被正确清除(通过调用 remove() 方法),那么这些变量可能会占用大量内存,导致内存泄漏。因此,在请求处理完成后,务必清除 ThreadLocal 中的数据。
-
我编写了一个有700多行代码的Java程序,已经打包为可以运行的Jar程序,双击运行后可以读取D分区下的建立的“boxs.txt”文件,读取其中的数据生成大小及位置任意设定的长方体,可以设定描边和填充颜色,可以设定透明度,可以旋转长方体,可以根据字符串来排列各个长方体的前后绘制循序,我想将其发布,不知在哪里可以呢?给看看截屏,运行程序读取文本文件的数据和字符串生成了一个桌子,还可以生成较简单的房子以及更为复杂的建筑等等。
-
1.正则表达式匹配引号匹配双引号"用\"匹配单引号'用'2.正则表达式匹配正则表达式中用到的特殊符号时需加\\如()[]{}/|\-+匹配[用\\[匹配]用\\]匹配\用\\\\匹配/用\\/匹配|用\\|匹配-用\\-匹配+用\\+匹配大写英文或小写英文或数字或下划线用\\w或0-9a-zA-Z_3.正则表达式中各种扩号()[]{}作用中括号[]表示匹配单个字符,匹配中扩号里列出的任意一个字符1[dsa]//匹配d或s或a小括号()表示匹配字符串,匹配小扩号里列出的所有字符构成的字符串1(dsaff) //仅能匹配dsaff大括号{}表示匹配的次数,放于()或[]之后1[dsa]{1,8}//匹配1-8次[dsa],如匹配d,dd,dddddddd1(dsa){1,8}//匹配1-8次(dsa),如匹配dsa,dsadsadsadsadsadsadsadsa4.常用匹配例子例子(匹配英语键盘上的任意非空字符)12345QRegExp re("^[\\w~!@#$%^&*()+`={}:;<>?,.|'\"\[\\]\\-\\/\\\\]+$"); QString test("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`1234567890-=~!@#$%^&*()_+[]{}|;:'\"\\/,.<>?");bool match = re.exactMatch(test); //match=true例子(匹配任意合法表示的有理数)12345QRegExp reg("^(\\-(?!0(?!\\.))|\\+(?!0(?!\\.)))?(0|[1-9]\\d*)(\\.\\d+)?$"); QString test("41424.4155346");bool match = re.exactMatch(test); //match=true例子(匹配任意合法表示的非负有理数)12345QRegExp reg("^(\\+(?!0(?!\\.)))?(0|[1-9]\\d*)(\\.\\d+)?$"); QString test("41424.4155346");bool match = re.exactMatch(test); //match=true例子(匹配任意合法表示的正有理数)12345QRegExp reg("^(\\+)?(0(?=\\.)|[1-9]\\d*)(\\.\\d+)?$"); QString test("41424.4155346");bool match = re.exactMatch(test); //match=true例子(匹配任意合法表示的整型数字)12345QRegExp reg("^(\\-(?!0)|\\+(?!0))?(0|[1-9]\\d*)$"); QString test("414246");bool match = re.exactMatch(test); //match=true例子(匹配任意合法表示的非负整型数字)12345QRegExp reg("^(\\+(?!0))?(0|[1-9]\\d*)$"); QString test("414246");bool match = re.exactMatch(test); //match=true例子(匹配任意合法表示的正整型数字)12345QRegExp reg("^(\\+)?([1-9]\\d*)$"); QString test("414246");bool match = re.exactMatch(test); //match=true例子(匹配任意合法表示的密码)123456789QRegExp reg("^[\\w~!@#$%^&*()+`={}:;<>?,.|'\"\[\\]\\-\\/\\\\]+$"); if (!reg.exactMatch(value.data())) { message_ = QObject::tr("The password can only contanin numbers, English " "characters or special characters ") .toStdString(); return false; } return true;
-
JAVA中没有指针一说,但也有引用的概念。这里要说的主要是Integer是不是同一个对象。 1、先看一段代码: public static void main(String[] args){ Integer a1 = 100; Integer b1 = a1;//另一种也可以b1=100 Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); }field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("b1="+b1); Integer c1 = 100; System.out.println("c1="+c1); } 结果: b1=5000 c1=5000 从上面,首先这里要说明几个, 1)、对于Integer来说,-128-127之间的整型已经初始化放在IntegerCache中,如果是装箱的话,就会从这里面取对象。 2)、b1=a1到底是数字赋值还是同一个对象?这个从结果实际就可以看出来,b1和a1指向同一个对象,而不是同一个数值 3)、c1=100,说明对于-128-127之间的数值,都是从IntegerCache中获取的对象,100对应的Integer对象被改变后,后续对于100的装箱都被改变。因为获取cache中对象时用的是数组索引,而不是数值比较获取的。 不过修改这个缓存会比较危险,不介意。谁知道什么jar包或者什么平台来个100的装箱,但得到结果又不是100,到时就崩溃了。 2、通过上面描述,那么如果改成这样又是什么答案 public static void main(String[] args){ Integer a1 = 200; Integer b1 = a1; Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("b1="+b1); Integer c1 = 200; System.out.println("c1="+c1); } 3、那么再改一下 public static void main(String[] args){ Integer a1 = new Integer(100); Integer b1 = a1; Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("b1="+b1); Integer c1 = 100; System.out.println("c1="+c1); }这又是什么答案。对于new的操作,是不进行装箱的,而是在堆中生成对象的。 理解了装箱、缓存、引用就不难理解了。可以自己试试。 ———————————————— 原文链接:https://blog.csdn.net/weixin_39637919/article/details/114523910
-
java八种基本数据类型分为四类八种 四类分别为整型、浮点型、布尔型、字符型; 八种分别为byte、short、int、long、float、double、boolean、char; java八种基本数据类型的字节数 分别为1、2、4、8个字节;1字节(byte、boolean)、 2字节(short、char)、4字节(int、float)、8字节(long、double); 整数的默认类型为int,浮点数的默认类型为double; 八种基本数据类型的包装类:除了char的是Character、int类型的是Integer,其他都是首字母大写 关于值的范围问题,需要注意char类型是无符号的,不能为负,所以是0开始的 二、引用数据类型 1.数组 2.接口 3.类 正文 一、包装类(Integer) 1.所在包位置 2.类继承关系 3.接口实现关系 4.final修饰(不能有子类不能被继承) 5.包装类是对基本数据类型的封装 Integer 类在对象中包装了一个基本类型 int 的值。Integer 类型的对象包含一个 int 类型 的字段 1.装箱 基本数据类型------》包装类 int-----》integer 2. 拆箱 包装类------》基本数据类型 integer---int 6.构造器(有参) 1.底层源码分析 1.根据Integer(int value)有参构造器编写代码如下 public class Test01 { public static void main(String [] arge){ Integer integer=new Integer(10);//实例化传入参数 System.out.println(integer.toString()); } } Integerl类的有参构造方法 public Integer(int value) { this.value = value; } Integer类final修饰的属性 private final int value; 总结 根据Integer类的有参构造方法(Integer(int value))进行实例化(new Integer(10))然后根据Integer类有参构造方法接收value值并且赋予给final修饰的int变量 归根接地Integer的底层就是int 2.根据Integer(String s)有参构造器分析 ———————————————— 原文链接:https://blog.csdn.net/m0_67929156/article/details/124162285
-
Java 中有八种内置的基本数据类型,他们分别是 byte、short、int、long、float、double、char 和 boolean,其中,byte、short、int 和 long 都是用来表示整数,float 和 double 是用来表示浮点数的,那它们之间有什么区别和联系呢?除了这八种基本类型(primitive type)外,其余的类型都是引用类型(reference type)。但是包装类型(wrapper class) Integer 和 Long 也可以用来表示整数,那它们与 int 和 long 又有什么区别和联系呢?这八种基本类型之间的运算关系又是怎样的呢? 一、基本类型 基本类型的表示范围 八种基本类型中,char 类型是用来表示字符的,boolean 类型是用来表示布尔值的,除此之外的 6 种都是用来表示数字的。byte、short、int 和 long 是用来表示整数的,float 和 double 是用来表示浮点数的。下面是每一种类型能表示的范围: 基本类型 位数 最小值 最大值 byte 8 -128 (-2^7) 127 (2^7-1) short 16 -32,768 (-2^15) 32,767 (2^15-1) int 32 -2,147,483,648 (-2^31) 2,147,483,647 (2^31-1) long 64 -9,223,372,036,854,775,808 (-2^63) 9,223,372,036,854,775,807 (2^63-1) float 32 1.4E-45 (0x0.000002P-126) 3.4028235E38 (0x1.fffffeP+127) double 64 4.9E-324 (0x0.0000000000001P-1022) 1.7976931348623157E308 (0x1.fffffffffffffP+1023) char 16 \u0000 (0) \uFFFF (65,535) boolean 1 false true 定义变量时超过对应数据类型最大的表示范围的话将报错。位数越大,单个该数据类型的变量所占用的内存就越多。 每一种类型的最大最小值都保存在了其对应包装类型的属性中,如 Integer.MAX_VALUE 的值为 2147483647,关于包装类型,下面会做详细说明。 类型的默认值 每一种类型都有一个默认值,除基本类型外,其他的类型的默认值都是 null,因为它们都是引用类型。整数默认为 int 类型,浮点数默认为 double 类型。 类型 默认值 byte 0 short 0 int 0 long 0L float 0.0f double 0.0 char '\u0000' boolean false String、Integer 等引用类型 null 当我们定义静态的基本类型变量时,它们将采用默认值: public class Test { static byte b; static short s; static int i; static long l; static float f; static double d; static char c; static boolean bool; static String str; public static void main(String[] args) { System.out.println("byte " + b); // byte 0 System.out.println("short " + s); // short 0 System.out.println("long " + l); // long 0 System.out.println("int " + i); // int 0 System.out.println("float " + f); // float 0.0 System.out.println("double " + d); // double 0.0 System.out.println("char " + c); // char '\u0000' (这个显示不出来) System.out.println("boolean " + bool); // boolean false System.out.println("String " + str); // String null } } 类型之间的转换 类型之间的转换有自动类型转换和强制类型转换两种。自动类型转换也称隐式转换,是编译器自动进行的,强制类型转换称为显式转换,是写代码时显式地完成的。 自动类型转换(隐式转换) 在八种基本数据类型中,除开 boolean 类型,其他的七种都是可以互相进行运算的(如加减法运算)。不同的类型在进行运算的时候,低位的数据类型会向高位的转化,最后的计算结果将是整个运算过程中数据类型位数最大的,这就是自动类型转换。 int a = 1; long b = 2; int c = a + b; // Error long c = a + b; // Right 但要注意一点,比 int 类型数据小的数据类型在做运算的时候,会转换成 int 类型然后再做运算,尽管计算结果能被 byte 或 short 类型表示: short c = 1, d = 2; short e = c + d; // Error int e = c + d; // Right 自动类型转换的规则可以总结为如下: 若有一个变量是 double 类型,则另一个也会被隐式转换为 double 类型;否则,若有一个变量是 float 类型,则另一个也会被隐式转换为 float 类型;否则,若有一个变量是 long 类型,则另一个也会被隐式转换为 long 类型;否则,若有一个变量是 int 类型,则另一个也会被隐式转换为 int 类型。特别的,boolean 类型无法转换(包括自动类型转换和强制类型转换) 即,自动类型转换优先级为:double > float > long > int > short = char = byte (boolean 不可转换) 注意:在 short、byte 和 char 之间不会发生自动类型转换,它们运算时都会先转换成 int 类型,结果最终也是 int 类型,所以前面说,比 int 还小的类型在运算时会被自动转换为 int 类型。 强制类型转换(显式转换) 强制类型转换就是在程序中显式地将一个变量从某一类型强制转换成另一类型。从小位类型到大位类型的转换是向上转换,一般这是没有问题的,但反过来,从大位类型转换到小位类型,即向下转换,是有可能发生数据溢出或者精度损失的。 int a = 32768; float b = 3.1415926f; System.out.println((long)a); // Right // Output: 1 System.out.println((short)a); // overflow // Output: -32768 System.out.println((int)b); // loss of accuracy // Output: 3 数据溢出和精度损失 这里关于数据溢出和精度损失做一些简单的说明。 数据溢出 数据溢出之后变量也还是有值的,程序也不会报错,那溢出后的值是如何计算出来的?这实际上和数据存储的规则有关,涉及到原码、反码和补码等知识,这里不会详细说明这个规则,我们只需要一张图便能知道溢出后的值是如何计算得到的。 数据溢出解释图(以 short 类型为例) 举个例子,int 类型变量值为 131073,在强制类型转换为 short 类型后值就变为了 1。我们可以这样理解,上面的图是 short 类型变量所有的取值,从 0 开始,131073 一个一个去对应,到 32768 时发生数据溢出,变成了 -32768,继续顺时针旋转去对应每个数,最会对应两圈多两个数,然后 131073 对应到第三圈的第二个数字 1,因此,强制类型转换数据溢出后的结果为 1。 注意:131073 = 65536 * 2 + 1 int a = 131073; System.out.println((short)a); // Output: 1 精度损失 在数据存储长度比较长的数据转换为数据存储长度较短的类型时,就可能会发生精度损失,因为要把长数据变成短数据只能将数据后面多余的部分截断才行。因为转换方式采用的是截断多余的,因此我们可以认为当浮点型数据转换为整型数据时是做了一个向零取整的操作(直接舍去小数)。 float a = 3.14f, b = -3.14f; System.out.println((int)a); // Output: 3 System.out.println((int)b); // Output: -3 隐含强制类型转换 除了前面提到的两种,还有一种隐含的强制类型转换,一个整数数字(int 表示范围之内的)会被隐含地转换成 int 类型,一个浮点数字会被隐含地转换成 double 类型。这也解释了为什么前面说整数默认是 int 类型,浮点数的默认类型是 double 类型了。所以,以后在用 float 类型时一定要在后面加上字母 f 或 F,long 类型后面要加上字母 l 或者 L。 二、包装类型 基本数据类型并不是对象,但为了编程的方便,Java 还是引入了它们,也就是前面提到的八个基本类型,但要将其作为对象来操作的话,还是要用这八个基本类型对应的包装类型(wrapper class)。这个包装类型就是 Java 对基本类型的封装,使其能作为对象使用,它们与其他的类型并没有什么太多的区别,都是引用类型(reference type)。 基本类型 包装类型 byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean 在 Java5 的时候引入了自动装箱/拆箱机制,使得基本类型和对应的包装类型之间可以相互转换。 基本类型和包装类型的区别 基本类型和包装类型在使用时所表示的值是一样的,表示的范围也是对应的,当 int 类型在转换为 Integer 类型的时候,实际上是调用了 Integer 的 valueOf 方法: Integer a = 1; Integer a = Integer.valueOf(1); // the two are equivalent 下面我们列出基本类型和包装类型的一些区别: 基本类型不是对象,而包装类型是对象(有属性和方法); 基本类型不需要实例化,而包装类型需要实例化; 基本类型是直接存储的值,而包装类型是对实例对象的引用; 基本类型有特殊的默认值(如 int 的默认值是 0),而包装类型都是 null; 基本类型所占用的内存比较少,包装类型占用内存较大; 同一基本类型相同值的不同变量的内存地址一样,但实例化得到的同一包装类型相同值的不同变量的内存地址不一样; 基本类型的运算是直接进行的,而包装类型的运算要先拆箱为基本类型才能进行运算。 对象有属性和方法,前面提到的 Integer.MAX_VALUE 就是包装类型的一个属性,上面提到的 Integer.valueOf() 就是一个方法,而基本类型 int 是没有这些的。 基本类型的值都是直接储存的,所以同一个基本类型、相同值的不同变量的地址是一样的: int a = 1, b = 1; System.out.println(a == b); // Output: true 包装类型都是对象实例化的引用,一般每个对象都拥有不同的内存空间,它们的内存地址也就不一样: Integer a = new Integer(100); Integer b = new Integer(100); System.out.println(a == b); // Output: false valueOf 方法的缓存机制 如果一个 Integer 实例对象是由基本类型转换而来的,值处于 -128 ~ 127 之间时,之前的代码输出结果就为 true 。是因为转换时调用的 valueOf 方法有一个缓存机制。 这个判断范围 -128 ~ 127 是默认的,可以在 JVM 提供的配置 (-XX:AutoBoxCacheMax) 进行修改。 为什么要有这个缓存机制?这是因为处于这个区间的值比较小,而且又比较常用,因此编译器就提前将其缓存了,需要时就直接从缓存里拿,既能提高速度,又能在同样值的包装类型较多的时候节省内存。所以,两个值在 -128 ~ 127 之间,且由基本类型 int 转换而来的 Integer 就是同一个对象。这对于包装类型 Byte、Short 和 Long 也是一样的。 Integer a = 100, b = 100; System.out.println(a == b); // Output: true Integer c = 128, d = 128; System.out.println(c == d); // Output: false 与此类似的还有包装类型 Boolean,它一共就只有两种可能,true 和 false,因此也被提前缓存了。包装类型 Character 在 '\u0000' ~ '\u007F' 之间的值(0 ~ 127)也是被提前缓存了。不过包装类型 Float 和 Double 的 valueOf 方法就没有这个缓存机制了。 基本类型和包装类型的联系 为什么包装类型叫做“包装类型”呢?顾名思义,就是对基本类型的一个封装,从名字里我们就能知道,基本类型和包装类型之间的实际上有个装箱与拆箱的关系。 直接由基本类型 int 转化而来的 Integer 对象是对 int 类型的装箱操作,而由 Integer 对象转换来的 int 类型变量就是对 Integer 对象的拆箱操作。 Integer a = 1; // 装箱 Integer a = Integer.valueOf(1); // 等价形式 int b = a; // 拆箱 int b = a.intValue(); // 等价形式 实例化生成的 Integer 类型变量与基本类型转化而来的 integer 类型变量尽管值相同,但内存地址并不相同(非 new 生成的 Integer 对象指向 Java 常量池中的对象),不是同一个对象,所以在比较的时候输出 false。但是当二者与基本类型相同值的变量去比较时却都输出 true。 Integer a = 1; Integer b = new Integer(1); System.out.println(a == b); // Output: false int c = 1; System.out.println(c == a); // Output: true System.out.println(c == b); // Output: true 这是因为包装类型 Integer 与基本类型在比较的时候会自动拆箱为 int 类型,然后再去比较,这样所得到的结果就是一样的,因此输出 true。 ———————————————— 原文链接:https://blog.csdn.net/weixin_62651706/article/details/130742296
-
处理场景:通过文本框获取用户输入的数字数据,可是得到的都是字符串,如果想要对这些字符串的数字进行运算,必须妖精字符串转化成数字, 在Java中提供了相应的解决的对象 基本数据类型包装类:Java将基本数据类型值封装成了对象。封装成对象有什么好处?——这样可以提供更多操作基本数值的功能 一般我们对数值的基本操作就是通过运算符来进行运算但是如果我们想要获得一个数值的二进制,这个就是对数值的更多操作,这些功能封装到对象中 基本数据类型:byte short int long float double boolean char 对应的类 :Byte Short Integer Long Float Double Boolean Character 特点:(以整数Integer为例) 1.类中包含了对数值操作的多种功能 2.基本数据类型包装类型最重要的特点及作用:提供了数值与字符串相互转化的方法(重点解析) 1.怎么将字符串转化为基本数值(不是按照进制转化而是直接从表面转化)。结果就应该是基本数值,参数为字符串 ”1234“————1234 "a1234"——出现传入数据类型异常 static int parseInt(String s) 将字符串参数解析为带符号的十进制整数。 各种基本数据的解析方法: xxx parseXxx(String s); character() 没有解析方法。 在parseInt(); 方法使用时会抛出一个异常,NumberFormatException 传入的数据错误,这是一个运行时异常,可以声明(提供一个解决办法),也可以不声明,让程序直接停止并抛出异常。 2.parseInt() 的一个重载形式:将字符串按照所需的进制转化为十进制 static int parseInt(String s, int radix) 将字符串参数解析为第二个参数指定的基数中的有符号整数。 函数的功能是将 String s 这个字符串按照 radix 所规定的进制,转换成整数。要求:字符串的书写必须符合进制的要求。 例如:paresInt("5959",2); 这样的语句就会抛出异常,因为二进制只能由1 0 组合。16进制以上所含的字母也要符合要求。 3.将十进制转化为其他进制 static String toBinaryString(int i) 在基数2中返回整数参数的字符串表示形式为无符号整数。 static String toHexString(int i) 返回整数参数的字符串表示形式,作为16位中的无符号整数。 static String toOctalString(int i) 在基数8中返回整数参数的字符串表示形式为无符号整数。 如何将数字转化为字符串 String.value(int i); Integer.toString(int i); 代码: package Wrapper; public class WrapperDemo1 { public static void main(String[] args){ /* /基本数据类型包装类 1.提供操作数据的多种功能 2.重点功能:数值和字符串的相互转化进制的转化********** */ System.out.println(Integer.MAX_VALUE);//整数的最大值 System.out.println(Integer.MIN_VALUE );//整数的最小值 //将字符串转化为数值 System.out.println(Integer.parseInt("123456"));//将字符串直接转化为十进制 System.out.println(Integer.parseInt("10101",2));//将字符串按照要求对的进制转化为十进制 //将十进制转化为其他进制 System.out.println(Integer.toBinaryString(12));//转化为二进制 System.out.println(Integer.toHexString(16));//转化为8进制 System.out.println(Integer.toOctalString(15) );//转化为16进制 //将数值转化为字符串 System.out.println(Integer.toString(484848)); System.out.println(String.valueOf(23.23)); } } 运行结果: 2147483647 -2147483648 123456 21 1100 10 17 484848 23.23 ————————————————基本数值和对象之间的转化—————————————————— //基本数值怎么变成包装对象 //构造函数 Integer in= new Integer(4);//将数值4 变成了包装好的对象 Integer i= new Integer("4");//也是创建数值4的对象(字符串被转化成了对象) //静态方法 Integer ii = Integer.valueOf(4); //包装好的对象怎么转化成数值(方法肯定是非静态的,要通过对象调用) int num=i.intValue(); System.out.println(num); ————————————自动拆箱装箱———————————————————————————— 在之前的书写中: int i=4; 只是定义了基本的数据,可以非常方便的进行运算 Integer i= Integer(4); 定义了一个对象,可以提供了很多对数据的操作,但是就进行基本的运算就显得有一点麻烦,因此找一个折中的办法 因此在JDK1.5 以后,有了yi一个包装类的新特性 Integer i = 4; 左边是一个引用型变量,右边是一个对象(新特性,简化书写)——自动将4封装——自动装箱 /// Integer.valueOf(4); valueOf(); 源代码: public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } 其实在最底层,还是使用的new Integer(int i); 这样的书写,一是使书写更加的简便,二是是使用更加的方便灵活,可以同时,实现调用操作对象的功能,运算也变得十分方便 a=a+5; 将右边的a 由对象转化成了数值,自动拆箱a.intValue()+5,在完成加法运算后又自动封箱(全自动) a=Integer.valueOf().(i.intValue()+5);//在1.5以下的版本中的书写 1.5以后的的这一新的特性在使用的时候,代码的书写上是给使用带来了极大的方便,但是一定要清楚他的原理 关于拆箱封箱的一些细节: //基本数据包装类中的一些细节 Integer num1= new Integer(3); Integer num2= new Integer(3); System.out.println(num1==num2);//false System.out.println(num1.equals(num2));//true //equals 是Object 类中的方法,但是在Integer 中重写了这个方法,建立了自己的比较规则:在对象不为null 时。只要对象包含的int 类型的数值是相等的,那么这两个对象就是相等的 Integer i1 = 127; Integer i2 = 127; Integer i3 = 128; Integer i4 = 128; System.out.println("i1==i2? "+(i1==i2));//ture System.out.println("i1==i2? "+i1.equals(i2));//true System.out.println("i3==i4? "+(i3==i4));//false System.out.println("i3==i4? "+i3.equals(i4));//true equals 是Object 类中的方法,但是在Integer 中重写了这个方法,建立了自己的比较规则:在对象不为null 时。只要对象包含的int 类型的数值是相等的,那么这两个对象就是相等的 在1.5 以后的自动拆箱和封装定义中,如果数值在byte (-128------127)的范围内,不会创建新的对象空间而是使用原来已有的空间——也就是说,当数值在-128 到 127 之间时。两个引用型变量指向的是同一个对象 ————————————————综合练习—————————————————————————————————— ”23 9 -4 18 100 7“ 要求将这串数字按照从大到小排序 思路:1.只要有排序就要有数组,数组中就要有元素 2.元素都在字符串里,要想获得字符串里的内容,就需要创建字符串对象 3.从字符串获取到数值后存储到一个int 数组中进行排序 4.将排序后的数组变成字符串 先定义字符串:String strs = ”23 9 -4 18 100 7“ 1.获取字符串中的数字。通过空格进行indexOf 的索引,找到位置,substring 截取。思路上就可以了,但是这个方法看起来就显得很麻烦,可以直接用split(分割的标记) String[] strs = nums.split(" "); 但是这样分割出来是字符串数组,是无法进行大小比较的,要比较还是要转化成整数才可以。————将字符串数组转化成整数数组 代码: package String; import java.util.Arrays; /* 基本数据包装类:整型 Integer 练习 ”23 9 -4 18 100 7“ 要求将这串数字按照从小到大排序 思路: 1.先定义字符串 2.要排序就需要数组 3.按照空格为分割依据,分成字符串数组,但是无法比较 4.将字符串数组转化为整型数组 5.将整型数组进行比较 6.最后在转化为字符串 */ public class IntegerDemo { //将字符串数组转化为整型数组 private static int[] toIntArray(String[] strs){ int[] nums = new int[strs.length]; for(int i =0 ;i<strs.length;i++){ nums[i] = Integer.parseInt(strs[i]); } return nums; }//1.自己写排序 private static void sortArray(int[] nums){ for(int i=0;i<nums.length-1;i++){ for(int j=i+1;j<nums.length;j++){ if(nums[i]>nums[j]){ int temp=nums[i]; nums[i]=nums[j]; nums[j]=temp; } } } } //将整形数组转化为字符串 private static String toString(int[] nums){ StringBuffer str = new StringBuffer(); for(int i=0;i<nums.length;i++){ if(i!=nums.length-1){ str.append(nums[i]+" "); } else{ str.append(nums[i]); } } return str.toString(); } private static String sortIntArrayString(String str){ //1.转化为字符串数组 final String SPACE = " "; String[] strs = str.split(SPACE); //2.将字符串数组转化为整型数组 int[] nums =toIntArray(strs); //3.将整型数组排序 //调用函数排序 Arrays.sort(nums); sortArray(nums); //转化为字符串 str= toString(nums); return str; } public static void main(String[] args){ String str ="23 9 -4 18 100 7"; str =sortIntArrayString(str); System.out.println("str = "+str); } } //学习了 String String Buffer StringBuilder 基本数据类型包装类 ———————————————— 原文链接:https://blog.csdn.net/Stitch__/article/details/82142444
-
JAVA中的基本实际原则就是“一切皆对象”。而基本数据类型很显然不是对象,因此可以采用基本数据类型进行包装。 JAVA给出了一组包装类,分别为Byte、Short、Integer、Long、Float、Double、Character、Boolean,对应不同的基本数据类型。 上面的包装类又可以分为两种子类型: 对象型包装类(Object直接子类):Character、Boolean 数值型包装类(Number直接子类):Byte、Short、Integer、Long、Float、Double Number是一个抽象类,其中一共定义了6个操作方法,分别是intValue/doubleValue/floatValue/byteValue/shortValue/longValue。 装箱与拆箱 基本数据类型和包装类之间的转换可以通过以下方法定义: 装箱操作:将基本数据类型变为包装类,每个包装类的构造方法都可以接收各自数据类型的变量 拆箱操作:从包装类中取出被包装的数据,利用从Number类中继承而来的一系列xxxValue方法完成 public class Demo { public static void main(String args[]) { Integer obj = new Integer(10); int num = obj.intValue(); System.out.println(num); } } 简单地说,装箱就是有参构造,拆箱就是调用xxxValue方法获得内部数据。除了int外,double也是一样的操作。而boolean虽然是Object的子类,但也有同样的操作。 自动装箱和自动拆箱 自动装箱和自动拆箱是指上述的操作都是自动进行的,无需进行构造操作。 public class Demo { public static void main(String args[]) { Integer obj = 10; int num = obj; System.out.println(obj); ++obj; System.out.println(obj); } } 结果为: 10 11 从上面的代码看,基本数据类型和包装类之间的转换是自动的,并不需要显式进行装箱和拆箱操作。 再看一段代码: public class Demo { public static void main(String args[]) { Integer obj1 = 10; Integer obj2 = 10; Integer obj3 = new Integer(10); System.out.println(obj1 == obj2); System.out.println(obj1 == obj3); System.out.println(obj2 == obj3); System.out.println(obj2.equals(obj3)); } } 结果为: true false false true 从上面的结果可以看出,自动装箱会保存对象到对象池中,而构造装箱则是会重新开辟新的堆内存空间。因此为了保证对象的有效比较,最好使用equals方法进行比较。 Object 既然知道基本数据类型和和包装类的转换操作,实际上也就可以利用Object来进行统一操作了。所有的引用数据类型都可以利用Object类来接收,而由于存在自动装箱机制,那么基本数据类型同样可以使用Object接收。 public class Demo { public static void main(String args[]) { Object obj = 10; int tmp = (Integer)obj; System.out.println(obj); System.out.println(tmp); System.out.println(tmp * 2); } } 结果为: 10 10 20 从上面的代码可以看出,可以使用Object接收基本数据,并可以直接打印输出,但并不能直接对Object类对象进行基本数据的计算,此时需要向下转型为Integer类型,才能够进行自动拆箱,并进行数据计算。 数据类型转换 而包装类中还存在数据类型转换的操作,在包装类中还提供了将String类数据转换为基本数据的方法,比如: Integer类:public static int parseInt(String s) Double类:public static double parseDouble(String s) Boolean类:public static boolean parseBoolean(String s) 实际上,在给出的8种基本数据类型的包装类中,一共有7个类定义了parseXxx()的方法,可以实现将String变为基本数据类型。但是在Character类中并没有存在这样的方法,相反其对应的方法为charAt()方法。 public class Demo { public static void main(String args[]) { String str1 = "12"; String str2 = "12.3"; int var1 = Integer.parseInt(str1); double var2 = Double.parseDouble(str2); char var3 = str1.charAt(0); System.out.println(var1); System.out.println(var2); System.out.println(var3); } } 结果为: 12 12.3 1 上面的操作可以将String字符串转换为相应的数据类型,但是如果字符串中包含非数字的字符内容,转换就会出现错误。因此实际开发中,需要严格对输入字符串进行检测,防止出错。 上面只是将字符串转换为基本数据类型,同样也可以将基本数据类型转换为字符串: public class Demo { public static void main(String args[]) { int var1 = 10; double var2 = 12.3; boolean var3 = true; String str1 = "" + var1; String str2 = "" + var2; String str3 = "" + var3; String str4 = String.valueOf(var1); String str5 = String.valueOf(var2); String str6 = String.valueOf(var3); System.out.println(str1); System.out.println(str2); System.out.println(str3); System.out.println(str4); System.out.println(str5); System.out.println(str6); } } 结果为: 10 12.3 true 10 12.3 true 上面的代码提供了两种基本数据类型转换为String的操作,之前提到字符串和基本数据类型相加会转换为字符串,因此一种操作就是与空字符串进行相加,另一种操作就是使用String中的valueOf方法进行转换。 ———————————————— 原文链接:https://blog.csdn.net/SAKURASANN/article/details/124647622
-
3.3 char 与 Character 之间的转换 3.3.1 char → Character 3.3.2 Character → char 3.4 boolean 与 Boolean 之间的转换 3.4.1 boolean → Boolean 3.4.2 Boolean → boolean 3.5 包装类与 String 类型的转换 3.5.1 包装类 → String 3.5.2 String → 包装类 1 Java 的数据类型 =============================================================================== Java 的数据类型可以分为两大类,即基本数据类型和引用数据类型。 2 Java 的包装类 ============================================================================== Java 的包装类便是一种特殊的引用数据类型,因为其是与基本数据类型一一对应的。 虽然基本数据类型的效率更高,然后对于面向对象的语言 —— Java,操作对象比操作基本数据类型更为方便,并且基本数据类型有很多局限性,比如对于 int,其有时无法区分默认值 0 还是真的为 0(比如考试成绩为 0 与没有参加考试 null)。 | 基本数据类型 | 引用数据类型 | | — | — | | byte | Byte | | short | Short | | int | Integer | | long | Long | | float | Float | | double | Double | | char | Character | | boolean | Boolean | 3 装箱和拆箱 ========================================================================== 装箱指的是将基本数据类型转为包装类;拆箱指的是将包装类转为基本数据类型。 以下 Java 的代码实现基于 JDK 1.8。 3.1 int 与 Integer 之间的转换 3.1.1 int → Integer int i = 13; Integer integer = Integer.valueOf(i); 3.1.2 Integer → int Integer integer = 10; int i = integer.intValue(); 其它整数类型(byte、shot、long)的转换方式与 int 相同。 3.2 float 与 Float 之间的转换 3.2.1 float → Float float i = 13; Float fo = Float.valueOf(i); 3.2.2 Float → float Float fo = new Float(13); float i = fo.floatValue(); 3.3 char 与 Character 之间的转换 3.3.1 char → Character char i = ‘s’; Character fo = Character.valueOf(i); 3.3.2 Character → char Character character = new Character(‘s’); char c = character.charValue(); ———————————————— 原文链接:https://blog.csdn.net/shenliba/article/details/137758939
-
基本数据类型间除了boolean和char类型外,都可以相互转换 1 基本数据类型转包装类型–》装箱 int a =10 ; Integer i1 = a;//可以自动转,自动装箱 Integer a1 = new Integer(a);//手动装箱 Integer i = Integer.valueOf(a); 1 2 3 4 2 包装类型转基本数据类型–》拆箱 Integer a =10 ; int i1 = a;//可以自动转,自动拆箱 int i2 = a.intValue();//手动拆箱 1 2 3 3 把字符串转换成基本数据类型,调用包装类的parseXXX方法或者valueOf方法 String s = "1234"; int i = Integer.parseInt(s); double b = Double.parseDouble(s); boolean boo = Boolean.parseBoolean(s); 1 2 3 4 int i = Integer.valueOf(s); 1 4 把基本数据类型转换成字符串 int i =9; //方法1 String s = i+""; //方法2 String s = String.valueOf(i); //方法3 String s = Integer.toString(i); ———————————————— 原文链接:https://blog.csdn.net/ss449988/article/details/103530198
-
装箱: 基本数据类型转换成包装类 拆箱:包装类转化成基本数据类型 装箱分为自动装箱和手动装箱俩种方法。 有装箱操作也会有拆箱操作,而拆箱也会分为自动拆箱和手动拆箱。 代码如下: package box; public class BoxOne{ public static void main(String[] args) { //自动装箱操作 int a=3; Integer a1=a; //手动装箱 Integer a2=new Integer(a); //运行结果值都是 3 //自动拆箱 int a3=a2; //手动拆箱 int a4=a2.intValue(); //运行结果会发现 这俩值是一样的 } } ———————————————— 原文链接:https://blog.csdn.net/zhihu000/article/details/114391378
-
在 Java 编程中,自动装箱(Autoboxing)和自动拆箱(Unboxing)是两个重要的概念。它们使得基本数据类型与其对应的包装类之间的转换更加方便,同时也提高了代码的可读性和可维护性。本篇博客将深入探讨自动装箱和拆箱的概念、用法以及为什么它们对 Java 程序员如此重要。 什么是自动装箱和拆箱? 在理解自动装箱和拆箱之前,让我们先回顾一下 Java 中的基本数据类型和包装类之间的关系。 基本数据类型(Primitive Data Types): Java 提供了一组基本数据类型,如整数(int、byte、short、long)、浮点数(float、double)、字符(char)、布尔(boolean)等。这些基本数据类型存储简单的数值或布尔值。 包装类(Wrapper Classes): 为了使基本数据类型具备面向对象的特性,Java 提供了对应的包装类,如 Integer、Double、Character、Boolean 等。这些包装类用于将基本数据类型封装为对象,以便进行更多的操作。 自动装箱和拆箱就是 Java 编译器自动处理基本数据类型与包装类之间的转换,使程序员无需手动编写繁琐的代码。 自动装箱(Autoboxing) 自动装箱是指将基本数据类型自动转换为相应的包装类对象。这意味着,你可以将一个 int 类型的值直接赋值给 Integer 类型的变量,而无需显式创建 Integer 对象。 int primitiveInt = 42; Integer wrappedInt = primitiveInt; // 自动装箱 在上述代码中,primitiveInt 是一个基本数据类型的变量,而 wrappedInt 是一个 Integer 类型的变量。通过自动装箱,primitiveInt 的值被自动封装为 Integer 对象。 自动拆箱(Unboxing) 自动拆箱是指将包装类对象自动转换为相应的基本数据类型。这意味着,你可以直接将一个 Integer 对象赋值给 int 类型的变量,而无需显式调用 .intValue() 方法。 Integer wrappedInt = 42; int primitiveInt = wrappedInt; // 自动拆箱 在上述代码中,wrappedInt 是一个 Integer 类型的对象,通过自动拆箱,它的值被自动提取为一个基本数据类型的 int。 常见包装类的使用 当谈到Java的自动装箱和拆箱时,理解每个包装类是非常重要的,因为它们与基本数据类型之间的转换密切相关。在这一部分,我们将详细介绍Java的主要包装类以及它们的作用。 Integer 包装类 java.lang.Integer 是表示整数的包装类,它封装了基本数据类型 int。Integer 类提供了许多方法来处理整数,例如将字符串解析为整数、将整数转换为字符串等。 常用方法和示例 parseInt(String s):将字符串转换为整数。 String str = "42"; int num = Integer.parseInt(str); // num 现在包含整数 42 toString():将整数转换为字符串。 Integer num = 42; String str = num.toString(); // str 现在包含字符串 "42" Double 包装类 java.lang.Double 是表示双精度浮点数的包装类,它封装了基本数据类型 double。Double 类提供了许多方法来处理浮点数,例如将字符串解析为双精度浮点数、将双精度浮点数转换为字符串等。 常用方法和示例 parseDouble(String s):将字符串转换为双精度浮点数。 String str = "3.14"; double num = Double.parseDouble(str); // num 现在包含双精度浮点数 3.14 toString():将双精度浮点数转换为字符串。 Double num = 3.14; String str = num.toString(); // str 现在包含字符串 "3.14" Character 包装类 java.lang.Character 是表示字符的包装类,它封装了基本数据类型 char。Character 类提供了一些方法来处理字符,例如检查字符的类型、转换字符为大写或小写等。 常用方法和示例 isDigit(char ch):检查字符是否是数字。 char ch = '5'; boolean isDigit = Character.isDigit(ch); // isDigit 现在为 true toUpperCase(char ch):将字符转换为大写。 char ch = 'a'; char upper = Character.toUpperCase(ch); // upper 现在为 'A' Boolean 包装类 java.lang.Boolean 是表示布尔值的包装类,它封装了基本数据类型 boolean。Boolean 类提供了一些方法来处理布尔值,例如解析字符串为布尔值、取反等。 常用方法和示例 parseBoolean(String s):将字符串解析为布尔值。 String str = "true"; boolean bool = Boolean.parseBoolean(str); // bool 现在为 true valueOf(boolean b):将布尔值转换为 Boolean 对象。 boolean bool = true; Boolean boolObj = Boolean.valueOf(bool); // boolObj 包含布尔值 true Autoboxing 和 Unboxing 示例 下面是一些自动装箱和拆箱的示例,展示了如何在基本数据类型和包装类之间转换,这些示例演示了如何使用自动装箱和拆箱来进行基本数据类型与包装类之间的转换,使代码更加简洁和易读。: 自动装箱示例 int primitiveInt = 42; Integer wrappedInt = primitiveInt; // 自动装箱 double primitiveDouble = 3.14; Double wrappedDouble = primitiveDouble; // 自动装箱 char primitiveChar = 'A'; Character wrappedChar = primitiveChar; // 自动装箱 自动拆箱示例 Integer wrappedInt = 42; int primitiveInt = wrappedInt; // 自动拆箱 Double wrappedDouble = 3.14; double primitiveDouble = wrappedDouble; // 自动拆箱 Character wrappedChar = 'A'; char primitiveChar = wrappedChar; // 自动拆箱 自动装箱和拆箱的好处 自动装箱和拆箱带来了许多好处,让 Java 编程变得更加方便和直观: 提高可读性: 自动装箱和拆箱使得代码更加清晰和简洁,不需要频繁地进行类型转换。 减少错误: 自动装箱和拆箱减少了因类型转换错误而引发的 bug,因为编译器可以在编译时进行类型检查。 更容易使用集合类: 自动装箱和拆箱使得将基本数据类型放入集合类(如 ArrayList<Integer>)变得更加容易,而无需手动转换。 提高性能: Java 的新版本中对自动装箱和拆箱进行了性能优化,使得它们的性能更好。 自动装箱和拆箱的注意事项 虽然自动装箱和拆箱非常方便,但在使用时仍需注意一些细节: 性能考虑: 尽管 Java 的性能优化有所改进,但在高性能要求的场景中,频繁的自动装箱和拆箱操作可能会导致性能下降。在这种情况下,建议手动管理类型转换。 空指针异常: 自动拆箱可能会引发 NullPointerException,因为包装类对象可能为 null。在拆箱之前,最好进行空值检查。 Integer wrappedInt = null; int primitiveInt = wrappedInt; // 抛出 NullPointerException 不同包装类之间的比较: 尽管两个包装类对象的值相同,但它们可能不会被视为相等,因为它们是不同的对象。要进行值比较,应使用 .equals() 方法。 Integer a = new Integer(42); Integer b = new Integer(42); boolean isEqual = a.equals(b); // true 实际应用 自动装箱和拆箱在实际应用中非常常见。以下是一些常见的用例: 集合类操作: 将基本数据类型添加到集合类中,如 ArrayList<Integer>。 泛型编程: 在泛型类或方法中使用基本数据类型和包装类。 方法参数传递: 方法可以接受包装类或基本数据类型参数,使得方法更加灵活。 数据持久化: 将数据保存到数据库或文件时,常常需要将基本数据类型转换为包装类。 总结 自动装箱和拆箱是 Java 语言中一个重要的特性,它们让基本数据类型与包装类之间的转换更加便捷,提高了代码的可读性和可维护性。通过自动装箱和拆箱,Java 程序员可以更加专注于解决业务逻辑,而不必过多关注数据类型转换的细节。然而,在使用自动装箱和拆箱时,仍需谨慎考虑性能和空指针异常等方面的问题。 了解和熟练使用自动装箱和拆箱是 Java 编程的重要一环。它们可以使你的代码更加简洁和易读,同时避免了很多类型转换的烦恼。但在性能敏感的场景中,仍需慎重选择是否使用自动装箱和拆箱,以确保程序的高效运行。 希望通过本篇博客,你对 Java 自动装箱和拆箱有了更深入的理解,并能够在实际编程中灵活运用这一特性。 ———————————————— 原文链接:https://blog.csdn.net/qq_21484461/article/details/132724519
-
一、什么是 Java 包装类? Java包装类(Wrapper Class)是一种将基本数据类型封装成对象的类。在Java中,每种基本数据类型都有对应的包装类。 常见的基本数据类型和其对应的包装类如下所示: 基本数据类型 包装类 boolean java.lang.Boolean byte java.lang.Byte short java.lang.Short int java.lang.Integer long java.lang.Long float java.lang.Float double java.lang.Double char java.lang.Character 使用Java包装类,我们可以将基本数据类型转换为对象,并使用这些对象调用它们的方法。例如,可以将int类型的变量转换为Integer类型的对象,然后使用该对象调用intValue()方法获取原始的int值。 除了基本数据类型和其对应的包装类之间的转换之外,Java包装类还提供了许多其他实用功能,例如字符串转换、格式化输出、比较大小等。此外,包装类也可以与Java集合框架一起使用,使得我们能够将基本数据类型的值存储在集合中。 二、什么是自动拆箱? Java自动拆箱(Auto Unboxing)是指将包装类型(如Integer、Double等)转换为对应的基本数据类型(如int、double等)的过程,这是Java 1.5之后提供的新特性。 在Java 1.4及以前的版本中,我们必须手动调用包装类型的intValue()、doubleValue()等方法才能将其转换为基本数据类型,如下所示: Integer i = new Integer(10); // 定义一个Integer对象 int j = i.intValue(); // 调用intValue()方法将i转换为int 而在Java 1.5及以后的版本中,我们可以直接将包装类型赋值给基本数据类型变量,Java编译器会自动将包装类型转换为对应的基本数据类型,如下所示: Integer i = new Integer(10); int j = i; // 自动拆箱,将i转换为int类型 可以看到,在上面的代码中,我们省略了调用intValue()方法的步骤,直接将Integer对象赋值给了int变量。此时,Java编译器会自动将Integer对象转换为int类型,这个过程叫做自动拆箱。 需要注意的是,自动拆箱有时也可能会出现NullPointerException异常,例如以下代码: Integer i = null; int j = i; // 抛出NullPointerException异常 在这种情况下,由于i为null,无法自动拆箱为int类型,因此会抛出NullPointerException异常。 三、什么是自动装箱? Java自动装箱(Autoboxing)是指Java编译器在需要的时候,会自动将原始数据类型转换为对应的包装类类型。这种特性可以使得我们在使用包装类对象时更加方便和简洁。 例如,我们可以将一个int类型的值赋给Integer类型的变量,编译器会自动将int类型的值“装箱”成Integer类型的对象: int i = 1; Integer j = i; // 自动装箱:将int类型的i转换为对应的Integer类型 同样地,当我们需要将一个Integer对象转换为int类型的值时,编译器也会自动将Integer对象“拆箱”成int类型的值: Integer i = new Integer(1); int j = i; // 自动拆箱:将Integer对象i转换为对应的int类型 在Java 5之前,我们需要手动进行装箱和拆箱操作,例如: int i = 1; Integer j = new Integer(i); // 手动装箱 int k = j.intValue(); // 手动拆箱 由于自动装箱和拆箱是Java编译器在编译时自动完成的,因此在运行时会稍微比手动装箱和拆箱多花费一些时间和空间。但在大多数情况下,这种开销都非常小,不会对程序性能造成显著影响。 四、为什么要进行自动拆箱和装箱? Java进行自动拆箱和装箱主要是为了方便编程以及提升代码的可读性。 具体来说,自动拆箱使得我们在需要使用基本数据类型时可以直接使用对应的包装类类型,而无需手动进行转换。例如: Integer a = 10; // 自动装箱 int b = a; // 自动拆箱 上述代码中,将整型值10赋值给一个Integer类型的变量a时,发生了自动装箱;而在之后将a赋值给一个int类型的变量b时,发生了自动拆箱。 自动拆箱和装箱使代码更加简洁,也更容易阅读和理解。同时,在某些情况下,如泛型相关的操作中,自动拆箱和装箱也是必须的。 虽然自动拆箱和装箱增加了一定的开销,但在大多数情况下并不会对程序性能造成较大影响。 ———————————————— 原文链接:https://blog.csdn.net/2301_77899321/article/details/131026407
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签