科技资讯

Java基础知识面试题4

发布日期:2023-07-06    点击次数:159

hashCode与equals

1、hashCode介绍

hashCode的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode函数。散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

2、为什么要有hashCode

hashCode是一个用于快速查找对象的整数值,它可以用于哈希表、集合等数据结构中,以提高数据的查找效率。hashCode方法是一种散列码算法,它可以将任意长度的输入数据映射到固定长度的散列码中,从而方便对数据进行比较和查找

例如:当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他已经加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了equals的次数,相应就大大提高了执行速度。

3、两个对象的hashCode相同,则equals也一定为true,对吗?

1、如果两个对象相等,则hashcode一定也是相同的

2、两个对象相等,对两个对象调用equals方法返回true

3、两个对象有相同的hashcode值,它们也不一定是相等的

4、为什么重写equals时必须重写hashCode方法?

如果只重写了equals方法,那么默认情况下,假设存了两个自定义的内容相同的对象到Set中,Set进行去重操作时,会先判断两个对象的hashCode是否相同,此时因为没有重写hashCode方法,所以会直接执行Object中的hashCode方法,而Object中的hashCode方法对比的是两个不同引用地址的对象,那么得到的两个Hash值是不一样的,那么equals方法就不会执行了,这两个对象就会被判断为不是相等的,于是就在Set集合中插入了两个相同的对象(这里的相同是指的内容相同)。

但是,如果在重写equals方法时,也重写了hashCode方法,那么在执行判断时会去执行重写的hashCode方法,此时对比的是两个对象的所有属性的hashCode是否相同,于是调用hashCode返回的结果就是true,再去调用equals方法,发现两个对象确实是相等的,于是就返回true了,因此Set集合就不会存储两个一模一样的数据了,于是整个程序的执行就正常了。

总结

hashCode和equals两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度,如果在重写equals时,不重写hashCode,就会导致在某些场景下,例如将两个相等的自定义对象存储在Set集合时,就会出现程序执行的异常,为了保证程序的正常执行,所以我们就需要在重写equals时,也一并重写hashCode方法才行。

对象的相等与指向他们的引用相等,两者有什么不同?

在Java中,对象的相等与指向它们的引用相等是两个不同的概念,它们有以下几点不同:

1.比较方式不同:对象的相等通常使用equals方法进行比较,而指向它们的引用相等通常使用“==”运算符进行比较。

2.比较结果不同:对象的相等比较的是对象的内容是否相同,而指向它们的引用相等比较的是对象的内存地址是否相同。

3.对象类型不同:对象的相等适用于所有对象类型,包括基本数据类型和对象类型,而指向它们的引用相等只适用于对象类型。

需要注意的是,如果一个类没有重载equals方法,那么它将继承Object类的equals方法,该方法比较的是两个对象的内存地址是否相同,即与指向它们的引用相等的结果相同。

通俗易懂的讲解为什么Java中只有值传递

在Java中,只有值传递,这是因为Java中的变量在传递给方法时,实际上是将变量的值(即数据的拷贝)传递给方法,而不是将变量本身传递给方法。

可以将变量想象成一个盒子,盒子里装着数据。当一个变量作为参数传递给方法时,实际上是将盒子里的数据复制一份,并将这份数据传递给方法。这就好比你把一个盒子里的东西复制一份给朋友,朋友拿到的是复制品,而不是原来的盒子。同理,方法也拿到的是变量的复制品,而不是原来的变量。

需要注意的是,如果变量是引用类型的变量,那么复制的是变量的值(即内存地址),而不是对象本身。这意味着,如果在方法内部修改了对象的数据,那么在方法外部也能看到这些修改,因为它们都是指向同一个对象的。

总之,Java中只有值传递,因为变量在传递给方法时,实际上是将变量的值(即数据的拷贝)传递给方法,而不是将变量本身传递给方法。因此,在Java中不能直接实现引用传递,但是可以通过修改对象的数据来达到类似于引用传递的效果。

骚戴理解:java中只要值传递,你传递的变量如果是引用类型,那也是把这个变量的内存地址复制一份传过去,重点就在于这里是复制!!!虽然我传递的是内存地址,但是我采用的方法是复制这个内存地址再把复制的传过去,效果是和引用传递一样,但是从定义上来看,由于是复制一份内存地址传递,所以就是值传递!

值传递和引用传递有什么区别

值传递和引用传递是两种不同的参数传递方式,它们的区别主要在于传递的是变量的值还是变量的引用(内存地址)。

在值传递中,当一个变量作为参数传递给方法时,实际上是将该变量的值(即数据的拷贝)传递给方法,而不是将变量本身传递给方法。在方法内部对该变量进行修改不会影响到原来的变量,因为它们指向的是不同的内存地址。这就好比你把一个盒子复制一份给朋友,朋友拿到的是复制品,而不是原来的盒子。

在引用传递中,当一个变量作为参数传递给方法时,实际上是将该变量的引用(内存地址)传递给方法,而不是将变量的值传递给方法。在方法内部对该变量进行修改会影响到原来的变量,因为它们指向的是同一个内存地址。这就好比你把一个盒子里的东西给朋友,朋友拿到的是原来的盒子,你和朋友都可以修改盒子里的东西。

JDK中常用的包有哪些

JDK中常用的包有很多,其中一些常用的包如下:

1.java.lang:包含Java语言的核心类,如基本数据类型、字符串、异常处理等。

2.java.util:包含各种实用工具类,如集合框架、日期和时间处理、随机数生成、正则表达式等。

3.java.io:包含输入输出相关的类,如文件读写、网络通信、对象序列化等。

4.java.net:包含网络编程相关的类,如Socket、URL等。

5.java.awt:包含图形用户界面(GUI)相关的类,如窗口、按钮、文本框等。

6.javax.swing:是AWT的扩展,提供了更多的GUI组件、更好的外观和感觉、更好的事件处理等。

7.java.sql:包含与数据库相关的类,如连接数据库、执行SQL语句、处理结果集等。

8.java.math:包含高精度计算相关的类,如BigDecimal、BigInteger等。

9.java.security:包含与安全相关的类,如加密、数字签名、密钥管理等。

10.java.text:包含文本处理相关的类,如格式化和解析日期、数字、货币等。

除了以上这些常用的包之外,JDK中还有很多其他的包,如XML处理、国际化、反射等。开发者在编写Java程序时需要根据具体的需求选择合适的包

IO流

反射

什么是反射机制?

反射是Java语言的一种机制,它允许程序在运行时获取对象的类型信息、访问对象的属性和方法,并调用对象的方法。反射机制使得程序可以在运行时动态地创建对象、调用方法、访问属性等,而不需要在编译时确定这些信息。

在Java中,每个类都有一个Class对象,它包含了该类的所有信息,如类名、属性、方法等。通过反射机制,可以获取一个类的Class对象,然后使用该对象来访问类的属性和方法。反射机制可以让程序在运行时动态地创建对象、调用方法、访问属性等,而不需要在编译时确定这些信息。

反射机制在Java中有很多应用,如动态代理、注解处理、框架开发等。但是,由于反射机制需要在运行时动态地获取对象信息,所以会带来一定的性能损失。因此,在使用反射机制时需要注意性能问题,并合理使用缓存等技术来提高程序的效率。

反射机制优缺点

反射机制是Java语言的一种特性,它允许程序在运行时动态地获取对象的类型信息、访问对象的属性和方法,并调用对象的方法。反射机制的优缺点如下:

优点:

1.动态性:反射机制允许程序在运行时动态地获取对象的类型信息、访问对象的属性和方法,并调用对象的方法,从而使程序具有更大的灵活性和动态性。

2.扩展性:反射机制可以让程序在运行时动态地创建对象、调用方法、访问属性等,而不需要在编译时确定这些信息,从而使程序具有更好的扩展性。

3.适用性:反射机制可以应用于很多场景,如动态代理、注解处理、框架开发等,使程序更加灵活和可扩展。

缺点:

1.性能问题:反射机制需要在运行时动态地获取对象信息,所以会带来一定的性能损失,特别是在频繁调用的情况下,会对程序的性能产生较大的影响。

2.安全问题:反射机制可以访问对象的私有属性和方法,从而可能破坏程序的安全性。

3.可读性问题:反射机制使得程序的逻辑更加复杂,代码可读性较差,特别是对于初学者来说,可能会造成困难。

总之,反射机制是Java语言的一种特性,它具有动态性、扩展性和适用性等优点,但也存在性能、安全和可读性等缺点。在使用反射机制时需要权衡其优缺点,并根据具体情况进行选择。

反射机制的应用场景有哪些?

反射机制在Java中有很多应用场景,包括以下几个方面:

1.动态代理:通过反射机制,可以动态地生成代理对象,从而实现对目标对象的代理操作,如AOP、RPC等。

2.注解处理:通过反射机制,可以读取和处理注解信息,从而实现对程序的自动化处理,如自动化测试、代码生成等。

3.框架开发:通过反射机制,可以实现框架的扩展性和灵活性,如Spring框架中的BeanFactory、AOP、IOC等。Spring通过XML配置模式装载Bean的过程(根据配置文件里的bean定义,通过反射创建一个bean对象)

4.反射调试工具:通过反射机制,可以实现反射调试工具,如获取对象的类名、属性、方法等信息,从而方便程序员进行调试和开发。我们在使用JDBC连接数据库时使用Class.forName通过反射加载数据库的驱动程序;

5.序列化和反序列化:通过反射机制,可以实现对象的序列化和反序列化,从而实现对象的持久化和传输。

6.动态加载类和资源:通过反射机制,可以动态地加载类和资源,从而实现程序的动态扩展和更新。

Java获取反射的三种方法

通过对象实例的getClass方法获取(使用的最少的)

通过Class.forName("路径")实现反射机制(jdbc驱动)

通过类名.class来实现反射机制

publicclassStudent{privateintid;Stringname;protectedbooleansex;publicfloatscore;}publicclassGet{//获取反射机制三种方式publicstaticvoidmain(String[]args)throwsClassNotFoundException{//方式一(通过建立对象)Studentstu=newStudent;Classclassobj1=stu.getClass;System.out.println(classobj1.getName);//方式二(所在通过路径-相对路径)Classclassobj2=Class.forName("fanshe.Student");System.out.println(classobj2.getName);//方式三(通过类名)Classclassobj3=Student.class;System.out.println(classobj3.getName);}}

String

字符型常量和字符串常量的区别

字符型常量和字符串常量是Java中的两种常量类型,它们的区别如下:

1.字符型常量:字符型常量是用单引号括起来的单个字符,如'a'、'b'、'c'等。字符型常量只能包含一个字符,且必须用单引号括起来。

2.字符串常量:字符串常量是用双引号括起来的一串字符,如"Hello"、"World"等。字符串常量可以包含多个字符,且必须用双引号括起来。

3.存储方式:字符型常量在内存中以字符的形式存储,而字符串常量在内存中以字符数组的形式存储。

4.可变性:字符型常量是不可变的,一旦定义,就不能修改。而字符串常量可以通过各种方法进行修改,如拼接、替换、截取等。

5.比较方式:字符型常量可以使用==运算符进行比较,比较的是字符的ASCII码值。而字符串常量不能使用==运算符进行比较,需要使用equals方法或compareTo方法进行比较。

什么是字符串常量池?

字符串常量池是Java中的一种特殊的内存区域,用于存储字符串常量,以便重复使用。当程序创建一个字符串常量时,如果该字符串常量在常量池中已经存在,则直接返回该字符串常量的引用;如果该字符串常量在常量池中不存在,则将该字符串常量添加到常量池中,并返回该字符串常量的引用。

字符串常量池的优点是可以减少内存的使用,提高程序的性能。因为字符串常量池会缓存字符串常量,以便重复使用,所以可以避免创建重复的字符串常量,从而减少内存的使用。同时,由于字符串常量池是一种特殊的内存区域,它的访问速度比堆内存和栈内存更快,所以可以提高程序的性能。

需要注意的是,字符串常量池中的字符串常量是不可变的,一旦定义,就不能修改。如果程序需要修改字符串常量,应该使用StringBuilder或StringBuffer等可变的字符串类型。

jdk1.8的字符串常量池是在堆内存中吗?

在JDK1.8中,字符串常量池的位置是在堆内存中,但是和一般的堆内存不同,它是被划分出来的一块特殊的内存区域,称为"永久代"(PermanentGeneration),也叫"元空间"(Metaspace)。

在JDK1.8之前,字符串常量池是在方法区中的,但是在JDK1.8之后,方法区被移除了,取而代之的是Metaspace。Metaspace是一种与堆内存分离的内存区域,用于存储类的元数据、静态变量、常量等数据。在Metaspace中,字符串常量池也被移动到了堆内存中。

需要注意的是,在JDK1.8中,字符串常量池也有一些变化。在JDK1.8之前,字符串常量池是固定大小的,当常量池中的字符串对象过多时,会导致OutOfMemoryError错误。但是在JDK1.8中,字符串常量池的大小是不固定的,可以动态调整,避免了OutOfMemoryError错误的问题。同时,JDK1.8中也引入了一种新的字符串常量池实现方式,称为"字符串去重"(StringDeduplication),可以进一步减少字符串常量池的内存占用。

String是最基本的数据类型吗?

不是。Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitivetype),剩下的都是引用类型(referencetype),Java5以后引入的枚举类型也算是一种比较特殊的引用类型。

这是很基础的东西,但是很多初学者却容易忽视,Java的8种基本数据类型中不包括String,基本数据类型中用来描述文本数据的是char,但是它只能表示单个字符,比如‘a’,‘好’之类的,如果要描述一段文本,就需要用多个char类型的变量,也就是一个char类型数组,比如“你好”就是长度为2的数组char[]chars={‘你’,‘好’};

但是使用数组过于麻烦,所以就有了String,String底层就是一个char类型的数组,只是使用的时候开发者不需要直接操作底层数组,用更加简便的方式即可完成对字符串的使用。

简单来说就是String类利用了final修饰的char类型数组存储字符,源码如下所示:

privatefinalcharvalue[];

String有哪些特性

String是Java中的一个类,具有以下特性:

1.不可变性:String对象一旦创建,就不能被修改。如果需要修改字符串内容,只能创建一个新的String对象。这种不可变性使得String对象在多线程环境下更加安全。

2.字符串常量池:Java中的字符串常量池是一种特殊的内存区域,用于缓存字符串常量,以便重复使用。String类中的字符串常量都是在字符串常量池中创建的。

3.比较方式:String类中提供了多种比较字符串的方法,如equals、equalsIgnoreCase、compareTo等。其中,equals方法比较的是字符串的内容,而==运算符比较的是字符串对象的引用。

4.不可变哈希值:String类中的哈希值是不可变的,一旦计算出来就不能被修改。这种不可变性使得String对象可以作为Map的key来使用。

5.字符串操作方法:String类中提供了多种字符串操作方法,如substring、trim、toUpperCase、toLowerCase等,可以方便地对字符串进行操作和处理。

6.国际化支持:String类中提供了多种支持国际化的方法,如getBytes、charAt、length等,可以处理不同语言和编码的字符串。

String为什么是不可变的吗?

String是不可变的,主要是为了保证程序的安全性和性能。

1.安全性:如果String是可变的,那么在多线程环境下,多个线程可能会同时修改同一个String对象,从而导致数据不一致的问题。为了避免这种问题,Java将String设计为不可变的,一旦创建,就不能被修改,这样就可以避免多线程环境下的数据竞争问题。

2.性能:如果String是可变的,那么每次修改字符串都需要创建一个新的String对象,这样会导致频繁的对象创建和销毁,从而降低程序的性能。为了避免这种问题,Java将String设计为不可变的,一旦创建,就不需要再修改,这样可以避免频繁的对象创建和销毁,提高程序的性能。

另外,String是不可变的还有一个好处,就是可以作为Map的key来使用。由于String的哈希值是不可变的,一旦计算出来就不能被修改,所以String对象可以作为Map的key来使用,保证了Map的稳定性和正确性。如果String是可变的,就不能作为Map的key来使用,从而限制了Map的使用范围。

综上所述,String是不可变的,主要是为了保证程序的安全性和性能。

是否可以继承String类

String类是final类,不可以被继承。

Stringstr="i"与Stringstr=newString(“i”)一样吗?

在功能上,Stringstr="i"与Stringstr=newString("i")是相同的,都是创建一个包含单个字符i的字符串对象。但是,在内存中,它们是不同的。

Stringstr="i"是使用字符串常量池中的字符串常量创建的,而字符串常量池是Java中的一种特殊的内存区域,用于缓存字符串常量,以便重复使用。当程序创建一个字符串常量时,如果该字符串常量在常量池中已经存在,则直接返回该字符串常量的引用;如果该字符串常量在常量池中不存在,则将该字符串常量添加到常量池中,并返回该字符串常量的引用。因此,使用Stringstr="i"创建的字符串对象会被添加到字符串常量池中,如果创建多个包含相同内容的字符串对象,只会在字符串常量池中创建一个对象,可以节省内存空间。

而Stringstr=newString("i")是使用new关键字创建的字符串对象,每次都会在堆内存中创建一个新的对象,不会使用字符串常量池中的对象。如果创建多个包含相同内容的字符串对象,每个对象都会在堆内存中创建一个新的对象,会占用更多的内存空间。

因此,如果需要创建包含单个字符的字符串对象,建议使用Stringstr="i"的方式,可以避免在堆内存中创建多个相同的对象,节省内存空间。

Strings=newString(“xyz”);创建了几个字符串对象

使用Strings=newString("xyz")创建了两个字符串对象。

第一个字符串对象是字面量"xyz",它是在编译期间就被创建并存储在字符串常量池中的。当程序执行到Strings=newString("xyz")这句话时,会在堆内存中创建一个新的String对象,该对象的内容是字符串常量池中"xyz"字符串对象的拷贝。因此,使用new关键字创建String对象时,会在堆内存中创建一个新的对象。

总之,使用Strings=newString("xyz")创建了两个字符串对象,一个是字符串常量池中的"xyz"字符串对象,另一个是堆内存中的新对象,该对象的内容是字符串常量池中"xyz"字符串对象的拷贝。需要注意的是,如果在代码中多次使用相同的字符串字面量,只会在字符串常量池中创建一个字符串对象,不会重复创建。

Stringstr1="hello";//str1指向静态区(字符串常量池)Stringstr2=newString("hello");//str2指向堆上的对象Stringstr3="hello";Stringstr4=newString("hello");1、System.out.println(str1.equals(str2));//true2、System.out.println(str2.equals(str4));//true3、System.out.println(str1==str3);//true4、System.out.println(str1==str2);//false5、System.out.println(str2==str4);//false6、System.out.println(str2=="hello");//falsestr2=str1;7、System.out.println(str2=="hello");//true

骚戴理解:首先String的equals方法是被重写过的,比较的内容是否相同,所以序号1和2都是true,因为内容都是hello,但是"=="在比较引用类型的时候比较的是内存地址是否相同,因为str1和str3都是指向的字符串常量池里hello这个字符串的地址,所以序号3位true,但是序号4、5、6都是false,因为它们内存地址都不一样,str2=str1把str2指向的地址改成了指向字符串常量池中hello的地址后自然序号7为true

如何将字符串反转?

使用StringBuilder或者stringBuffer的reverse方法。

示例代码:

//StringBufferreverseStringBufferstringBuffer=newStringBuffer;stringBuffer.append("abcdefg");System.out.println(stringBuffer.reverse);

结果:gfedcba

//StringBuilderreverseStringBuilderstringBuilder=newStringBuilder;stringBuilder.append("abcdefg");System.out.println(stringBuilder.reverse);

结果:gfedcba

数组有没有length方法?String有没有length方法

数组没有length方法,但是有一个length属性,可以用来获取数组的长度,或者用size方法。

例如,对于int类型的数组,可以使用以下方式获取数组的长度:

int[]arr={1,2,3,4,5};intlen=arr.length;//获取数组的长度,结果为5

对于String类型的对象,有一个length方法,可以返回字符串的长度,即字符串中字符的个数。

例如,可以使用以下方式获取字符串的长度:

Stringstr="HelloWorld";intlen=str.length;//获取字符串的长度,结果为11

需要注意的是,String的length方法返回的是字符串中字符的个数,而不是字节数或者编码单元数。对于包含Unicode字符的字符串,其长度可能会大于字符串的字节数或编码单元数。

String类的常用方法都有那些?

String类是Java中最常用的类之一,提供了许多实用的方法,下面列出了String类的一些常用方法:

1.charAt(intindex):返回指定索引处的字符。

2.length:返回字符串的长度,即字符串中字符的个数。

3.substring(intbeginIndex):返回从指定索引开始到字符串末尾的子字符串。

4.substring(intbeginIndex,intendIndex):返回从指定索引开始到指定索引结束的子字符串。

5.equals(Objectobj):比较字符串是否相等,区分大小写。

6.equalsIgnoreCase(StringanotherString):比较字符串是否相等,忽略大小写。

7.compareTo(StringanotherString):按字典顺序比较两个字符串,如果相等返回0,如果当前字符串大于另一个字符串返回正数,否则返回负数。

8.toLowerCase:将字符串中的所有字符转换为小写。

9.toUpperCase:将字符串中的所有字符转换为大写。

10.trim:去除字符串开头和结尾的空格。

11.startsWith(Stringprefix):判断字符串是否以指定的前缀开始。

12.endsWith(Stringsuffix):判断字符串是否以指定的后缀结束。

13.indexOf(intch):返回指定字符在字符串中第一次出现的索引。

14.lastIndexOf(intch):返回指定字符在字符串中最后一次出现的索引。

15.replace(charoldChar,charnewChar):将字符串中的所有旧字符替换为新字符。

16.replaceAll(Stringregex,Stringreplacement):将字符串中所有匹配正则表达式的子串替换为指定字符串。

17.split(Stringregex):按照指定的正则表达式将字符串拆分为多个子串。

18.valueOf(Objectobj):将指定的对象转换为字符串。

19.format(Stringformat,Object...args):使用指定的格式字符串和参数返回格式化的字符串。

在使用HashMap的时候,用String做key有什么好处?

在使用HashMap时,使用String作为key有以下好处:

1.String是不可变的,因此可以保证key的不可变性,避免了在修改key时可能出现的问题。

2.String的hashCode方法被重写过,可以保证相同字符串的hashCode值相同,因此可以更好地利用HashMap的散列特性。

3.String实现了Comparable接口,可以进行比较,因此在对HashMap进行排序或者遍历时,可以更方便地进行操作。

4.String是Java中最常用的类之一,使用String作为key可以提高代码的可读性和可维护性。

骚戴理解:需要注意的是,在使用自定义类作为HashMap的key时,需要重写hashCode和equals方法,以保证正确性和性能。

String和StringBuffer、StringBuilder的区别是什么?

String、StringBuffer和StringBuilder都是Java中用于处理字符串的类,它们的主要区别如下:

1.String是不可变的,即一旦创建就不能修改,对String对象进行修改实际上是创建了一个新的String对象,旧的String对象仍然存在。而StringBuffer和StringBuilder是可变的,可以修改其内容。

2.StringBuffer和StringBuilder都是可变的字符串缓冲区,它们的主要区别在于线程安全性。StringBuffer是线程安全的,即多个线程可以同时访问一个StringBuffer对象并执行修改操作,而不会产生不一致的结果。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder则是非线程安全的,如果多个线程同时访问一个StringBuilder对象并执行修改操作,可能会产生不一致的结果。String中的对象是不可变的,也就可以理解为常量,线程安全。

3.在字符串拼接的场景中,如果使用String进行拼接,每次拼接都会创建一个新的String对象,如果拼接的字符串比较多,会产生大量的临时对象,占用大量内存,影响性能。而如果使用StringBuffer或StringBuilder进行拼接,由于它们是可变的,可以直接在原有对象上进行修改,避免了创建大量临时对象,提高了性能。

骚戴理解:性能由好到坏:StringBuilder>StringBuffer>String

总之,String、StringBuffer和StringBuilder都有各自的特点,需要根据具体的场景选择合适的类进行使用。如果需要进行频繁的字符串拼接操作,建议使用StringBuffer或StringBuilder,而不是使用String。如果需要在多线程环境下进行字符串操作,建议使用StringBuffer,而不是使用StringBuilder。

包装类

自动装箱与拆箱

装箱:将基本类型用它们对应的引用类型包装起来;

拆箱:将包装类型转换为基本数据类型;

int和Integer有什么区别

它们的主要区别如下:

1.int是Java的基本数据类型,而Integer是int的包装类,是一个对象。

2.int在内存中占用4个字节,而Integer对象在内存中占用更多的空间。

3.int可以直接进行数值运算,而Integer对象需要通过intValue方法将其转换为int类型后才能进行数值运算。

4.int是值类型,即在传递时传递的是实际的数值,而Integer是引用类型,即在传递时传递的是对象的引用。

5.在使用时,int通常用于基本的数值运算,而Integer通常用于需要将int类型的数据封装成对象的场景,例如在集合类中存储int类型的数据。

总之,int和Integer都有各自的特点和使用场景,需要根据具体的需求进行选择和使用。需要注意的是,在进行数值运算时,尽量使用int,避免使用Integer对象,以提高性能。

Java原始类型和包装类对比

Java为每个原始类型提供了包装类型:

原始类型::booleancharbyteshortintlongfloatdouble

包装类型:BooleanCharacterByteShortIntegerLongFloatDouble

Integera=127与Integerb=127相等吗

相等

总结

int和Integer在进行比较的时候,Integer会进行拆箱,转为int值与int进行比较。

Integer与Integer比较的时候,由于直接赋值的时候会进行自动的装箱,那么这里就需要注意两个问题

一是-128

二是当大于这个范围的时候,直接newInteger来创建Integer对象。

newInteger(1)和Integera=1不同,前者会创建对象,存储在堆中,而后者因为在-128到127的范围内,不会创建新的对象,而是从IntegerCache中获取的。那么Integera=128,大于该范围的话才会直接通过newInteger(128)创建对象,进行装箱。

对于对象引用类型:==比较的是对象的内存地址。对于基本数据类型:==比较的是值。

注意只有newInteger不一样点,不管new的这个数是不是在-128到127这个范围内都会在堆中创建一个新的对象,而不是使用IntegerCache缓存中的值

publicclassa{publicstaticvoidmain(String[]args){Integera=newInteger(3);Integerb=3;//将3自动装箱成Integer类型intc=3;System.out.println(a==b);//false两个引用没有引用同一对象System.out.println(a==c);//truea自动拆箱成int类型再和c比较System.out.println(b==c);//true}}

骚戴理解:Integera=newInteger(3);是创一个对象在堆里,Integerb=3;是直接从IntegerCache缓存中拿(-128到127这个范围内的Integer对象已经在这个IntegerCache缓存中创建好了的),把b的引用指向IntegerCache缓存中的3。所以第一个判断为false。

第二个和第三个都是因为会拆箱,所以就是int之间的值比较,自然是true

packageanomyous;publicclassTest{publicstaticvoidmain(String[]args){Integeri1=newInteger(99);Integeri2=Integer.valueOf(99);//手动装箱Integeri3=99;//自动装箱隐式调用Integer.valueOfSystem.out.println(i1==i2);//falseSystem.out.println(i2==i3);//trueSystem.out.println(i1==i3);//false}}publicstaticvoidmain(String[]args){Integera1=128;Integerb1=128;System.out.println(a1==b1);//falseIntegera2=127;Integerb2=127;System.out.println(a2==b2);//true}

骚戴理解:如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,超过范围a1==b1的结果是false



上一篇:[设计模式]策略模式在Java工程中应用
下一篇:[jsp]为什么出现JSP?