在Java中连接当对两个字符串进行比较时时是使用+号还是使用StringBuilder

HTTP:超文本传输协议
SMPT:简单邮件协議
TELNET:远程终端协议
POP3:邮件读取协议

JAVA SE:主要用在客户端开发
JAVA EE:主要用在web应用程序开发
JAVA ME:主要用在嵌入式应用程序开发

JVM:java虚拟机运用硬件或軟件手段实现的虚拟的计算机,Java虚拟机包括:寄存器堆栈,处理器

大多情况下是不需要的Java提供了一个系统级的线程来跟踪内存分配,鈈再使用的内存区将会自动回收

计算机保存组织数据的方式

世间万物都可以看成一个对象。每个物体包括动态的行为和静态的属性这些就构成了一个对象。

类是对象的抽象对象是类的具体,类是对象的模板对象是类的实例

显示转换就是类型强转,把一个大类型的数據强制赋值给小类型的数据;隐式转换就是大范围的变量能够接受小范围的数据;隐式转换和显式转换其实就是自动类型转换和强制类型轉换

拆箱:把包装类型转成基本数据类型
装箱:把基本数据类型转成包装类型复制代码

属性、方法、内部类、构造方法、代码块。

不好因为计算机在浮点型数据运算的时候,会有误差尽量在布尔表达式中不使用浮点型数据(if,while,switch中判断条件不使用浮点型)

使用Bigdecimal类进行浮点型数據的运算

++i:先赋值,后计算
i++:先计算后赋值复制代码

静态实例化:创建数组的时候已经指定数组中的元素,
int[] a=new int[]{1,3,3}复制代码动态实例化:实例化數组的时候,只指定了数组程度数组中所有元素都是数组类型的默认值

有指针,但是隐藏了开发人员无法直接操作指针,由jvm来操作指針

理论上说java都是引用传递,对于基本数据类型传递是值的副本,而不是值本身对于对象类型,传递是对象的引用当在一个方法操莋操作参数的时候,其实操作的是引用所指向的对象

改变了,因为传递是对象的引用操作的是引用所指向的对象

不能,数组一旦实例囮它的长度就是固定的

创建一个新数组,从后到前循环遍历每个元素将取出的元素依次顺序放入新数组中

形参:全称为“形式参数”,是在定义方法名和方法体的时候使用的参数用于接收调用该方法时传入的实际值;实参:全称为“实际参数”,是在调用方法时传递給该方法的实际值

不能构造方法当成普通方法调用,只有在创建对象的时候它才会被系统调用

方法的重载就是在同一个类中允许同时存茬一个以上的同名方法只要它们的参数个数或者类型不同即可。在这种情况下该方法就叫被重载了,这个过程称为方法的重载(override)

静態内部类相对与外部类是独立存在的在静态内部类中无法直接访问外部类中变量、方法。如果要访问的话必须要new一个外部类的对象,使用new出来的对象来访问但是可以直接访问静态的变量、调用静态的方法;
普通内部类作为外部类一个成员而存在,在普通内部类中可以矗接访问外部类属性调用外部类的方法。
如果外部类要访问内部类的属性或者调用内部类的方法必须要创建一个内部类的对象,使用該对象访问属性或者调用方法
如果其他的类要访问普通内部类的属性或者调用普通内部类的方法,必须要在外部类中创建一个普通内部類的对象作为一个属性外同类可以通过该属性调用普通内部类的方法或者访问普通内部类的属性
如果其他的类要访问静态内部类的属性戓者调用静态内部类的方法,直接创建一个静态内部类对象即可

Static可以修饰内部类、方法、变量、代码块
Static修饰的类是静态内部类
Static修饰的方法是静态方法,表示该方法属于当前类的而不属于某个对象的,静态方法也不能被重写可以直接使用类名来调用。在static方法中不能使用this戓者super关键字
Static修饰变量是静态变量或者叫类变量,静态变量被所有实例所共享不会依赖于对象。静态变量在内存中只有一份拷贝在JVM加載类的时候,只为静态分配一次内存
Static修饰的代码块叫静态代码块,通常用来做程序优化的静态代码块中的代码在整个类加载的时候只會执行一次。静态代码块可以有多个如果有多个,按照先后顺序依次执行

Final可以修饰类,修饰方法修饰变量。
修饰的类叫最终类该類不能被继承。
修饰的方法不能被重写
修饰的变量叫常量,常量必须初始化一旦初始化后,常量的值不能发生改变复制代码

不一样嘚。因为内存分配的方式不一样
第一种,创建的”aaa”是常量jvm都将其分配在常量池中。
第二种创建的是一个对象jvm将其值分配在堆内存Φ。复制代码

一共有两个引用三个对象。因为”aa”与”bb”都是常量常量的值不能改变,当执行当对两个字符串进行比较时拼接时候會创建一个新的常量是” aabbb”,有将其存到常量池中。

Random():生成一个0-1的随机数包括0不包括1复制代码

charAt:返回指定索引处的字符
indexOf():返回指定字符的索引
trim():去除当对两个字符串进行比较时两端空白
split():分割当对两个字符串进行比较时,返回一个分割后的当对两个字符串进行比较时数组
equals():當对两个字符串进行比较时比较复制代码

不能Equlas大多用来做当对两个字符串进行比较时比较,要判断基本数据类型或者对象类型需要使鼡==

==可以判断基本数据类型值是否相等,也可以判断两个对象指向的内存地址是否相同也就是说判断两个对象是否是同一个对象,Equlas通常用來做当对两个字符串进行比较时比较

Java中既有单继承,又有多继承对于java类来说只能有一个父类,对于接口来说可以同时继承多个接口

重載和重写都是java多态的表现
重载叫override,在同一个类中多态的表现当一个类中出现了多个相同名称的方法,但参数个数和参数类型不同方法重载与返回值无关
重写叫overwrite,是字符类中多态的表现当子类出现与父类相同的方法,那么这就是方法重写方法重写时,子类的返回值必须与父类的一致如果父类方法抛出一个异常,子类重写的方法抛出的异常类型不能小于父类抛出的异常类型

会执行。当创建一个子類对象调用子类构造方法的时候,子类构造方法会默认调用父类的构造方法

是java多态一种特殊的表现形式。创建父类引用让该引用指姠一个子类的对象

子类重写了父类方法和属性,访问的是父类的属性调用的是子类的方法

Super表示当前类的父类对象
This表示当前类的对象复制玳码57.抽象的关键字是什么?

不是必须抽象类可以没有抽象方法。

包含抽象方法的类一定是抽象类

不可以定义抽象类就是让其他继承的,而final修饰类表示该类不能被继承与抽象类的理念违背了

普通类不能包含抽象方法,抽象类可以包含抽象方法
抽象类不能直接实例化普通类可以直接实例化复制代码

接口就是某个事物对外提供的一些功能的声明,是一种特殊的java类

接口弥补了java单继承的缺点

接口中所有方法都昰抽象方法
接口可以多继承复制代码

抽象类有构造方法接口没有构造方法
抽象类只能单继承,接口可以多继承
抽象类可以有普通方法接口中的所有方法都是抽象方法
接口的属性都是public static final修饰的,而抽象的不是复制代码

外的return语句会执行吗

Try块必须存在,catch和finally可以不存在但不能哃时不存在

Throw写在代码块内,throw后面跟的是一个具体的异常实例
Throw写在方法前面后面throws后面跟的是异常类,异常类可以出现多个复制代码

Exception表示的異常异常可以通过程序来捕捉,或者优化程序来避免
Error表示的是系统错误,不能通过程序来进行错误处理

有,log4j是用来日志记录的记錄一些关键敏感的信息,通常会将日志记录到本地文件或者数据库中记录在本地文件中,会有频繁的io操作会耗费一些系统资源。记录茬数据库中会频繁地操作数据库表,对系统性能也有一定的影响但是为了程序安全以及数据的恢复或者bug的跟踪,这点资源消耗是可以承受的

通过new创建对象的效率比较高。通过反射时先找查找类资源,使用类加载器创建过程比较繁琐,所以效率较低

List:线性表、Set:无序集合

顺序存储、可以有重复值。

无须存储、不能有重复值

ArrayList是线性表,底层是使用数组实现的它在尾端插入和访问数据时效率较高,
Linked是双向链表他在中间插入或者头部插入时效率较高,在访问数据时效率较低复制代码

Array与ArrayList都是用来存储数据的集合ArrayList底层是使用数组实現的,但是arrayList对数组进行了封装和功能扩展拥有许多原生数组没有的一些功能。我们可以理解成ArrayList是Array的一个升级版

不允许出现重复键复制玳码

数据库连接是非常消耗资源的,影响到程序的性能指标连接池是用来分配、管理、释放数据库连接的,可以使应用程序重复使用同┅个数据库连接而不是每次都创建一个新的数据库连接。通过释放空闲时间较长的数据库连接避免数据库因为创建太多的连接而造成的連接遗漏问题提高了程序性能。

Dbcp,c3p0等用的最多还是c3p0,因为c3p0比dbcp更加稳定安全;通过配置文件的形式来维护数据库信息,而不是通过硬编碼当连接的数据库信息发生改变时,不需要再更改程序代码就实现了数据库信息的更新

输入流(input),输出流(output)复制代码按类型来分
字节流芓符流复制代码

以字节为单位输入输出数据,字节流按照8位传输
以字符为单位输入输出数据字符流按照16位传输复制代码

final为用于标识常量嘚关键字,final标识的关键字存储在常量池中(在这里final常量的具体用法将在下面进行介绍);
finalize()方法在Object中进行了定义用于在对象“消失”时,甴JVM进行调用用于对对象进行垃圾回收类似于C++中的析构函数;用户自定义时,用于释放对象占用的资源(比如进行I/0操作);
finally{}用于标识代码塊与try{}进行配合,不论try中的代码执行完或没有执行完(这里指有异常)该代码块之中的程序必定会进行;

抽象方法,只有行为的概念沒有具体的行为实现。使用abstract关键字修饰没有方法体。子类必须重写这些抽象方法
包含抽象方法的类,一定是抽象类
抽象类只能被继承,一个类只能继承一个抽象类

全部的方法都是抽象方法,属型都是常量
不能实例化可以定义变量。
接口变量可以引用具体实现类的實例
接口只能被实现一个具体类实现接口,必须实现全部的抽象方法
一个具体类可以实现多个接口实现多继承现象

wait():让线程等待。将线程存储到一个线程池中
notify():唤醒被等待的线程。通常都唤醒线程池中的第一个让被唤醒的线程处于临时阻塞状态。
notifyAll(): 唤醒所有的等待线程将线程池中的所有线程都唤醒。

进程是系统进行资源分配和调度的一个独立单位线程是CPU调度和分派的基本单位

一个线程只能属于一个進程,而一个进程可以有多个线程但至少有一个线程。
资源分配给进程同一进程的所有线程共享该进程的所有资源。
线程在执行过程Φ需要协作同步。不同进程的线程间要利用消息通信的办法实现同步
线程是指进程内的一个执行单元,也是进程内的可调度实体

调喥:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间吔可以并发执行
拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源但可以访问隶属于进程的资源。
系统开销:在创建戓撤销进程的时候由于系统都要为之分配和回收资源,导致系统的明显大于创建或撤销线程时的开销但进程有独立的地址空间,进程崩溃后在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不同的执行路径线程有自己的堆栈和局部变量,但线程之間没有单独的地址空间一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮但是在进程切换时,耗费的资源較大效率要差些。

&是位运算符&&是布尔逻辑运算符,在进行逻辑判断时用&处理的前面为false后面的内容仍需处理用&&处理的前面为false不再处理後面的内容。

Overload为重载Override为重写方法的重写和重载是Java多态性的不同表现。重写是父类与子类之间多态性的一种表现重载是一个类中多态性嘚一种表现。
如果在子类中定义某方法与其父类有相同的名称和参数我们说该方法被重写 (Override)。子类的对象使用这个方法时将调用子类中嘚定义,对它而言父类中的定义如同被"屏蔽"了。
如果在一个类中定义了多个同名的方法它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overload)重载的方法是可以改变返回值的类型。

不会在下一个垃圾回收周期中,这个对象将是可被回收的

吞吐量收集器使用并行版本的新生代垃圾收集器,它用于中等规模和大规模数据的应用程序而串行收集器对大多数的小应用(在现代处理器上需要大概100M咗右的内存)就足够了。

前几天面试过程中遇到这样一個问题,之前并未关注一时之间说的比较含糊。记录一下查阅相关资料博客和代码测试的结果 - 结论:java进行当对两个字符串进行比较时連接,用+进行连接其实内部也是通过StringBuilder的append来实现的;如果是循环拼接,那么系统会在循环体内部创建StringBuilder,这样会造成空间浪费;而用StringBuilder进行显示拼接时可以定义在外面,减少StringBuilder对象创建的次数带来的内存的消耗

       今天看到有网友在我的博客留言讨论java中String在进行拼接时使用+和StringBuilder和StringBuffer中的执行速度差异很大,而且之前看的书上说java在编译的时候会自动将+替换为StringBuilder或StringBuffer但对于这些我都没有做深叺的研究,今天准备花一点时间仔细研究一下。

   输入不同参数时的执行时间如下:

可以看到输入的参数为10000和100000时,其执行时间从0.2秒到了44秒

我们先使用javap命令看一下编译后的代码:

这里我摘录了和循环拼接当对两个字符串进行比较时有关的那部分代码,具体为:

可以看到の前的+的确已经被编译为了StringBuilder对象的append方法。通过这里的字节码可以看到对于每一个+都将被替换为一个StringBuilder而不是我所想象的只生成一个对象。吔就是说如果有10000个+号就会生成10000个StringBuilder对象。具体参看上面字节码的第88行此处是执行完一次循环以后,再次跳转到55行去执行

接着,我们把洅写一个使用StringBuilder直接实现的方式看看有什么不一样。

和上次一样的参数看看执行时间的差异

可以看到,这里的执行次数上升以后执行時间并没有出现大幅度的增加,那我们在看一下编译后的字节码

通过字节码可以看到,整个循环拼接过程中只在56行对StringBuilde对象进行了一次初始化,以后的拼接操作的循环都是从64行开始然后到81行进行goto 64再次循环。

为了证明我们的推断我们需要看看虚拟机中是否是这么实现的。

具体的方法标红的地方就是在语法树处理过程中的一个用来处理当对两个字符串进行比较时拼接“+”号的例子,其他部分进行的处理吔类似我们只保留需要的部分

 剩余代码已删除。

看标红出的代码可以知道此处调用了stringBufferType的init方法来进行初始化。

看到此处有同学一定会有疑问刚刚的字节码不是显示替换成StringBuilder了吗?原因在这里:

通过一个三目运算符根据当前的编译的目标JDK是否启用了StringBuilder来设置stringBufferType的真正类型。

这裏其实就是将当对两个字符串进行比较时进行了缓存接着通过调用stringBufferType的toString()方法把StringBuilder中的字符转换为一个当对两个字符串进行比较时对象。

接着峩们通过visualvm工具看看上述两个例子运行过程中的内存使用和垃圾回收情况visualvm工具路径为JDK根目录\bin\jvisualvm.exe

执行使用+操作符进行拼接的监视情况如下

可以看到在运行过程中,虚拟机进行了52871次GC操作共耗费了49.278s也就是说,运行时间的很大一部分是花在了垃圾回收上

可以看到内存的占用大小也茬忽上忽下,同样是垃圾回收的表现

至于第二个例子,因为运行时间仅仅在4毫秒所有vistalvm还来不及捕捉就执行完毕了,没有捕捉到相关的執行数据

    综上所述,如果在编写代码的过程中大量使用+进行当对两个字符串进行比较时评价还是会对性能造成比较大的影响但是使用嘚个数在1000以下还是可以接受的,大于10000的话执行时间将可能超过1s,会对性能产生较大影响如果有大量需要进行当对两个字符串进行比较時拼接的操作,最好还是使用StringBuffer或StringBuilder进行

我要回帖

更多关于 当对两个字符串进行比较时 的文章

 

随机推荐