Java基础知识
JVM
ClassLoader包括bootstrap?classloader,加载Java核心API,包括ExtClassLoader和AppClassLoader(加载CLASSPATH目录下定义的Class)
父类委托模式,避免重复加载,父类加载了该类的时候,没必要再加载
loadClass()和Class.ForName()
Class.forName(“something”,true,CALLCLASS.class.getClassLoader())
loadClass(“”,resolve)第二个默认是false,也就是不解释,所以不会初始化
第二个参数true用于设置加载类的时候是否连接
JVM加载类的时候,经历三个步骤:装载、连接和初始化
forName进行加载的时候就会将Class进行初始化,而loadClass不会进行初始化
&、|、^可作为位运算符以及布尔逻辑运算符,非短路运算,&&、||短路运算
移位操作符右边的参数要先进行模的32运算
异常
java运行时异常(RuntimeException)是可能在java虚拟机正常工作时抛出的异常,当出现这样的异常时,总是由虚拟机接管,用户不必处理
ClassCastException(类转换异常)
IndexOutOfBoundsException(数组越界)
NullPointerException(空指针)
ArrayStoreException(数据存储异常,操作数组时类型不一致)
BufferOverflowException异常
检查式异常(Checked?exception):表示程序可以处理的异常,我们经常遇到的IO异常及sql异常就属于检查式异常。对于这种异常,java编译器要求我们必须对出现的这些异常进行catch?所以?面对这种异常不管我们是否愿意,只能自己去写一堆catch来捕捉这些异常
所有抛出的异常都由Throwable派生,有两个直接子类Error和Exception
错误包括死循环、内存泄露等,程序运行时本身无法解决
异常在程序运行时可以本身解决
若有多个catch块,则从上到下,选择一个异常类执行catch块代码
Throw和throws的区别
Throw用于方法体内部,由方法体内的语句处理
Throws用于方法外部声明,由该方法的调用者处理
throws主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常
throw是具体向外抛异常的动作,所以它是抛出一个异常实例
Final
Final定义变量时,一旦初始化则不可改变,基本类型是其值不变,对象是其引用不变
Final方法说明该方法不需要扩展,而且不允许该类的子类覆写该方法;允许编译器将对此方法的调用转化为inline的调用机制
Final类无法被任何类继承,类中的成员可以是final也可以不是,方法必须是final类型
Finally是对异常处理模型的补充,使得代码总会执行
Finalize是object类的一个方法,在gc执行的时候调用被回收对象的此方法,在将对象从内存清理之前,供垃圾收集时的其他资源回收
反射
反射主要是指程序可以访问、检测和修改它本身状态或者行为的一种能力
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
Java中的反射能够创建灵活的代码,这些代码可以在运行时装配,无须在组件之间进行链接。允许编写与执行时,使程序代码能够接入装载到JVM中类的内部信息
Java.lang.class类
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息记录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类
ClassLoader找到了需要调用的类时,就会加载它,然后根据.class文件内记载的类信息来产生一个与该类相联系的独一无二的Class对象。该Class对象记载了该类的字段,方法等等信息。以后jvm要产生该类的实例,就是根据内存中存在的该Class类所记载的信息来进行
容许程序在运行时加载、探知、使用编译期间完全未知的classes
传值和传引用
不管java参数的类型是什么,一律传递参数的副本
对于基本类型,传值的副本,对于对象,传引用的副本
数组传值传的是引用的副本
序列化
Java对象序列化能将一个实现了Serializable接口的对象转换成一组byte,跨网络跨平台,实现轻量级持久化,在程序两次调用之间仍然存活,将序列化后的对象写入磁盘
序列化对象,必须先创建一个outputStream,把它嵌进ObjectOutputStream,用writeObject方法写入
可以将对象中的引用对象也保存起来
内存泄露
过去的语言要求程序员显式地分配内存和释放内存,容易造成“内存泄露”,java在创建对象时自动分配内存,当该对象的引用不存在时自动释放内存
Java使用垃圾收集器来监视java程序的运行,并在对象不使用时释放内存
Java使用一系列软指针跟踪对象的各个引用,用对象表将软指针映射为对象的引用。垃圾收集器可以以单独的线程在后台运行,并依次检查每个对象
垃圾收集器自动运行,调用System类中的gc()方法可以运行垃圾收集器,并不能保证立即回收指定对象
判断一块内存空间是否符合垃圾回收的标准
给对象赋值为null,以后再也没有被掉用过
给对象赋予了新值
Java内存管理就是java对象的分配和释放
内存泄露就是为对象分配了内存空间,并存在引用,但是之后不会使用该对象
软引用、弱引用和虚引用
ClassLoader容易造成内存泄露
Clone
Object类的clone是protected,不能被直接调用,但是能被子类调用
Clone之前先检查class是否实现了cloneable接口
默认的clone只是浅复制
先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象
Collection:
List--?ArrayList、LinkedList
ArrayList和Vector都是通过数组实现,但是Vector支持线程的同步
ArrayList在添加元素时,会检查内部数组的容量是否足够,如果不够,就重建一个当前容量两倍的数组,然后将旧元素复制到新数组,抛弃旧数组
Set--HashSet基于hashMap实现,使用hashCode函数确定散列码
?????TreeSet基于TreeMap实现,实现Comparable接口,元素不重复,自动排序
?????LinkedHashSet使用链表维护hashSet
Queue--可用数组或者链表实现,维护两个指针head和rear,head指向实际的第一个元素,rear指向尾元素的后一位
Map:
hashMap由线性数组实现,其存储数据的容器就是一个线性数组,数组与链表的结合,数组的每一项是一个链表,允许null
HashMap内部实现了一个静态内部类Entry,其重要属性有key、value、next,hashMap的基础就是数组Entry[],使用hashCode()分配散列码,实现随机存取
hashCode()--hash()--indexFor()计算保存的index
如果两个key得到的index相同,则用到next属性。A的index为0,则Entry[0]=A,下一个B的index为0,则Entry[0]=B,B.next=A
HashTable也是一个散列表,存储键值对映射,继承于Dictionary,实现Map、Cloneable、java.io.serializable接口,不允许null,函数都是同步的,线程安全,其内部实现了一个Entry类,包含next、hash、key、value等属性,数组和链表结合,拉链法
TreeMap通过红黑树实现,是一个有序的键值对集合,实现NavigableMap、Cloneable、serializable接口,非同步,继承于AbstractMap接口
红黑树,根节点和叶节点都是黑色,每个红色节点的两个子节点都是黑色的,从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
Super关键字
子类的构造函数调用父类的构造函数,super()放在第一个
子类成员变量或方法隐藏了超类的成员变量和方法,super调用超类的方法或成员变量
This关键字在方法体中指向当前正在执行方法的对象实例
全面访问当前对象,而不是一个个别的实例对象System.out.println(this)
构造函数的第一条语句,this(参数列表)调用同一个类的另一个相对的构造函数
匿名内部类是没有名字的内部类,不能继承其他类,但一个内部类可以作为一个接口,由另一个内部类实现
抽象类和接口
抽象类用于表达一种抽象的概念,接口是对操作的抽象
java中一个类只有继承一个抽象类,但是能实现多个接口
接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类
接口定义方法,不能实现,而抽象类可以实现部分方法
接口中基本数据类型为static,而抽类象不是
Override和overload
Override(重写,覆写)
String
String是final的,其值不可修改,非可变性,线程安全的
常量池,不用new
当调用?intern?方法时,如果池已经包含一个等于此?String?对象的字符串(用?equals(Object)?方法确定),则返回池中的字符串。否则,将此?String?对象添加到池中,并返回此?String?对象的引用
避免使用+=构造字符串,会新建一个对象,将原来的引用指向新的对象,造成内存浪费
在某些特别情况下,?String?对象的字符串拼接其实是被?JVM?解释成了?StringBuffer?对象的拼接?String?S1=”a”+”b”+”c”
StringBuffer
线程安全,主要操作append和insert,和String类型不能进行强制类型转换
大部分情况下StringBuilder>StringBuffer
StringBuilder提供一个与StringBuffer兼容的API,但是不能保证同步。被设计用作?StringBuffer?的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比?StringBuffer?要快。两者的方法基本相同
A的ASC||码是65,Z的ASC||码是90,a的ASC||码是97
泛型
泛型(Generic?type?或者?generics)是对?Java?语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类(参数化类型)
类型参数
当声明或者实例化一个泛型的对象时,必须指定类型参数的值:
Map<String,?String>?map?=?new?HashMap<String,?String>();
泛型不是协变的List<Object>?不是?List<String>?的父类型
Iterator迭代器也需要采用泛型参数
Java泛型的处理几乎都在编译器中进行,编译器生成的bytecode是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除
无论何时定义一个泛型类型,都自动提供了一个相应的原始类型。原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定的变量用Object)。一般而言,原始类型使用第一个限定的类型变量进行替换,如果没有给定限定就使用Object替换
一个泛型类的所有实例在运行时具有相同的运行时类(class),而不管他们的实际类型参数
调用时强制类型转换
线程安全的单例模式
(1)Private?static?Singleton?uniqueInstance?=?new?Singleton()静态初始化器
Private?Singleton(){}
if(uniqueInstance==null){
???????Synchronized(){
??????????If(uniqueInstance==null){
??????????????uniqueInstance=new?singleton();
???????????}
??????}
??????Return?uniqueInstance
JAVA处理高并发高负载网站
数据库
主-从方式同步复制,将查询分别在不同的服务器上进行操作
Slaves进行进一步负载均衡,结合LVS(数据库集群)
从业务层面上进行表分区,数据库hash散列法
HTML静态化
缓存
Memcached分布式缓存服务器,基于hashmap
squid缓存服务器
定时生成静态页面
进程和线程
进程是一个具有独立功能的程序关于某个数据集合的一个运行过程,是系统分配资源的基本单位,而线程是独立运行和独立调度的基本单位
一个进程可以包含多个线程,线程在进程外不可见
进程间通信需要同步互斥,而线程间可以直接读写进程数据段
线程上下文切换比进程上下文切换快得多
线程的5种状态
新建态(New):new关键字创建Thread类(子类)的对象
就绪态(Runnable):该对象调用start()方法,系统会为这个线程分配它运行时所需的除处理器之外的所有系统资源,等待CPU
线程在处于RUNNABLE状态时并没有运行完自己的run方法,时间片用完之后回到RUNNABLE状态;还有种情况就是处于BLOCKED状态的线程结束了当前的BLOCKED状态之后重新回到RUNNABLE状态
运行态(Running):线程占用CPU
阻塞态(Blocked):出于某种原因,比如调用了sleep方法、wait方法、调用了其他线程的join方法、等待用户输入等而让出当前的CPU给其他的线程
死亡态(Dead):当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。线程有可能是正常执行完run()方法而退出,也有可能是遇到异常而退出。不管线程是正常结束还是异常结束,都不会对其他线程造成影响
Sleep()和wait()的区别
Sleep来自Thread类,wait来自Object类
Sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。Sleep不出让系统资源,wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断
wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用?
通过实现Runnable接口可以实现线程间的资源共享
thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程
在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B
Volatile?类型修饰符,修饰被不同线程访问和修改的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的
Serialize
对象通过写出描述自己状态的数值来记录自己?,这个过程叫对象的串行化
Transient表示不是该对象串行化的一部分
Synchronized关键字可以修饰函数、instance变量、对象引用、static函数
无论加载方法还是对象上,取得的锁都是对象
不同对象实例的synchronized方法互不干扰
<!--[if !supportLists]-->(1)<!--[endif]-->修饰方法,不同对象实例的synchronized方法不互相干扰
<!--[if !supportLists]-->(2)<!--[endif]-->用于方法中的某个区域,synchronized(this)作用域是当前对象,synchronized(a.class)作用域是整个对象
数据库和SQL
数据库事务是作为单个逻辑工作单元执行的一系列操作,要么都执行,要么都不执行,不可分割
ACID
原子性
一致性:只有合法的数据可以被写入数据库,否则事务应该回滚到最初状态
隔离性
持久性
数据库操作过程中可能出现的几种不确定情况
更新丢失:两个事务同时进行写操作,某一个事务异常终止,事务回滚导致另外的事务的更新也丢失
脏读:第二个事务查询到第一个事务还未提交的更新数据
不可重复读:一个事务对同一行数据重复读取两次,但是得到了不同的结果
两次
虚读:一个事务执行两次查询,第二次结果集包含第一次中没有或者某些行已被删除,造成两次结果不一致,另一个事务在这两次查询中间插入或者删除了数据造成的(除了串行化都会出现)
第二类丢失更新:是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都进行写操作,并提交,第一个事务所做的改变就会丢失
数据库事务隔离级别
Serializable串行化
Repeatable?read?可重复读(mysql默认)
Read?committed?可读已提交
Read?uncommitted?可读未提交
数据库的锁机制:
共享锁:由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写
排它锁:由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁
悲观锁:在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制
乐观锁:大多是基于数据版本(?Version?)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个?“version”?字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一
聚簇索引的顺序就是数据的物理存储顺序
非聚簇索引的索引顺序与数据物理排列顺序无关
什么时候应该不建或少建索引
<!--[if !supportLists]-->(1)<!--[endif]-->表记录太少
<!--[if !supportLists]-->(2)<!--[endif]-->经常插入、删除、修改的表
<!--[if !supportLists]-->(3)<!--[endif]-->数据重复且分布平均的表字段
<!--[if !supportLists]-->(4)<!--[endif]-->经常和主字段一块查询但主字段索引值比较多的表字段
Join
两个表的连接分为内连接(等值连接)和外连接,外连接又分为左连接、右连接和全连接
Oracle还有两种连接方式:cross?join,结果就是两个表的笛卡尔乘积;natural?inner?join,也是一种inner?join系统自动匹配两个表中字段名相同的列,两表中名称相同的列只出现一次
外连接:并不要求连接的两表的每一条记录在对方表中都一条匹配的记录
全连接是左连接和右连接的并集
尽量将?OUTER?JOIN?转换为?INNER?JOIN,并尽可能地嵌套。如果嵌套循环JOIN的?WHERE?子句或?ON?子句中有一个条件表达式剔除了内表中某属性为?NULL?的所有值,则??OUTER?JOIN?可以替换为??INNER?JOIN
数据量较小的表可能会被放在最前面先处理,数据量较大的表会稍后处理(嵌套循环)
网络
NAT网络地址转换:将一个IP地址域映射到另一个IP地址域
反向NAT可以实现负载均衡
TCP和UDP的区别
<!--[if !supportLists]-->(1)<!--[endif]-->TCP面向连接,UDP无连接,TCP连接时三次“会话”,断开连接时四次“会话”
请求发送数据——同意连接要求同步——确认同步
<!--[if !supportLists]-->00001.?<!--[endif]-->
客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态
服务器端收到SYN报文,回应一个SYN?(SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态
客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态
断开连接:主机A将FIN位置为1,请求断开连接
主机B收到FIN相应,确认关闭这一方向上的连接,ACK=1
主机B提出反方向断开连接,将FIN=1
主机A收到,ACK=1,双方向连接关闭
(2)TCP报头最小20字节
UDP报头最小8个字节
<!--[if !supportLists]-->(3)<!--[endif]-->对系统资源的要求(TCP较多,UDP少)
<!--[if !supportLists]-->(4)<!--[endif]-->TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证,尽最大努力交付
OSI7层模型
物理层:利用物理传输介质为数据链路层提供物理连接
数据链路层:在此层将数据分帧,并处理流控制。屏蔽物理层,为网络层提供一个数据链路的连接,在一条有可能出差错的物理连接上,进行几乎无差错的数据传输(帧)
网络层:通过寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层(IP数据报)
传输层:为会话层用户提供一个端到端的可靠、透明和优化的数据传输服务机制(数据段)
会话层:两进程之间建立、维护和结束会话连接
表示层:主要用于处理两个通信系统中交换信息的表示方式
应用层
IP地址
A类:0.0.0.0.0——127.255.255.255
B类:128.0.0.0——191.255.255.255
C类:192.0.0.0——223.255.255.255
测试本机是否安装了TCP/IP协议:ping?127.0.0.1
J2EE
Spring轻量级框架
非侵入式:对象不依赖于Spring的类
控制反转:对组件对象控制权的转移,从程序代码本身转移到了外部容器,通过容器来实现对象组件的装配和管理,对象被动接收依赖类而不是自己主动寻找
依赖注入:在运行期由容器将依赖关系转入到组件中,将其他对象的引用通过组件提供的setter方法进行设定
面向切面(AOP):针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果
核心组件BeanFactory
特点:提供的是一种管理业务对象的方法,TDD,易于单元测试
Hibernate
从sessionFactory获得一个session对象
使用session的openTransaction开始一个新的事务
使用Session接口的save方法保存实例
如果成功,使用Transaction接口的commit方法提交事务,否则使用rollback方法回滚事务
关闭Session对象
Session对象并不是线程安全的,可通过ThreadLocal类,产生可重入的线程安全的代码
懒加载也被称为延迟加载,它在查询的时候不会立刻访问数据库,而是返回代理对象,当真正去使用对象的时候才会访问数据库
Servlet?的主要功能在于交互式地浏览和修改数据,生成动态?Web?内容,并不是线程安全的
Struts2?业务逻辑控制框架
Action是线程安全的,为每个http请求新建一个action实例
JSP的基础是servlet
当一个请求被映射到jsp,web容器首先检查该jsp的servlet是否比jsp页面老,如果是就将jsp页面转成servlet并且编译
Page:定义页面中的全局属性
Include:实现JSP页面的模块化,使JSP的开发和维护变得相当简单
Forward:把当前JSP请求转发到另一个资源上,使用RequestDispatcher?,JSP的转发功能是在服务器本身上实现的
Javabean规范
Usebean的scope:
page表示将JavaBean实例对象存储在PageContext对象中,作用范围是当前JSP页面有效
request表示将JavaBean实例对象存储在ServletRequest对象中,存储在request对象中的JavaBean对象可以被属于同一个请求的所有Servlet和JSP页面访问
session表示将JavaBean实例对象存储在HttpSession对象中,存储在HttpSession对象中的JavaBean对象可以被属于同一个会话的所有Servlet和JSP页面访问,此设置要求当前JSP页面支持Session,即没有将page指令的session属性设置为false。也就是对一个特定用户有效,一个http会话
application表示将JavaBean实例对象存储在ServletContext对象中,存储在ServletContext对象中的JavaBean对象可以被同一个Web应用程序中的所有Servlet和JSP页面访问。也就是所有用户都可以使用
Session?记录客户端状态,保存在浏览器上
Cookie也是记录客户端状态,保存在浏览器中
永久登录
账号和加密后的密码保存在cookie中,下次访问时解密并与数据库比较
账号保存在account的cookie中,MD5加密后的账号和秘钥保存在ssid的cookie中,下次访问时比较
Session和cookie的比较
存取方式:cookie只能保存ASC||字符,进行编码,session可以保存任何类型的数据
隐私安全:cookie保存在客户端浏览器,session保存在服务器端
有效期:cookiede?maxAge属性可以设为一个很大很大的值,而session依赖于JSESSIONID的cookie,而Cookie?JSESSION的maxAge默认为-1,只要关闭了浏览器该session就会失效
两种机制实现session
Cookie——jsessionid
URL重写
Cookie?在线书店,按照用户的爱好,当用户再次访问站点时,向用户推荐书籍
Session?跟踪用户的购物车,导航信息,登录状态
?
?
?
装箱:把基本类型用它们相应的引用类型包装起来,使其具有对象的性质。int包装成Integer、float包装成Float
拆箱:和装箱相反,将引用类型的对象简化成值类型的数据
自动拆箱有个很典型的用法就是在进行运算的时候:因为对象时不能直接进行运算的,而是要转化为基本数据类型后才能进行加减乘除?
Java对于Integer与int的自动装箱与拆箱的设计(享元模式)
在自动装箱时对于值从-128到127之间的值,被装箱为Integer对象后,会存在内存中被重用,始终只存在一个对象,而超过该范围的值,被装箱后的Integer对象并不会被重用
?
?
原文:http://roomfourteen224.iteye.com/blog/2193129