基础知识入门
Java面向对象特性
三种基本特征:继承、封装和多态。
封装:将对象的实现细节隐藏起来,然后通过一些公用方法暴露该对象的功能;继承:子类直接获得父类的属性和方法;多态:子类对象可以直接赋给父类变量,单运行时依然表现出子类的行为特征,这意味着同一个类型的对象在执行同一个方法时,可能表现出多种行为特征。
面向对象分析OOA,面向对象设计OOD,面向对象编程OOP
UML图形:活动图(activity diagram)、类图(class diagram)、通信图(communication diagram)、组件图(component diagram)、复合结构图(composite structure diagram)、部署图(deployment diagram)、交互概观图(interactive overview diagram)、对象图(object diagram)、包图(package diagram)、顺序图(sequence diagram)、状态机图(state machine diagram)、定时图(timing diagram)、用例图(use case diagram)。
用例图:用于描述系统提供的系列功能,每个用例代表系统的一个功能模块。
顺序图:显示具体用例的详细流程,并且显示流程中不同对象之间的调用关系,同时还可以很详细的显示对不同对象的不同调用。顺序图描述了对象之间的交互,重点在于描述消息及其时间顺序。
Java程序的执行必须经过先编译后解释两个步骤,Java编译生成与平台无关的字节码。
Jvm是一个抽象的计算机,具有指令集并使用不同的存储区域,它负责执行指令,还要管理数据,内存和寄存器。
Java基础
开发环境搭建
JDK Java SE Development Kit,即Java标准开发包,提供了编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行时环境(JRE,Java Runtime Environment),以及常用的Java类库等。(JRE包括JVM和JavaSe API子集,JVM是运行Java的核心虚拟机,而运行Java程序还需要其他的类加载器、字节码校验器以及大量的基础类库。JRE除了包含JVM之外,还包含运行Java程序的其他环境支持)。
CLASSPATH:设置类的搜索路径。
JAVA_HOME、path、CLASS_PATH
JVM虚拟机
程序计数器
程序计数器(Program Counter Register)是一块娇小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。字节码解释器是通过改变这个计数器的值来选去下一条需要执行的字节码指令。每条线程都有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,因此这类内存被称为线程私有的内存。
如果线程执行的是一个Java方法,则计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是Native方法,则计数器的值为空(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
Java虚拟机栈
Java虚拟机栈(Java Virtual Machine Stacks)属线程私有,生命周期与线程相同。
虚拟机栈描述的是Java方法执行的内存模型:每个方法执行会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
栈内存,所指的栈就是虚拟机栈或者说是虚拟机栈中的局部变量表部分。局部变量表存放了各种基本数据类型、对象应用(reference类型,根据虚拟机的不同实现,可能是对象起始地址的引用指针,可能是指向一个代表对象的句柄或者与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。
本地方法栈
本地方法栈(Native Method Stacks)为虚拟机使用到的Native方法服务。
Java堆
Java堆(Java Heap)是被所有线程共享的一块内存区域,在虚拟机启动时创建,此区域的唯一目的是存放对象实例,几乎所有的对象实例都在这里分配内存。是垃圾收集器管理的主要区域,因此很多时候也被称作GC堆(Garbage Collected Heap)。
分代收集算法:新生代和老年代。
Java堆可以位于物理上不连续的内存空间,只要内存上是连续的即可。
方法区
方法区(Metho Area)是各个线程共享的内存区域,用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
运行时常量池
直接内存
垃圾回收机制
JRE在后台自动进行内存的分配和回收
垃圾回收算法:
1,引用计数算法
2,根搜索算法
根搜索算法:通过一系列的名为“GC Roots”的对象作为起始点,搜索所走过的路径成为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。
Java语言中,可作为GC Roots的对象包括:
1,虚拟机栈(栈帧中的本地变量表)中引用的对象。
2,方法区中的类静态属性引用的对象。
3,方法区中常量引用的对象。
4,本地方法中JNI(即一般说的Native方法)的饮用对象。
两次标记
1,没有与GC Roots相连接的引用链,第一次标记且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法(当对象没有覆盖finalize方法(),或者finalize()方法已经被虚拟机调用过,虚拟机则视为没有必要执行)。
如果有必要执行,那么这个对象将会被放置在一个名为F-Queue的队列之中,并在稍后由一条由虚拟机自己建立的、低优先级的Finalizer线程去执行,这里所谓的执行,是指虚拟机会触发这个方法,但并不承诺会等待它运行结束。这样的原因是,如果一个对象在finalize方法中执行缓慢,或者发生了死循环,将很可能导致F-Queue队列中的其他对象永久处于等待状态,甚至导致整个内存回收系统崩溃。
finalize方法是对象逃脱死亡的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize中成功拯救自己(重新与引用链上的任何一个对象建立关联),那么在第二次标记时,将被移除即将回收的集合;如果对象这个时候还没有逃脱,那么它就真的离死不远了。
任何一个对象的finalize方法都只会被系统自动调用一次。
回收方法区
方法区(或者HotSpot虚拟机中的永久代)。
永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。
废弃常量:没有任何的对象引用常量池中对应的常量。
无用类:
1,该类的所有实例都已经被回收(Java堆中不存在该类的任何实例)。
2,加载该类的ClassLoader已经被回收。
3,该类对应的java.lang.Class对象没有在任何地方被引用。
垃圾收集算法
1,标记-清除算法
算法分为标记和清除两个阶段:首先标记出所有需要回收的对象,标记完成后统一回收掉所有被标记的对象。
两个缺点:a,标记和清除的效率都不高;b,标记清除之后,会产生大量不连续的内存碎片,导致后面无法分配较大的连续内存空间而不得不提前出发另一次垃圾收集动作。
2,复制算法
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活着的对象复制到另外一块上面,然后把已经使用过的内存空间一次清理掉。
新生代的复制:将内存分为一块较大的Eden和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor。当回收时,将Eden和一块Survivor中还存活的对象一次性的拷贝到另外一块Survivor空间上,最后清除掉Eden和刚才用过的Survivor的空间。HotSpot默认Eden和Survivor的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%,只有10%是会被浪费的。
3,标记-整理算法
首先标记处要回收的对象,然后让所有存活的对象都向一端移动,直接清除掉端边界以外的内存。
4,分代收集算法
分代收集(Generational Collection):根据对象的存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代。新生代中,每次垃圾收集时都会有大批对象死去,只有少量存活,选用复制算法。老年代因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记-清理或标记-整理算法来进行回收。
垃圾收集器
1,Serial收集器
单线程的收集器,进行垃圾收集时,必须暂停其他所有的工作线程(Stop The World)
2,ParNew收集器
ParNew收集器其实就是Serial收集器的多线程版本。除了多线程以外,其他的信息完全一致。
是许多运行在Server模式下的虚拟机的首选的新生代收集器。
除了Serial之外,目前只有ParNew能与CMS收集器配合工作。
3,Parallel Scavenge收集器
Parallel Scavenge收集器也是一个新生代收集器,也是使用复制算法的收集器,又是并行的多线程收集器。
目标:达到一个可控制的吞吐量。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值。
由于与吞吐量关系密切,该收集器也经常被称为吞吐量优先收集器。
4,Serial Old收集器
Serial Old是Serial的老年代版本。单线程的,使用“标记-整理”算法。
5,Parallel Old收集器
是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
6,CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
基于“标记-清除”算法,整个过程分为四个步骤:a,初始标记(CMS initial mark);b,并发标记(CMS concurrent mark);c,重新标记(CMS remark);d,并发清除(CMS concurrent sweep)。其中,a和c仍然需要“Stop The World”。a初始标记仅仅是标记一下GC Roots能直接关联到的对象;b并发标记就是进行GC Roots Tracing的过程;c重新标记则是为了修改并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录;
并发标记和并发清除期间,收集器线程都可以与用户线程一起工作。
缺点:
a,CMS收集器对CPU资源非常敏感。
b,CMS收集器无法处理浮动垃圾。
c,CMS收集器基于“标记-清除”,会产生大量空间碎片。
7,G1收集器
两个改进:
a,G1(Garbage First)收集器基于“标记-整理”算法。
b,可以精确地控制停顿。
内存分配与回收策略
Java技术体系中所提倡的自动内存管理最终可以归结为自动化的解决了两个问题:给对象分配内存以及回收分配给对象的内存。
给对象分配内存,就是在堆上分配(但也可能经过JIT编译后被拆散为标量类型并间接的在栈上分配),对象主要分配在新生代的Eden区,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配。
1,对象优先在Eden分配:大多数情况下,对象在新生代Eden区分配。当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。
2,大对象直接进入老年代:大对象就是指需要大量连续内存空间的Java对象。
3,长期存活的对象将进入老年代:对象在Eden出生,每经过一次Minor GC后仍然存活,并且能被Survivor容纳,年龄就增加1岁,当年龄增加到一定程度(默认15岁,可通过-XX:MaxTenuringThreshold来设置)。
4,动态对象年龄判断:如果在Survivor空间中,相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。
5,空间分配担保:发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则改为进行一次Full GC;如果小于,则查看HandlePromotionFailure设置是否允许担保是被,如果允许,那只会进行Minor GC,如果不允许,则也要改为进行一次Full GC。
虚拟机性能监控与故障处理工具
JDK命令行工具
1,jps:虚拟机进程状况工具
2,jstat:虚拟机统计信息监视工具
3,jinfo:Java配置信息工具
4,jmap:Java内存映像工具
5,jhat:虚拟机堆转储快照分析工具
6,jstack:Java堆栈跟踪工具
JDK可视化工具
1,JConsole:Java监视与管理控制台
2,VisualVM:多合一故障处理工具
类
声明的类的引用,存放在栈内存中,指向实际的实例对象。
真正的实例对象,存放在堆内存中。
当类初始化完成之后,系统在堆内存中为该类分配一个内存区,存放类成员。
继承:
子类构造器执行体的第一行使用super显式调用父类构造器,系统将根据传入的实参调用父类对应的构造器。
子类构造器执行体的第一行使用this显式调用本类中重载的构造器,系统根据this调用里传入的实参列表调用本类的另一个构造器,执行另一个构造器时会调用父类的构造器。
子类构造器执行体中没有super和this调用,系统将会在执行子系统构造器之前,隐式调用父类无参数的构造器。
类的初始化
从某种程度上来说,初始化块是构造器的补充,初始化块总是在构造器执行之前执行。
与构造器类似,创建一个对象的时候,不仅会执行该类的普通初始化块和构造器,而且系统会一直上溯到Object类,先执行Object类的普通初始化和构造器,然后依次往下执行其初始化类父类的初始化块和构造器...最后才执行该类的初始化块和构造器,返回该类对象,完成对象初始化。。
静态初始化块(类初始化块):在类初始化阶段执行。
系统在类初始化阶段执行静态初始化块,首先上溯到Object类,执行Object的静态初始化块,然后执行初始化类的父类的静态初始化块,依次执行,直到初始化类的静态初始化块,此时完成该类的初始化。然后才可以在系统中使用这个类。
this关键字
指向调用该方法的对象。
重载的构造器之间相互调用,需要使用this关键字执行,并且放在当前构造器的第一行
final
修饰变量、方法和类。系统不允许为final变量重新赋值;子类不允许覆盖父类的final方法;final类不能派生子类。
通过使用final关键字,允许Java实现不可变类,不可变类让系统更加安全。
equals方法
自反性:对于任意x,x.equals(x)一定返回true;
对称性:对于任意x和y,如果x.equals(y)为true,则y.equals(x)一定返回true;
传递性:对于任意x、y、z,如果x.equals(y)为true,并且y.equals(z)为true,则x.equals(z)一定返回true;
一致性:对于任意x和y,如果对象中用于等价比较的信息没有变,那么无论调用多少次,返回的结果应该保持一致。
对任何不是null的x,x.equals(null)一定返回false;
基本语言元素
基本类型和包装类
强类型语言,每个变量和每个表达式都有一个在编译时就确定的类型。所有的变量必须显示声明类型。
Java类型分为基本类型和引用类型。
基本类型包括boolean和数值类型,数值类型有整数类型和浮点类型,整数类型包括byte、short、int、long、char,浮点类型包括float和double。
引用类型包括类、接口和数组类型。所谓引用数据类型就是对一个对象的引用。
正无穷大:整数除以0,通过Double或Float的POSITIVE_INFINITY表示。
负无穷大:负数除以0,通过Double或Float的NEGATIVE_INFINITY表示。
非数:0.0除以0.0或者对一个负数开方,通过Double或Float的NaN表示。
所有的正无穷大都是相等的,所有的负无穷大都是相等的,而NaN不与任何数值相等,甚至不和NaN相等。
流程控制
Java常用类
BigDecimal
构造器BigDecimal(double val)不推荐使用,会产生不可预知性。
建议使用BigDecimal(String str),BigDecimal.valueOf(double val)。
Object
String、StringBuffer
Math
Date
抽象类
接口
接口中Field:public static final
接口中方法:public abstract
接口和抽象类:
0,接口多继承,抽象类单继承
1,接口只能包含抽象方法;抽象类可以包含普通方法
2,接口不能定义静态方法和构造器;抽象类可以
3,接口只能定义静态常量Field,不能定义普通Field;抽象类既可以定义普通Field,也可以定义常量静态Field。
4,接口中不能包含初始化块;抽象类可以
包装类
int和Integer
系统把一个-128127之间的整数自动装箱成Integer实例,并放入了一个名为cache的数组中缓存起来。所以,当把一个-128127之间的整数自动装箱成一个Integer实例时,实际上是直接指向对应的数组元素。因此它们全部相等。但对于一个不在此范围内的整数自动装箱成Integer实例时,系统总是重新创建一个新的Integer实例。
如果采用new构造器来创建Integer对象,则每次返回全新的Integer对象;如果采用valueOf方法来创建对象,则会缓存该方法创建的对象。
当使用new String("hello")时,JVM会先使用常量池来管理“hello”直接量,再调用String类的构造器来创建一个新的String对象,新创建的对象被保存在堆内存中。换句话说,new String("hello")一共产生了两个对象。
内部类
内部类成员可以直接访问外部类的私有数据,因为内部类被当成外部类的成员。非静态内部类的成员只在内部类的范围内是可知的,并不能直接被外部类使用。外部类必须显示创建内部类对象来调用其实例成员。(因为内部类存在时,外部类一定存在;外部类存在时,内部类实例不一定存在,所以外部类不能直接访问内部类成员)
外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量,创建实例等。
非静态内部类不能有静态方法、静态Field、静态初始化块。
在非静态内部类的方法中访问某个变量时,系统优先在该方法内查找,其次方法所在的内部类中查找,再次该内部类所在的外部类中查找。
如果外部类成员变量、内部类成员变量与非静态内部类方法里面的局部变量同名,则通过外部类类名.this.成员变量名访问外部类成员变量;this.成员变量名访问内部类成员变量。
静态内部类可以包含静态成员和非静态成员。不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。
外部类不能直接访问静态内部类的成员,但可以使用静态内部类的类名访问静态内部类的类成员,也可以使用静态内部类对象访问静态内部类的实例成员。
静态内部类是外部类的类相关。
非静态内部类是外部类的实例(对象)相关。
创建内部类对象时,静态内部类只需使用外部类即可调用构造器;非静态内部类必须使用外部类对象来调用构造器。
局部内部类
方法内定义,方法内有效,不能使用访问控制符和static修饰符修饰。
局部内部类定义变量、创建实例或派生子类都只能在局部内部类所在的方法内进行。
匿名内部类
匿名内部类适合用于创建那些仅需要一次使用的类。
创建匿名内部类会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。
匿名内部类必须继承一个父类或者实现一个接口,但最多一个父类或一个接口。
两条规则:
1,匿名内部类不能是抽象类
2,不能定义构造器
Java异常
Checked异常和Runtime异常体系
Java的异常分为两大类:Checked异常和Runtime异常(运行时异常)。
Checked异常:必须显式捕获并处理,或者显式声明抛出该异常。
Java集合
Java集合概述
集合类主要负责保存、盛装其他数据,因此集合类也被成为容器类。
集合里只能保存对象。
当使用Iterator和foreach迭代访问集合里面的元素时,集合不能被改变,否则将引发ConcurrentModificationException异常。(用Iterator遍历的时候,可以用Iterator去remove,但不能用集合去删除)。
Set集合
Set集合不允许包含相同的元素。
判断两个对象相同,不是使用==,而是根据equals方法。
HashSet
HashSet按Hash算法来存储集合中的元素。
特点:
1,不保证元素的排列顺序,顺序有可能发生变化。
2,HashSet不是同步的,多个线程同时修改时,必须通过代码来保证同步。
3,集合元素可以是null。
对于一个类,要同时重写equals方法和hashCode方法。规则是,如果两个对象通过equals方法比较返回true,则这两个对象的hashCode值也应该相同。
重写hashCode的原则
1,在程序运行过程中,同一个对象多次调用hashCode方法应该返回相同的值。
2,两个对象equals方法比较返回true时,这两个对象的hashCode方法应返回相同的值。
3,对象中用作equals方法比较标准的field,都应该用来计算hashCode值。
重写hashCodede的一般规则
1,把对象内每个有意义的Field(用作equals方法比较标准的Field)计算出一个int类型的hashCode值。
2,用计算出来的多个hashCode值组合计算出一个hashCode值返回。
注意:当向HashSet中添加可变对象时,如果修改集合中的对象,有可能导致该对象与集合中的其他对象相同,从而导致HashSet无法准确访问该对象。(对象存入HashSet,桶位固定,这时候,修改对象的Field值,HashSet的值变化,但是对象的桶位未变。这个时候,如果根据对象所在桶位查找时,会找不到)
LinkedHashSet类
根据元素的hashCode值来决定元素的存储位置,但同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。
TreeSet类
TreeSet类是SortedSet接口的实现类。TreeSet可以确保集合元素处于排序状态。
TreeSet采用红黑树的数据结构来存储集合元素。TreeSet支持两种排序:自然排序和定制排序。在默认情况下,采用自然排序。
自然排序调用集合元素的compareTo方法来比较元素之间的大小关系。然后将集合按照升序排列。自然排序的元素对象的类,必须实现Comparable接口。
定制排序
如果要实现定制排序,则需要在创建TreeSet集合对象时,提供一个Comparator对象与该TreeSet集合关联,由该Comparator对象负责几何元素的排序逻辑。
HashSet性能比TreeSet好,但是HashSet不排序
HashSet、TreeSet和EnumSet都是线程不安全的。
EnumSet类
专为枚举类设计的集合类,所有的元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式的指定,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。
EnumSet在内部以位向量的形式存储。EnumSet不允许插入null值。
List集合
List集合代表一个元素有序、可重复的集合,集合中的每个元素都有其对应的顺序索引。
List集合中,判断元素相等,根据equals方法。
ArrayList和Vector都是基于数组实现的List类,所以ArrayList和Vector类封装了一个动态的、允许再分配的Object数组。
ArrayList是线程不安全的,Vector是线程安全的。
注解(Annotation)
一种为程序元素设置元数据的方法。
通常把Annotation放在所有修饰符之前,而且由于使用Annotation时可能还需要为成员变量指定值,因而Annotation的长度可能较长,所以通常单独放一行。
自定义Annotation
定义新的Annotation类型使用@interface关键字。
Annotation的成员变量在定义的时候,以无形参的方法形式声明,其方法名和返回值定义了该成员变量的名字和类型。
Annotation分为:
1,标记Annotation,没有定义成员变量的Annotation。
2,元数据Annotation,包含成员变量的Annotation。
高级语言特性
Java I/O
在Java中把不同的输入输出源(键盘、文件、网络连接等)抽象表述为“流”(stream),通过流的方式允许Java程序使用相同的方式来访问不同的输入输出源。stream是从起源到接受的有序数据。
Java的输入流主要由InputStream和Reader作为基类,而输出流主要由OutputStream和Writer作为基类。它们都是一些抽象类,无法直接创建实例。
字节流操作的数据单元是8位的字节。字符流操作的数据单元是16位的字符。字节流主要由InputStream和OutputStream作为基类,而字符流主要由Reader和Writer作为基类。
InputStream和Reader
InputStream和Reader是所有输入流的抽象基类,它们的所有方法是所有输入流都可使用的方法。它们分别有一个用于读取文件的输入流:FileInputStream和FileReader
OutputStream和Writer
FileOutputStream、FileWriter
多线程
进程和线程
每个运行的程序就是一个进程,当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程。
进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位。进程的特性:独立性(系统中独立存在的个体,拥有自己独立的资源,私有的地址空间)、动态性(系统中活动的指令集合,具有自己的生命周期和各种不同的状态)、并发性(多个进程可以在单个处理器上并发执行)。
并发:宏观上多个进程执行快速轮换执行,微观上同一时刻只能有一条指令执行。
并行:同一时刻多条指令在多个处理器上同时执行。
线程:轻量级进程,线程是进程的执行单元。线程在程序中是独立的、并发的执行流。线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不拥有系统资源,他与父进程的其他线程共享该进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
操作系统可以执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程。
线程的运行是抢占式的。
同一个进程中的线程都有共性--多个线程共享同一个进程虚拟空间。线程共享的环境包括:进程代码段、进程的共有数据等。
线程的创建和启动
继承Thread类
实现Runnable接口
线程的生命周期
新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)。
新建:使用new关键字创建之后,为新建状态,此时仅仅由Java虚拟机为其分配内存,并初始化其成员变量的值。
就绪:调用了start方法之后,Java虚拟机会为其创建方法调用栈和程序计数器,此时线程并没有开始运行。
运行:就绪状态的线程获得了CPU,开始执行run方法的线程执行体。
阻塞:调用sleep方法|调用阻塞式I/O|视图获得其他线程持有的同步监视器|等待某个通知|调用suspend方法。
死亡:run或call方法执行完成|抛出未捕获得Exception或Error|调用该线程的stop方法。
控制线程
join线程
后台线程
线程睡眠:sleep
线程让步:yield
sleep与yield
1,sleep暂停当前县城后,让给其他线程执行机会,不分优先级;yield方法只会给优先级相同或更高的线程执行机会。
2,sleep将线程转入阻塞状态,直到阻塞时间完成才会转入就绪状态;yield不会让线程转入阻塞,只是强制进入就绪状态,因此有可能某个线程通过yield暂停之后,立即再次获得处理器资源而执行。
3,sleep声明抛出了InterruptedException异常;yield没有声明抛出任何异常。
4,sleep比yield方法有更好的可移植性。
线程的优先级
MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY
线程同步
Java网络编程
计算机网络:把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成为一个规模大、功能强的网络系统,从而使众多的计算机可以方便的互相传递信息,共享硬件、软件、数据信息等资源。
计算机网络按照规模大小和延伸范围来分类:局域网(LAN)、城域网(MAN)、广域网(WAN)。
通信协议负责对传输速率、传输代码、代码结构、传输控制步骤、出错控制等制定处理标准。通信协议通常由三部分组成:一是语义部分,用于决定双方对话的类型;二是语法部分:用于决定双方对话的格式;三是变换规则,用于决定通信双方的应答关系。
开放式互连参考模型:物理层,网络链路层,网络层,传输层,会话层,表示层,应用层。
TCP/IP协议模型:物理+数据链路,网络层,传输层,应用层。
TCP(Transmission Control Protocol)协议:传输控制协议,规定一种可靠的数据信息传递服务。
IP(Internet Protocol)协议:互联网协议,是支持网间互联的数据报协议。
Java反射机制
类的加载、连接和初始化
当Java命令运行某个Java程序时,该命令将会启动一个Java虚拟机进程。
类的加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象。类加载由类加载器完成,类加载器由JVM提供,JVM提供的这些类加载器被称为系统类加载器。
类的连接:把类的二进制数据合并到JRE中。分为如下三个阶段:1、验证,检验类是否有正确的内部结构,是否和其他类协调一致;2、准备,为类的静态Field分配内存,并设置默认值;3、解析,将类的二进制数据中的符号引用替换成直接引用。
类的初始化:虚拟机完成对类初始化,主要是对静态Field进行初始化。
JVM初始化类的步骤:
1,如果类没有加载和连接,则程序先加载并连接该类。
2,如果类的直接父类还没有被初始化,则先初始化其直接父类。
3,加入类中有初始化语句,则系统依次执行这些初始化语句。
当JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构:
1,BootstrapClassLoader:根类加载器。
2,ExtensionClassLoader:扩展类加载器。
3,SystemClassLoader:系统类加载器
JDBC
JDBC(JavaDatabase Connectivity,即Java数据库连接)是一种可以执行SQL语句的JavaAPI。
SQL语言基础
Structured Query Language,结构化查询语言。
标准SQL语句可分为以下几种类型
1,查询语句:由select关键字组成。
2,DML(Data Manipulation Language,数据操作语言)语句:insert、update和delete三个关键字组成。
3,DDL(Data Definition Language,数据定义语言)语句:create、alter、drop和truncate。
4,DCL(Data Control Language,数据控制语言)语句:grant、revoke。
5,事务控制语言:commit、rollback和savepoint。
事务
事务具备四个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持续性(Durability)。
编译期优化
编译期:把.java文件转成.class文件的过程;虚拟机的后端运行期编译器(JIT编译器,Just In Time Compiler)把字节码转变成机器码的过程;使用静态提前编译器(AOT编译器,Ahead Of Time Compiler)直接把*.java文件编译成本地机器代码的过程。
早期(编译期)优化
把Java源码文件转变为Class文件的编译过程(从Sun Javac的代码来看,可以分为以下三个):
a,解析与填充符号表过程。
b,插入式注解处理器的注解处理过程。
c,分析与字节码生成过程。
解析与填充符号表
1,词法、语法分析
词法分析是将源代码的字符流转变为标记(Token)集合,单个字符是程序编写过程的最小元素,而标记则是编译过程的最小元素,关键字、变量名、字面量和云算符都可以成为标记。(com.sun.tools.javac.parser.Scanner)
语法分析是根据Token序列来构造抽象语法树的过程,抽象语法树(AST,Abstract Syntax Tree)是一种用来描述程序代码语法结构的树形表示方式,语法树的每一个节点都代表着程序代码的一个语法结构(Construct),例如包、类型、修饰符、运算符、接口、返回值甚至代码注释都可以是一个语法结构。(com.sun.tools.javac.parser.Parser)
2,填充符号表
符号表(Symbol Table)是由一组符号地址和符号信息构成的表格,符号表中所登记的信息在编译的不同阶段都要用到。在语义分析中,符号表所登记的内容将用于语义检查(如检查名字的使用和原先的说明是否一致)和产生中间代码。在目标代码生成阶段,当对符号名进行地址分配时,符号表是地址分配的依据。(com.sun.tools.javac.comp.Enter)
注解处理器
如果在处理注解期间,对语法树进行了修改,那么编译器将回到解析及填充符号表的过程重新处理,直到所有的插入式注解处理器都没有再对语法树进行修改为止。
语义分析与字节码生成
语义分析的主要任务是对结构上正确的源程序进行上下文有关性质的审查,如进行类型审查。
语义分析过程分为标注检查和数据及控制流分析两个步骤。
1,标注检查
标注检查检查的内容包括诸如变量使用前是否已经被声明、变量与赋值之间的数据类型是否能够匹配等等。在该步骤中,还有一个重要的动作成为常量折叠。
2,数据及控制流分析
数据及控制流分析是对程序上下文逻辑更进一步的验证,它可以检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都被正确处理了等问题。
3,解语法糖
语法糖(Syntactic Sugar),也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说,使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
4,字节码生成
字节码生成阶段不仅仅是把前面各个步骤所生成的信息(语法树、符号表)转化成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。
晚期(运行期)优化
当虚拟机发现某个方法或代码块的运行特别频繁,就会把这段热点代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器成为即时编译器(Just In Time Compiler,JIT编译器)。
HotSpot虚拟机中内置了两个即时编译器,成为Client Compiler和Server Compiler,或者简称为C1编译器和C2编译器(也叫Opto编译器)。目前主流的HotSpot虚拟机中,默认是采用解释器与其中一个编译器直接配合的方式工作。
分层编译:
第0层:程序解释执行,解释器不开起性能监控功能,可触发第1层编译。
第1层:也成为C1编译,将字节码编译为本地代码,进行简单可靠的优化,如有必要将加入性能监控的逻辑。
第2层(或2层以上):也成为C2编译,也是将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。
热点探测判定方式:
1,基于采样的热点探测:周期性检查各个线程的栈顶。
2,基于计数器的热点探测:虚拟机会为每个方法(甚至是代码块)建立计数器,统计方法的执行次数。
Jvm
设计模式
工厂模式
单例模式
框架扩展
Struts
Spring
Hibernate
开源框架介绍
扩展学习
正则表达式
Python
网友评论