跟着以上的java常用基础知识(一)继续来更新。

11、理解 Java 的字符串,String、StringBuffer、StringBuilder 有什么区别?

String 是 Java 语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是典型的 Immutable 类,被声明成为 final class,所有属性也都是 final 的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的 String 对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。
StringBuffer 是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,我们可以用 append 或者 add 方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer 本质是一个线程安全的可修改字符序列,它的线程安全是通过把各种修改数据的方法都加上 synchronized 关键字实现的,非常直白。它保证了线程安全,也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是 StringBuilder。
StringBuilder 是 Java 1.5 中新增的,在能力上和 StringBuffer 没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选。

12、【String】/【StringBuffer】/【StringBuilder】理解心得:

1 String

(1) String的创建机理
由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池。其运行机制是:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接从池中刚查找到的对象引用;如果没有则新建字符串对象,返回对象引用,并且将新创建的对象放入池中。但是,通过new方法创建的String对象是不检查字符串池的,而是直接在堆区或栈区创建一个新的对象,也不会把对象放入池中。上述原则只适用于通过直接量给String对象引用赋值的情况。

举例:String str1 = “123”; //通过直接量赋值方式,放入字符串常量池
String str2 = new String(“123”);//通过new方式赋值方式,不放入字符串常量池

注意:String提供了inter()方法。调用该方法时,如果常量池中包括了一个等于此String对象的字符串(由equals方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并且返回此池中对象的引用。

(2) String的特性
[A] 不可变。是指String对象一旦生成,则不能再对它进行改变。不可变的主要作用在于当一个对象需要被多线程共享,并且访问频繁时,可以省略同步和锁等待的时间,从而大幅度提高系统性能。不可变模式是一个可以提高多线程程序的性能,降低多线程程序复杂度的设计模式。

[B] 针对常量池的优化。当2个String对象拥有相同的值时,他们只引用常量池中的同一个拷贝。当同一个字符串反复出现时,这个技术可以大幅度节省内存空间。

2 StringBuffer/StringBuilder

StringBuffer和StringBuilder都实现了AbstractStringBuilder抽象类,拥有几乎一致对外提供的调用接口;其底层在内存中的存储方式与String相同,都是以一个有序的字符序列(char类型的数组)进行存储,不同点是StringBuffer/StringBuilder对象的值是可以改变的,并且值改变以后,对象引用不会发生改变;两者对象在构造过程中,首先按照默认大小申请一个字符数组,由于会不断加入新数据,当超过默认大小后,会创建一个更大的数组,并将原先的数组内容复制过来,再丢弃旧的数组。因此,对于较大对象的扩容会涉及大量的内存复制操作,如果能够预先评估大小,可提升性能。

唯一需要注意的是:StringBuffer是线程安全的,但是StringBuilder是线程不安全的。可参看Java标准类库的源代码,StringBuffer类中方法定义前面都会有synchronize关键字。为此,StringBuffer的性能要远低于StringBuilder。

13、谈谈 Java 反射机制,动态代理是基于什么原理?

反射机制是 Java 语言提供的一种基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。
动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装 RPC 调用、面向切面的编程(AOP)。
实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了上面提到的反射机制。

14、一个简单JDK Proxy动态代理Demo



public



public



最后是动态代理的调用测试:



public



15、【JDK Proxy 】和【 cglib 】两种动态代理的实现方式,我们在开发中怎样选择呢?简单对比下两种方式各自优势。

JDK Proxy 的优势:
最小化依赖关系,减少依赖意味着简化开发和维护,JDK 本身的支持,可能比 cglib 更加可靠。
平滑进行 JDK 版本升级,而字节码类库通常需要进行更新以保证在新版 Java 上能够使用。
代码实现简单。

基于类似 cglib 框架的优势:
有的时候调用目标可能不便实现额外接口,从某种角度看,限定调用者实现接口是有些侵入性的实践,类似 cglib 动态代理就没有这种限制。
只操作我们关心的类,而不必为其他相关类增加工作量。
高性能。

16、动态代理使用场景:




java中string是什么 java中string的作用_字符串


17、 关于反射:

反射最大的作用之一就在于我们可以不在编译时知道某个对象的类型,而在运行时通过提供完整的”包名+类名.class”得到。注意:不是在编译时,而是在运行时。

功能:

•在运行时能判断任意一个对象所属的类。
•在运行时能构造任意一个类的对象。
•在运行时判断任意一个类所具有的成员变量和方法。
•在运行时调用任意一个对象的方法。
说大白话就是,利用Java反射机制我们可以加载一个运行时才得知名称的class,获悉其构造方法,并生成其对象实体,能对其fields设值并唤起其methods。

应用场景:

反射技术常用在各类通用框架开发中。因为为了保证框架的通用性,需要根据配置文件加载不同的对象或类,并调用不同的方法,这个时候就会用到反射——运行时动态加载需要加载的对象。

特点:

由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

18、动态代理:

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在两者之间起到中介的作用(可类比房屋中介,房东委托中介销售房屋、签订合同等)。
所谓动态代理,就是实现阶段不用关心代理谁,而是在运行阶段才指定代理哪个一个对象(不确定性)。如果是自己写代理类的方式就是静态代理(确定性)。

组成要素:

(动态)代理模式主要涉及三个要素:
其一:抽象类接口
其二:被代理类(具体实现抽象接口的类)
其三:动态代理类:实际调用被代理类的方法和属性的类

实现方式:

实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了反射机制。还有其他的实现方式,比如利用字节码操作机制,类似 ASM、CGLIB(基于 ASM)、Javassist 等。
举例,常可采用的JDK提供的动态代理接口InvocationHandler来实现动态代理类。其中invoke方法是该接口定义必须实现的,它完成对真实方法的调用。通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。此外,我们常可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。

19、int 和 Integer 有什么区别?谈谈 Integer 的值缓存范围?

int 是我们常说的整形数字,是 Java 的 8 个原始数据类型(Primitive Types,boolean、byte 、short、char、int、float、double、long)之一。Java 语言虽然号称一切都是对象,但原始数据类型是例外,其并不是对象(对象都是引用类型)。
Integer 是 int 对应的包装类,它有一个 int 类型的字段存储数据,并且提供了基本操作,比如数学运算、int 和字符串之间转换等。在 Java 5 中,引入了自动装箱和自动拆箱功能(boxing/unboxing),Java 可以根据上下文,自动进行转换,极大地简化了相关编程。
关于 Integer 的值缓存,这涉及 Java 5 中另一个改进。构建 Integer 对象的传统方式是直接调用构造器,直接 new 一个对象。但是根据实践,我们发现大部分数据操作都是集中在有限的、较小的数值范围,因而,在 Java 5 中新增了静态工厂方法 valueOf,在调用它的时候会利用一个缓存机制,带来了明显的性能改进。按照 Javadoc,这个值默认缓存是 -128 到 127 之间。

20、理解自动装箱、拆箱

自动装箱实际上算是一种语法糖。什么是语法糖?可以简单理解为 Java 平台为我们自动进行了一些转换,保证不同的写法在运行时等价,它们发生在编译阶段,也就是生成的字节码是一致的。
原则上,建议避免无意中的装箱、拆箱行为,尤其是在性能敏感的场合,创建 10 万个 Java 对象要比 10 万个原始数据类型的开销大很多,不管是内存使用还是处理速度,光是对象头的空间占用就已经是数量级的差距了。