持续精进_java语言2

2018-10-27  本文已影响18人  兮兮码字的地方

1 String字符串

在Java 9之前,字符串是使用 char 数组来存数据的,这样非常直接。(java开始改为byte求组,节省内存开销)

它是典型的 Immutable 类,被声明成为 final class,所有属性也都是 final 的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的 String 对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。

由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池

其运行机制是:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接返回从池中查找到的对象引用;如果没有则新建字符串对象,返回对象引用,并且将新创建的对象放入池中。

但是,通过new方法创建的String对象是不检查字符串池的,而是直接在堆区或栈区创建一个新的对象,也不会把对象放入池中。

举例:

String str1 = "123"; //通过直接量赋值方式,放入字符串常量池

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

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

总结String的特性

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

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

2 StringBuffer/StringBuilder

由于String类的“+”拼接操作会产生新的对象,性能低,所以才有了这两个类。

StringBuffer和StringBuilder都实现了AbstractStringBuilder抽象类,拥有几乎一致对外提供的调用接口;

其底层在内存中的存储方式与String相同,都是以一个有序的字符序列(char类型的数组)进行存储。

不同点是StringBuffer/StringBuilder对象的值是可以改变的,并且值改变以后,对象引用不会发生改变;

两者对象在构造过程中,首先按照默认大小申请一个字符数组,由于会不断加入新数据,当超过默认大小后,会创建一个更大的数组,并将原先的数组内容复制过来再丢弃旧的数组。因此,对于较大对象的扩容会涉及大量的内存复制操作。

StringBuffer是线程安全的,但效率低。

StringBuilder是线程不安全的,但效率高。


3 反射与动态代理原理

编程语言通常有各种不同的分类角度,动态类型和静态类型就是其中一种分类角度,简单区分就是语言类型信息是在运行时检查,还是编译期检查。

与其近似的还有一个对比,就是所谓强类型和弱类型,就是不同类型变量赋值时,是否需要显式地(强制)进行类型转换。

Java 是编译期检查—>静态语言,需要强制类型转换—>强类型语言。

但是因为提供了类似反射等机制,也具备了部分动态类型语言的能力。

1 反射

反射机制是 Java 语言提供的一种基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。

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

功能:

•在运行时能判断任意一个对象所属的类。

•在运行时能构造任意一个类的对象。

•在运行时判断任意一个类所具有的成员变量和方法。

•在运行时调用任意一个对象的方法。

说大白话就是,利用Java反射机制我们可以加载一个运行时才得知名称的class,获悉其构造方法,并生成其对象实体,能对其fields设值并唤起其methods。

应用场景:

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

特点:

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

2 动态代理

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在两者之间起到中介的作用(可类比房屋中介,房东委托中介销售房屋、签订合同等)。

所谓动态代理,就是实现阶段不用关心代理谁,而是在运行阶段才指定代理哪个一个对象(不确定性)。如果是自己写代理类的方式就是静态代理(确定性)。

组成要素:

(动态)代理模式主要涉及三个要素:

其一:抽象类接口

其二:被代理类(具体实现抽象接口的类)

其三:动态代理类:实际调用被代理类的方法和属性的类

实现方式:

实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了反射机制。还有其他的实现方式,比如利用字节码操作机制,类似 ASM、CGLIB(基于 ASM)、Javassist 等。

总结:动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,反射是实现动态代理的方式中的一种。

上一篇下一篇

猜你喜欢

热点阅读