刷题知识点笔记-P3:字符串
1.字符串
1.1字符串定义
字符串:是有零个或多个字符组成的有序序列,是计算机处理的最基本的非数值数据。
S=‘a1a2a3…an’ (n ≥0)
-
字符串的值中每个字符ai(0 ≤i ≤n)可以是字母、数字或其他字符组成的序列,组成线性表的每个元素就是一个单字符,所以是一种特殊的线性表
-
串又称为字符串,是一种特殊的线性表,其特殊性体现在数据元素是一个字符,也就是说串是一种内容受限的线性表。(栈和队列是操作受限的线性表)
-
串是特殊的线性表(连续存储),故其存储结构与线性表的存储结构类似,只不过组成串的结点是单个字符而已。连续存储包括静态定长存储和动态堆分配存储;串值也可用单链表存储,简称为链串。所以实际应用中为了提高空间利用率,可使每个结点存放多个字符(这是顺序串和链串的综合 (折衷) ),称为块链结构。
-
空串是长度为0,内容为空
-
空白串是包含一个或多个空白字符‘ ’(空格键)的字符串。
1.2子字符串
子串定义:串中任意个连续的 字符 组成的子序列
字符串的子串,就是字符串中的某一个连续片段。截取一个字符串长度需要一个起始位置和结束位置
- 含有n个不同字符的字符串的非空子串的个数为C(n + 1, 2) = n * (n + 1) / 2
- 子串(包括空串)为 n * (n + 1) / 2 + 1
- 非空真子子串(不包括空串和跟自己一样的子串)为 n *(n + 1)/ 2 - 1
1.3字符串常量
一个字符常量表示为一个字符或一个转义序列,被一对ASCII单引号关闭。
CharacterLiteral:
' SingleCharacter '
' EscapeSequence '
SingleCharacter:
InputCharacter but not ' or \
而转义序列包括:
EscapeSequence:
\ b (backspace BS, Unicode \u0008)
\ t (horizontal tab HT, Unicode \u0009)
\ n (linefeed LF, Unicode \u000a)
\ f (form feed FF, Unicode \u000c)
\ r (carriage return CR, Unicode \u000d)
\ " (double quote ", Unicode \u0022)
\ ' (single quote ', Unicode \u0027)
\ \ (backslash \, Unicode \u005c)
OctalEscape (octal value, Unicode \u0000 to \u00ff)
...
2.类加载类过程
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:
- 加载(Loading)
- 验证(Verification)
- 准备(Preparation)
- 解析(Resolution)
- 初始化(Initialization)
- 使用(Using)
- 卸载(Unloading)
7个阶段。其中准备、验证、解析3个部分统称为连接(Linking)。如图所示。
加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。以下陈述的内容都已HotSpot为基准。
2.1加载
在加载阶段(可以参考java.lang.ClassLoader的loadClass()方法),虚拟机需要完成以下3件事情:
- 通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;
加载阶段和连接阶段(Linking)的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。
2.2验证
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
验证阶段大致会完成4个阶段的检验动作:
- 文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以魔术0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
- 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了
java.lang.Object
之外。 - 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
- 符号引用验证:确保解析动作能正确执行。
验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone
参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
2.3准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:
public static int value=123;
那变量value在准备阶段过后的初始值为0而不是123.因为这时候尚未开始执行任何java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器()方法之中,所以把value赋值为123的动作将在初始化阶段才会执行。
至于“特殊情况”是指:public static final int value=123,即当类字段的字段属性是ConstantValue时,会在准备阶段初始化为指定的值,所以标注为final后,value的值在准备阶段初始化为123而非0.
2.4解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对
- 类或接口
- 字段
- 类方法
- 接口方法
- 方法类型
- 方法句柄
- 调用点限定符
7类符号引用进行。
2.5初始化
类初始化阶段是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的java程序代码。在准备极端,变量已经付过一次系统要求的初始值,而在初始化阶段,则根据程序猿通过程序制定的主管计划去初始化类变量和其他资源,或者说:初始化阶段是执行类构造器<clinit>()
方法的过程.
<clinit>()
方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块- -
static{}
中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问
3. Super与this
- super()表示调用父类构造函数、this()调用自己的构造函数,而自己的构造函数第一行要使用super()调用父类的构造函数,所以这俩不能在一个构造函数中会出现重复引用的情况
- super()和this()必须在构造函数第一行,所以这一点也表明他俩不能在一个构造函数中
- this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块(里面不能使用非static类型的)。
4.线程
4.1线程状态转换
4.2运行时常量池
- 运行时常量池是每一个类或接口的常量池的运行时表示形式
- 存放编译期生成的各种字面量和符号引用;
- 运行时常量池(Runtime Constant Pool)是方法区的一部分。
4.3字符串常量池
- 字符串常量池:在JVM中,为了减少相同的字符串的重复创建,为了达到节省内存的目的。会单独开辟一块内存,用于保存字符串常量,这个内存区域被叫做字符串常量池.
- JDK1.6时字符串常量池,被存放在方法区中(永久代),而到了JDK1.7,因为永久代垃圾回收频率低;而字符串使用频率比较高,不能及时回收字符串,会导致导致永久代内存不足,就被移动到了堆内存中。
5. 运算符
5.1 a++ 和++a
- a++可以理解为当访问a之后再对a进行加一操作
- a++很好记的,表示先用后+,而++a表示先+后用。
5.2 >> 和 >>>
-
>>
带符号右移,如果该数为正,则高位补0,若为负数,则高位补1; -
>>>
表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。
5的二进制是0101。 -
例如
x=5>>2 (>>带符号右移)
将0101右移2位,为:0001。y=x>>>2 (>>>无符号右移,左边空缺补充为0)
将0001右移2位,补0。结果为:0000。
5.3 & 和 &&
&和&&都是逻辑运算符,都是判断两边同时真则为真,否则为假;
- 但是&&当第一个条件不成之后,后面的条件都不执行了
- 而当第一个条件不成之后,&则还是继续执行,直到整个条件语句执行完为止
6. 异常
- 粉红色的是受检查的异常(checked exceptions),其必须被 try{}catch语句块所捕获(编译时异常需要我们手动的进行捕捉处理,也就是我们用try…catch块进行捕捉处理。),或者在方法签名里通过throws子句声明.受检查的异常必须在编译时被捕捉处理,命名为 Checked Exception 是因为Java编译器要进行检查,Java虚拟机也要进行检查,以确保这个规则得到遵守.
- 绿色的异常是运行时异常(runtime exceptions),需要程序员自己分析代码决定是否捕获和处理,比如 空指针,被0除…
- 而声明为Error的,则属于严重错误,如系统崩溃、虚拟机错误、动态链接失败等,这些错误无法恢复或者不可能捕捉,将导致应用程序中断,Error不需要捕捉。
7.接口
7.1 接口中 方法和成员变量
- 接口中的变量默认是
public static final
的 ,相当于全局常量 - 方法默认是
public abstract
的 - 接口中的属性必然是常量,只能读不能改
- 接口不可以实例化,只有子类重写了接口中的所有方法后,子类才可以实例化,否则子类还是一个抽象类。子类重写方法的访问权限都是public的。
8.基本数据类型 与包装类
9.Queue
9.1LinkedBlockingQueue
- LinkedBlockingQueue是一个可选有界队列,不允许null值
- 基于链接节点的可选限定的blocking queue 。 这个队列排列元素FIFO(先进先出)。队列的头部是队列中最长的元素。 队列的尾部是队列中最短时间的元素。 新元素插入队列的尾部,队列检索操作获取队列头部的元素。 链接队列通常具有比基于阵列的队列更高的吞吐量,但在大多数并发应用程序中的可预测性能较低。
blocking queue说明:不接受null元素;可能是容量有限的;实现被设计为主要用于生产者 - 消费者队列;不支持任何类型的“关闭”或“关闭”操作,表示不再添加项目实现是线程安全的;
9.2PriorityQueue
-
基于优先级堆的无限优先级queue 。 优先级队列的元素根据它们的有序natural ordering ,或由一个Comparator在队列构造的时候提供,这取决于所使用的构造方法。 优先队列不允许null元素。 依靠自然排序的优先级队列也不允许插入不可比较的对象(这样做可能导致ClassCastException )。
-
该队列的头部是相对于指定顺序的最小元素。 如果多个元素被绑定到最小值,那么头就是这些元素之一 - 关系被任意破坏。 队列检索操作poll , remove , peek和element访问在队列的头部的元件。
-
优先级队列是无限制的,但是具有管理用于在队列上存储元素的数组的大小的内部容量 。 它始终至少与队列大小一样大。 当元素被添加到优先级队列中时,其容量会自动增长。 没有规定增长政策的细节。
-
该类及其迭代器实现Collection和Iterator接口的所有可选方法。 方法iterator()中提供的迭代器不能保证以任何特定顺序遍历优先级队列的元素。 如果需要有序遍历,请考虑使用Arrays.sort(pq.toArray()) 。
-
请注意,此实现不同步。 如果任何线程修改队列,多线程不应同时访问PriorityQueue实例。 而是使用线程安全的PriorityBlockingQueue类。
实现注意事项:此实现提供了O(log(n))的时间入队和出队方法( offer , poll , remove()和add ); remove(Object)和contains(Object)方法的线性时间; 和恒定时间检索方法( peek , element和size )。 -
PriorityQueue是一个无界队列,不允许null值,入队和出队的时间复杂度是O(log(n))
9.3、ConcurrentLinkedQueue
基于链接节点的并发deque(deque是双端队列) 。 并发插入,删除和访问操作可以跨多个线程安全执行。 A ConcurrentLinkedDeque是许多线程将共享对公共集合的访问的适当选择。像大多数其他并发集合实现一样,此类不允许使用null元素。
10 try catch finally
10.1执行流程分析1
如果try语句里有return,返回的是try语句块中变量值。
详细执行过程如下:
- 如果有返回值,就把返回值保存到局部变量中;
- 执行jsr指令跳到finally语句里执行;
- 执行完finally语句后,返回之前保存在局部变量表里的值。
如果try,finally语句里均有return,忽略try的return,而使用finally的return
10.2 执行流程分析2
当Java程序执行try块、catch块时遇到了return或throw语句,这两个语句都会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,程序立即执行return或throw语句,方法终止;
- 如果有finally块,系统立即开始执行finally块。只有当finally块执行完成后,系统才会再次跳回来执行try块、catch块里的return或throw语句;
- 如果finally块里也使用了return或throw等语句,finally块会终止方法,系统将不会跳回去执行try块、catch块里的任何代码。