目录
Java基础
public boolean equals(Object obj): 比较字符串的内容是否相同,区分大小写
public boolean equalsIgnoreCase(String str): 比较字符串的内容是否相同,忽略大小写
public boolean contains(String str): 判断字符串中是否包含传递进来的字符串
public boolean isEmpty(): 判断字符串的内容是否为空串""
public String replace(String old,String new) : 将指定字符串进行互换
public String trim() :去除两端空格
public int length () :返回此字符串的长度。
public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。有些特殊符号需要用反斜杠 \ 转义,在Java要用两个反斜杠 \\
public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,不含endIndex (当只有参数beginIndex,则从beginIndex开始截取字符串到字符串结尾。)
public String toLowerCase()//将当前字符串中所有字符转换成小写
public String toUpperCase()//将当前字符串中所有字符转换成大写
public boolean startsWith(String str): 判断字符串是否以传递进来的字符串开头
public boolean endsWith(String str): 判断字符串是否以传递进来的字符串结尾
2、Java 是值传递还是引用传递?
值传递与引用传递的区别:
值传递:是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。简单来说就是直接复制了一份数据过去,因为是直接复制,所以这种方式在传递时如果数据量非常大的话,运行效率自然就变低了,所以java在传递数据量很小的数据是值传递,比如java中的各种基本类型:int,float,double,boolean等类型。
引用传递:引用传递其实就弥补了上面说的不足,如果每次传参数的时候都复制一份的话,如果这个参数占用的内存空间太大的话,运行效率会很底下,所以引用传递就是直接把内存地址传过去,也就是说引用传递时,操作的其实都是源数据,这样的话修改有时候会冲突,记得用逻辑弥补下就好了,具体的数据类型就比较多了,比如Object,二维数组,List,Map等除了基本类型的参数都是引用传递。
3、== 与 equals的区别
== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
4、String s = “123”这个语句有几个对象产生?
(1) 若字符串池中没有"123",则产生一个对象,并且放入常量池中,若有"123",则产生0个对象。(0或1个)
(2) 若是String s1 = new String("123")
若常量池中没有,则在常量池中创建一个,然后在堆内存中创建一个。(1个或2个)
5、如果去掉了main方法的static修饰符会怎样?
程序能正常编译。运行时会抛NoSuchMethodError异常。
6、什么是接口幂等性?
接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。
7、Java 重载与重写是什么?有什么区别?
重载(Overload)是让类以统一的方式处理不同类型数据的一种手段,实质表现就是多个具有不同的参数个数或者类型的同名函数(返回值类型可随意,不能以返回类型作为重载函数的区分标准)同时存在于同一个类中,是一个类中多态性的一种表现(调用方法时通过传递不同参数个数和参数类型来决定具体使用哪个方法的多态性)。
重写(Override)是父类与子类之间的多态性,实质是对父类的函数进行重新定义,如果在子类中定义某方法与其父类有相同的名称和参数则该方法被重写,不过子类函数的访问修饰权限不能小于父类的;若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法,如需父类中原有的方法则可使用 super 关键字。
8、重写与重载之间的区别
方法重载:
1、同一个类中
2、方法名相同,参数列表不同(参数顺序、个数、类型)
3、方法返回值、访问修饰符任意
4、与方法的参数名无关
方法重写:
1、有继承关系的子类中
2、方法名相同,参数列表相同(参数顺序、个数、类型),方法返回值相同
3、访问修饰符,访问范围需要大于等于父类的访问范围
4、与方法的参数名无关
8、Java 中String、StringBuffer、StringBuilder有什么区别?
String是Java中基础且重要的类,并且String也是Immutable类的典型实现,被声明为final class,除了hash这个属性其它属性都声明为final,因为它的不可变性,所以例如拼接字符串时候会产生很多无用的中间对象,如果频繁的进行这样的操作对性能有所影响。
StringBuffer就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类,提供append和add方法,可以将字符串添加到已有序列的末尾或指定位置,它的本质是一个线程安全的可修改的字符序列,把所有修改数据的方法都加上synchronized。但是保证了线程安全是需要性能的代价的。
StringBuilderr类也代表可变字符串对象。实际上,StringBuilder和StringBuffer基本相似,两个类的构造器和方法也基本相同。不同的是:StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高。
结论
在字符串不经常发生变化的业务场景优先使用String(代码更清晰简洁)。如常量的声明,少量的字符串操作(拼接,删除等)。
在单线程情况下,如有大量的字符串操作情况,应该使用StringBuilder来操作字符串。不能使用String"+"来拼接而是使用,避免产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。如JSON的封装等。
在多线程情况下,如有大量的字符串操作情况,应该使用StringBuffer。如HTTP参数解析和封装等。
9、Java开发设计——七大原则
(1)开闭原则(Open Closed Principle,OCP):当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性。
(2)里氏替换原则(Liskov Substitution Principle,LSP):主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。里氏替换原则是实现开闭原则的重要方式之一。
(3)依赖倒置原则(Dependence Inversion Principle,DIP):高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。
依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
(4)单一职责原则(Single Responsibility Principle,SRP):单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。核心就是控制类的粒度大小、将对象解耦、提高其内聚性。
(5)接口隔离原则(Interface Segregation Principle,ISP):要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。其目的为了约束接口、降低类对接口的依赖性。
(6)迪米特法则(Law of Demeter,LoD):只与你的直接朋友交谈,不跟“陌生人”说话。其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。法则中的“朋友”是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。
(7)合成复用原则(Composite Reuse Principle,CRP):要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
总结
这7种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同:
◆ 开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭。
◆ 里氏替换原则告诉我们不要破坏继承体系。
◆ 依赖倒置原则告诉我们要面向接口编程。
◆ 单一职责原则告诉我们实现类要职责单一。
◆ 接口隔离原则告诉我们在设计接口的时候要精简单一。
◆ 迪米特法则告诉我们要降低耦合度。
◆ 合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。
Java泛型
1、引入泛型的主要目标有以下几点
· 类型安全
- 泛型的主要目标是提高 Java 程序的类型安全
- 编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException 异常
- 符合越早出错代价越小原则
· 消除强制类型转换
- 泛型的一个附带好处是,使用时直接得到目标类型,消除许多强制类型转换
- 所得即所需,这使得代码更加可读,并且减少了出错机会
· 潜在的性能收益
- 由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改
- 所有工作都在编译器中完成
- 编译器生成的代码跟不使用泛型(和强制类型转换)时所写的代码几乎一致,只是更能确保类型安全而已
2、泛型的使用方式
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
类型参数的意义是告诉编译器这个集合中要存放实例的类型,从而在添加其他类型时做出提示,在编译时就为类型安全做了保证。
这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
3、泛型的通配符
(1)上界通配符 < ? extends E>
在类型参数中使用 extends 表示这个泛型中的参数必须是 E 或者 E 的子类,这样有两个好处:
如果传入的类型不是 E 或者 E 的子类,编辑不成功
泛型中可以使用 E 的方法,要不然还得强转成 E 才能使用
< ? extends E> 用于灵活读取,使得方法可以读取 E 或 E 的任意子类型的容器对象。
如果参数化类型表示一个 T 的生产者,使用 < ? extends T>;
(2)下界通配符 < ? super E>
在类型参数中使用 super 表示这个泛型中的参数必须是 E 或者 E 的父类。
< ? super E> 用于灵活写入或比较,使得对象可以写入父类型的容器,使得父类型的比较方法可以应用于子类对象。
如果它表示一个 T 的消费者,就使用 < ? super T>;
如果既是生产又是消费,那使用通配符就没什么意义了,因为你需要的是精确的参数类型。
简而言之,为了获得最大限度的灵活性,要在表示生产者或者消费者的输入参数上使用通配符,使用的规则就是:生产者有上限、消费者有下限:PECS: producer-extends, costumer-super
Java集合
- ArrayList和LinkedList的区别
·两者区别:
(1)ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表结构。
(2)对于随机访问get和set方法,ArrayList要优于LinkedList,因为LinkedList要移动指针。
(3)对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。
·两者性能上的缺点
(1)对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
(2)在ArrayList集合中添加或者删除一个元素时,当前的列表所所有的元素都会被移动。而LinkedList集合中添加或者删除一个元素的开销是固定的。
(3)LinkedList集合不支持高效的随机访问(RandomAccess),因为可能产生二次项的行为(需要首先遍历一遍链表才知道你所要)。
(4)ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
2、HashMap(数组+链表+红黑树)
HashMap根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。HashMap最多只允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。大方向上,HashMap里面是一个数组,然后数组中每个元素是一个单向链表,Entry包含四个属性:key,value,hash值和用于单向链表的next。
1.capacity:当前数组容量,始终保持2^n,可以扩容,扩容后数组大小为当前的2倍。
2.oadFactor:负载因子,默认为0.75。
3.threshold:扩容的阈值,等于capacity*loadFactor
Java8对HashMap进行了一些修改,最大的不同就是利用了红黑树,所以其由数组+链表+红黑树组成。根据Java7HashMap的介绍,可以知道在查找的时候,根据hash值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度为O(n)。为了降低这部分的开销,在Java8中,当链表中的元素超过了8个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为O(logN)。
3、HashTable(线程安全)
Hashtable是遗留类,很多映射的常用功能与HashMap类似,不同的是它承自Dictionary类,并且是线程安全的,任一时间只有一个线程能写Hashtable,并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。Hashtable不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换
4、HashMap和HashTable的区别
(1) 两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全。Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步。
(2) HashMap是允许key和value为null值的,用containsValue和containsKey方法判断是否包含对应键值对;HashTable键值对都不能为空,否则报空指针异常。
(3) HashMap继承AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。
(4) HashMap的初始容量为16,Hashtable初始容量为11,HashMap哈希扩容必须要求为原容量的2倍,而且一定是2的幂次倍扩容结果,而且每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入;而Hashtable扩容为原容量2倍加1;
(5) 解决hash地址冲突方式不同:在Java8中HashMap出现地址冲突时,如果冲突数量小于8,则是以链表方式解决冲突,而当冲突大于等于8时,就会将冲突的Entry转换为红黑树进行存储,而又当数量小于6时,则又转化为链表存储;而HashTable都是以链表方式存储。
5、说说ConcurrentHashMap
在JDK1.7版本中,ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成,Segment数组的意义就是将一个大的table分割成多个小的table来进行加锁,也就是锁分离技术,而每一个Segment元素存储的是HashEntry数组+链表,这个和HashMap的数据存储结构一样。
Segment实现了ReentrantLock,也就带有锁的功能,当执行put操作时,会进行第一次key的hash来定位Segment的位置,如果该Segment还没有初始化,即通过CAS(比较并交换) 操作进行赋值,然后进行第二次hash操作,找到相应的HashEntry的位置,这里会利用继承过来的锁的特性,在将数据插入指定的HashEntry位置时(链表的尾端),会通过继承ReentrantLock的tryLock()方法尝试去获取锁,如果获取成功就直接插入相应的位置,如果已经有线程获取该Segment的锁,那当前线程会以自旋的方式去继续的调用tryLock方法去获取锁,超过指定次数就挂起,等待唤醒。
ConcurrentHashMap的get操作跟HashMap类似,只是ConcurrentHashMap第一次需要经过一次hash定位到Segment的位置,然后再hash定位到指定的HashEntry,遍历该HashEntry下的链表进行对比,成功就返回,不成功就返回null。
JDK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS(比较并交换) 来操作,整个看起来就像是优化过且线程安全的HashMap,虽然在JDK1.8中还能看到Segment的数据结构,但是已经简化了属性,只是为了兼容旧版本。
当执行put操作时,如果没有hash冲突就直接CAS(比较并交换) 插入,如果存在hash冲突,就加锁来保证线程安全,这里有两种情况,一种是链表形式就直接遍历到尾端插入,一种是红黑树就按照红黑树结构插入,最后一个如果Hash冲突时会形成Node链表,在链表长度超过8,Node数组超过64时会将链表结构转换为红黑树的结构,break再一次进入循环,如果添加成功就调用addCount()方法统计size,并且检查是否需要扩容。
当执行get操作时计算hash值,定位到该table索引位置,如果是首节点符合就返回,如果遇到扩容的时候,会调用标志正在扩容节点ForwardingNode的find方法,查找该节点,匹配就返回;都不符合的话,就往下遍历节点,匹配就返回,否则最后就返回null。
JDK1.8使用内置锁synchronized来代替重入锁ReentrantLock,在大量的数据操作下,对于JVM的内存压力,基于API的ReentrantLock会开销更多的内存,而synchronized优化空间更大,使用内嵌的关键字比使用API更加自然。
6、Collection包结构,与Collections的区别
(1)Collection是集合类的上级接口,其意义是为各种具体的集合提供了最大化的统一操作方式,子接口有Set、List、LinkedList、ArrayList、Vector、Stack;
(2)Collections是集合类的一个帮助类,它包含有各种有关集合操作的静态多态方法,用于实现对各种集合的搜索、排序、线程安全化等操作。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
7、泛型
早期Java是使用Object来代表任意类型的,但是向下转型有强转的问题,这样程序就不太安全。首先,我们来试想一下:没有泛型,集合会怎么样Collection、Map集合对元素的类型是没有任何限制的。本来我的Collection集合装载的是全部的Dog对象,但是外边把Cat对象存储到集合中,是没有任何语法错误的。
把对象扔进集合中,集合是不知道元素的类型是什么的,仅仅知道是Object。因此在get()的时候,返回的是Object。外边获取该对象,还需要强制转换
有了泛型以后:
代码更加简洁【不用强制转换】
程序更加健壮【只要编译时期没有警告,那么运行时期就不会出现ClassCastException异常】
可读性和稳定性【在编写集合的时候,就限定了类型】
8、说说List,Set,Map三者的区别
List , Set, Map都是接口,前两个继承至Collection接口,Map为独立接口
Set下有HashSet,LinkedHashSet,TreeSet
List下有ArrayList,LinkedList,Vector
Map下有HashMap,Hashtable,LinkedHashMap,TreeMap
Collection接口下还有个Queue接口,有PriorityQueue类
9、Array与ArrayList有什么不一样?
(1)使用Array时必须指定数组的数据类型及数组长度,即数组中存放的元素个数固定并且类型相同。ArrayList是动态数组,长度动态可变,会自动扩容。不使用泛型的时候,可以添加不同类型元素。
(2)效率:效率上Array>ArrayList,原因自然在于ArrayList动态扩容造成了效率损耗
10、Map有什么特点
map集合特点就是采用了Key-value键值对映射的方式进行存储,key在Map里面是唯一的但是value可重复,一个key对应一个value。key是无序、唯一的,value是无序不唯一的
11、集合类存放于Java.util包中,主要有几种接口
主要包含set(集)、list(列表)和map(映射)。
(1)Collection:Collection是集合List、Set、Queue的最基本的接口。
(2)Iterator:迭代器,可以通过迭代器遍历集合中的数据
(3)Map:是映射表的基础接口
12、什么是list接口
(1)List接口是Collection接口的子类;
(2)它是一个元素存取有序的集合(不是正序和倒序的,是怎么存就怎么取);
(3)它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组中的索引是一个道理);
(4)集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素;
(5)常用的子类有:ArrayList集合、LinkedList集合。
13、说说ArrayList(数组)
ArrayList是一个其容量能够动态增长的动态数组。它继承了AbstractList,实现了List、RandomAccess,Cloneable,java.io.Serializable。基本的ArrayList,擅长于随机访问元素,但是在List中间插入和移除元素时较慢。同时,ArrayList的操作不是线程安全的!一般在单线程中才使用ArrayList,而在多线程中一般使用Vector或者CopyOnWriteArrayList。
14、说说LinkList(链表)
LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用
15、什么Set集合
Set注重独一无二的性质,该体系集合用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。对象的相等性本质是对象hashCode值(java是依据对象的内存地址计算出的此序号)判断的,如果想要让两个不同的对象视为相等的,就必须覆盖Object的hashCode方法和equals方法。
JDK1.8新特性
①引入了lambda表达式,可以简化匿名内部类的代码,允许将方法作为参数。
②方法引用,可以进一步简化lambda表达式的书写,可以引用类的构造方法,静态方法,特定类的方法和某个对象的方法。
③可以在接口中使用default定义默认方法和静态方法,引入默认方法方便了接口升级的维护,之前如果在接口中新增一个方法必须修改所有实现类。
④引入了stream类,支持链式编程,为集合类和数组提供了一些方便的操作方法,例如filter、skip、limit和map、concat等。
⑤可以通过类型自动推测泛型参数。
⑥允许重复使用注解,扩大了注解的使用范围,可以用在局部变量和泛型,方法异常上。
⑦引入了Optional类解决空指针异常,更新了日期类的API等。
Java反射
1、除了使用new创建对象之外,还可以用什么方法创建对象?
使用Java反射可以创建对象!
2、Java反射创建对象效率高还是通过new创建对象的效率高?
通过new创建对象的效率比较高。通过反射时,先找查找类资源,使用类加载器创建,过程比较繁琐,所以效率较低
3、java反射的作用
反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
4、哪里会用到反射机制?
jdbc就是典型的反射
Class.forName('com.mysql.jdbc.Driver.class');//加载MySQL的驱动类
- 反射的实现方式:
第一种:通过Object类的getClass方法,如
Foo foo=new Foo();
Class cla=foo.getClass();
第二种:通过对象实例方法获取对象,如Class cla=Foo.class;
第三种(最常用):通过Class.forName方式,如Class cla=Class.forName("xx.xx.Foo");
6、反射机制的优缺点:
优点:运行期类型的判断,动态加载类,提高代码灵活度。
缺点:a.性能瓶颈:反射相当于一系列解释操作,通知JVM要做的事情,性能比直接的java代码要慢很多。
b.相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
解决方案:
i、通过setAccessible(true)关闭JDK的安全检查来提升反射速度;
ii、多次创建一个类的实例时,有缓存会快很多
iii、ReflectASM工具类,通过字节码生成的方式加快反射速度
Java序列化
1、什么是java序列化,如何实现java序列化?
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implementsSerializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Objectobj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
2、序列化对象以字节数组保持-静态成员不保存
使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
3、Serializable实现序列化
在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。
通过ObjectOutputStream和ObjectInputStream对对象进行序列化及反序列化。
4、writeObject和readObject自定义序列化策略
在类中增加writeObject和readObject方法可以实现自定义序列化策略。
5、Transient关键字阻止该变量被序列化到文件中
a.在变量声明前加上Transient关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient变量的值被设为初始值,如int型的是0,对象型的是null。
b.服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可对密码进行读取,这样可一定程度保证序列化对象的数据安全。
Java中IO和NIO
1、Java中IO流分为几种?
a.按功能来分:输入流(input)、输出流(output)。
b.按类型来分:字节流和字符流。
字节流和字符流的区别:
字节流按8位传输以字节为单位输入输出数据,字符流按16位传输以字符为单位输入输出数据。
UTF-8方式编码的字符,一个英文字符需要一个字节,一个中文需要三个字节。
字节数据是二进制形式的,要转成我们能识别的正常字符,需要选择正确的编码方式。我们生活中遇到的乱码问题就是字节数据没有选择正确的编码方式来显示成字符。
从本质上来讲,写数据(即输出)的时候,字节也好,字符也好,本质上都是没有标识符的,需要去指定编码方式。
但读数据的时候,如果需要去“看数据”,那么字节流的数据需要指定字符编码方式,这样我们才能看到我们能识别的字符;而字符流,因为已经选择好了字符编码方式,通常不需要再改了(除非定义的字符编码方式与数据原有的编码方式不一致!)
在传输方面上,由于计算机的传输本质都是字节,而一个字符由多个字节组成,转成字节之前先要去查表转成字节,所以传输时有时候会使用缓冲区。
扩展:
(1)InputStream/Reader:所有的输入流的基类,前者是字节输入流,后者是字符输入流。
(2)OutputStream/Writer:所有输出流的基类,前者是字节输出流,后者是字符输出流。
2、什么是NIO?
NIO即NewIO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在JavaAPI中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区),Selector(选择区)。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。NIO和传统IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。
3、NIO的缓冲区
Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。NIO的缓冲导向方法不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
4、NIO的非阻塞
IO的各种流是阻塞的。这意味着,当一个线程调用read()或write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
4、JavaIO与NIO的区别
a.面向流与面向缓冲
b.阻塞与非阻塞IO
c.NIO选择器(Selectors)
5、NIO和IO适用场景
NIO是为弥补传统IO的不足而诞生的,但是尺有所短寸有所长,**NIO也有缺点,因为NIO是面向缓冲区的操作,每一次的数据处理都是对缓冲区进行的,那么就会有一个问题,在数据处理之前必须要判断缓冲区的数据是否完整或者已经读取完毕,如果没有,假设数据只读取了一部分,那么对不完整的数据处理没有任何意义。**所以每次数据处理之前都要检测缓冲区数据。 那么NIO和IO各适用的场景是什么呢? 如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,这时候用NIO处理数据可能是个很好的选择。而如果只有少量的连接,而这些连接每次要发送大量的数据,这时传统的IO更合适。使用哪种处理数据,需在数据的响应等待时间和检查缓冲区数据的时间上作比较来权衡选择。
6、常用io类有哪些
字符流常用底层类:
FileReader、FileWriter,
BufferedReader、BufferedWriter,区别为缓存机制;
字节流常用底层类:
FileInputStream、FileOutputStream,
BufferedInputStream、BufferedOutputStream,区别为缓存机制。
字符流,字节流转换类:
InputStreamReader、OutputStreamWriter,本身属于字符流体系,通过传入字节流和字符编码通过构造方法创建字符流实例。
7、阻塞IO模型
最传统的一种IO模型,即在读写数据过程中会发生阻塞现象。当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。典型的阻塞IO模型的例子为:data=socket.read();如果数据没有就绪,就会一直阻塞在read方法
8、非阻塞IO模型
当用户线程发起一个read操作后,并不需等待,而是马上就得到一个结果。如果结果是一个error时,它就知道数据还没准备好,于是它可以再次发送read操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。所以事实上,在非阻塞IO模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞IO不会交出CPU,而会一直占用CPU。
典型的非阻塞IO模型一般如下:
while(true){
data=socket.read();
if(data!=error){
//处理数据
break;
}}
但是对于非阻塞IO就有一个非常严重的问题,在while循环中需要不断地去询问内核数据是否就绪,这样会导致CPU占用率非常高,因此一般情况下很少使用while循环这种方式来读取数据。
9、多路复用IO模型
多路复用IO模型是目前使用得比较多的模型。JavaNIO实际上就是多路复用IO。在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。在JavaNIO中,是通过selector.select()去查询每个通道是否有到达事件,如果没有事件,则一直阻塞在那里,因此这种方式会导致用户线程的阻塞。多路复用IO模式,通过一个线程就可以管理多个socket,只有当socket真正有读写事件发生才会占用资源来进行实际的读写操作。因此,多路复用IO比较适合连接数比较多的情况。
另外多路复用IO为何比非阻塞IO模型的效率高是因为在非阻塞IO中,不断地询问socket状态时通过用户线程去进行的,而在多路复用IO中,轮询每个socket状态是内核在进行的,这个效率要比用户线程要高的多。
不过要注意的是,多路复用IO模型是通过轮询的方式来检测是否有事件到达,并且对到达的事件逐一进行响应。因此对于多路复用IO模型来说,一旦事件响应体很大,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询。
Java异常
1、Java中异常分为哪两种?
编译时异常,运行时异常
2、异常的处理机制有几种?
异常捕捉:try…catch…finally,异常抛出:throws。
3、如何自定义一个异常
继承一个异常类,通常是RuntimeException或者Exception
4、try...catch...finally,try里有return,finally还执行么?
执行,并且finally的执行早于try里面的return
结论:
(1)不管有没有出现异常,finally块中代码都会执行;
(2)当try和catch中有return时,finally仍然会执行;
(3)finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,仍是之前保存的值),所以函数返回值是在finally执行前确定的;
(4)finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
5、Excption与Error包结构
Java可抛出(Throwable)的结构分为三种类型:被检查的异常(CheckedException),运行时异常(RuntimeException),错误(Error)。
- uncheckedExceptions运行时异常
定义:RuntimeException及其子类都被称为运行时异常。
特点:Java编译器不会检查它。也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。该异常在开发中测试功能时会导致程序终止,控制台出现的异常,比如: NullPointerException(空指针异常)
IndexOutOfBoundsException(下标越界异常) ClassCastException(类转换异常) ArrayStoreException(数据存储异常,操作数组时类型不一致) IO操作的BufferOverflowException异常
- checkedExceptions非运行时异常(编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。通俗的话说就是在写代码时出现红线,需要trycatch或者throws时出现的异常。
- Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时JVM(Java虚拟机)出现的问题。例如,Java虚拟机运行错误(VirtualMachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
6、thow与thorws区别
(1)throws出现在方法函数头;而throw出现在函数体。
(2)throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常。
(3)两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。。
7、Error与Exception区别?
(1)Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
(2)Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
(3)Exception类又分为运行时异常(RuntimeException)和受检查的异常(CheckedException),运行时异常;ArithmaticException,IllegalArgumentException,编译能通过,但是一运行就终止了,程序不会处理运行时异常,出现这类异常,程序会终止。而受检查的异常,要么用try...catch捕获,要么用throws字句声明抛出,交给它的父类处理,否则编译不会通过。
Java WEB
- 说下原生jdbc操作数据库流程?
第一步:Class.forName()加载数据库连接驱动;
第二步:DriverManager.getConnection()获取数据连接对象;
第三步:根据SQL获取sql会话对象,有2种方式Statement、PreparedStatement;
第四步:执行SQL处理结果集,执行SQL前如果有参数值就设置参数值setXXX();
第五步:关闭结果集、关闭会话、关闭连接
2.什么要使用PreparedStatement?
(1)PreparedStatement接口继承Statement,PreparedStatement实例包含已编译的SQL语句,所以其执行速度要快于Statement对象。
(2)作为Statement的子类,PreparedStatement继承了Statement的所有功能。三种方
法execute、executeQuery和executeUpdate已被更改以使之不再需要参数
(3)在JDBC应用中,在任何时候都不要使用Statement,原因如下:
·代码的可读性和可维护性Statement需要不断地拼接,而PreparedStatement不会。
·PreparedStatement尽最大可能提高性能DB有缓存机制,相同的预编译语句再次被调用不会再次需要编译。
·最重要的一点是极大地提高了安全性Statement容易被SQL注入,而PreparedStatementc传入的内容不会和sql语句发生任何匹配关系。
3.关系数据库中连接池的机制是什么?
前提:为数据库连接建立一个缓冲池。
(1)从连接池获取或创建可用连接
(2)使用完毕之后,把连接返回给连接池
(3)在系统关闭前,断开所有连接并释放连接占用的系统资源
(4)能够处理无效连接,限制连接池中的连接总数不低于或者不超过某个限定值。
其中有几个概念需要大家理解:
最小连接数是连接池一直保持的数据连接。如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费掉。
最大连接数是连接池能申请的最大连接数。如果数据连接请求超过此数,后面的数据连接请求将被加入到等待队列中,这会影响之后的数据库操作。
如果最小连接数与最大连接数相差太大,那么,最先的连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,它将被放到连接池中等待重复使用或是空闲超时后被释放。
上面的解释,可以这样理解:数据库池连接数量一直保持一个不少于最小连接数的数量,当数量不够时,数据库会创建一些连接,直到一个最大连接数,之后连接数据库就会等待。
4.http的长连接和短连接
HTTP协议有HTTP/1.0版本和HTTP/1.1版本。HTTP1.1默认保持长连接(HTTPpersistent
connection,也翻译为持久连接),数据传输完成了保持TCP连接不断开(不发RST包、不四次握手),等待在同域名下继续用这个通道传输数据;相反的就是短连接。
在HTTP/1.0中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。从HTTP/1.1起,默认使用的是长连接,用以保持连接特性。
5.HTTP/1.1与HTTP/1.0的区别
(1)可扩展性
a)HTTP/1.1在消息中增加版本号,用于兼容性判断。
b)HTTP/1.1增加了OPTIONS方法,它允许客户端获取一个服务器支持的方法列表。
c)为了与未来的协议规范兼容,HTTP/1.1在请求消息中包含了Upgrade头域,通过该头域,客户端可以让服务器知道它能够支持的其它备用通信协议,服务器可以据此进行协议切换,使用备用协议与客户端进行通信。
(2)缓存
在HTTP/1.0中,使用Expire头域来判断资源的fresh或stale,并使用条件请求(conditional
request)来判断资源是否仍有效。HTTP/1.1在1.0的基础上加入了一些cache的新特性,当缓存对象的Age超过Expire时变stale对象,cache不需要直接抛弃stale对象,而是与源服务器进行重新激活(revalidation)。
(3)带宽优化
HTTP/1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了。例如,客户端只需要显示一个文档的部分内容,又比如下载大文件时需要支持断点续传功能,而不是在发生断连后不得不重新下载完整的包。
HTTP/1.1中在请求消息中引入了range头域,它允许只请求资源的某个部分。在响应消息中ContentRange头域声明了返回的这部分对象的偏移值和长度。如果服务器相应地返回了对象所请求范围的内容,则响应码为206(PartialContent),它可以防止Cache将响应误以为是完整的一个对象。另外一种情况是请求消息中如果包含比较大的实体内容,但不确定服务器是否能够接收该请求(如是否有权限),此时若贸然发出带实体的请求,如果被拒绝也会浪费带宽。
HTTP/1.1加入了一个新的状态码100(Continue)。客户端事先发送一个只带头域的请求,如果服务器因为权限拒绝了请求,就回送响应码401(Unauthorized);如果服务器接收此请求就回送响应码100,客户端就可以继续发送带实体的完整请求了。注意,HTTP/1.0的客户端不支持100响应码。但可以让客户端在请求消息中加入Expect头域,并将它的值设置为100-continue。
节省带宽资源的一个非常有效的做法就是压缩要传送的数据。Content-Encoding是对消息进行端到端(end-toend)的编码,它可能是资源在服务器上保存的固有格式(如jpeg图片格式);在请求消息中加入Accept-Encoding头域,它可以告诉服务器客户端能够解码的编码方式
(4)长连接
HTTP/1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求。此外,由于大多数网页的流量都比较小,一次TCP连接很少能通过slow-start区,不利于提高带宽利用率。
HTTP1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。例如:一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接。
HTTP1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间
(6)错误提示
HTTP/1.0中只定义了16个状态响应码,对错误或警告的提示不够具体。
HTTP/1.1引入了一个Warning头域,增加对错误或警告信息的描述。此外,在HTTP/1.1中新增了24个状态响应码,如409(Conflflict)表示请求的资源与资源的当前状态发生冲突;
410(Gone)表示服务器上的某个资源被永久性的删除
6.http常见的状态码有哪些?
200 OK //客户端请求成功
301 MovedPermanently(永久移除),请求的URL已移走。Response中应该包含一个Location
URL,说明资源现在所处的位置
302 found重定向
400 BadRequest //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 NotFound//请求资源不存在,eg:输入了错误的URL
500 InternalServerError//服务器发生不可预期的错误
503 ServerUnavailable//服务器当前不能处理客户端的请求,一段时间后可能恢复正常
7.GET和POST的区别?
从表面现像上面看GET和POST的区别:
GET在浏览器回退时是无害的,而POST会再次提交请求。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body
本质区别:
GET产生一个TCP数据包;POST产生两个TCP数据包。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次
8.http中重定向和请求转发的区别?
本质区别:转发是服务器行为,重定向是客户端行为。
重定向特点:两次请求,浏览器地址发生变化,可以访问自己web之外的资源,传输的数据会丢失。
请求转发特点:一次请求,浏览器地址不变,访问的是自己本身的web资源,传输的数据不会丢失
9.Cookie和Session的区别
Cookie是web服务器发送给浏览器的一块信息,浏览器会在本地一个文件中给每个web服务器存储cookie。以后浏览器再给特定的web服务器发送请求时,同时会发送所有为该服务器存储的cookie。
Session是存储在web服务器端的一块信息。session对象存储特定用户会话所需的属性及配置信息。当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下。
Cookie和session的不同点:
(1)无论客户端做怎样的设置,session都能够正常工作。当客户端禁用cookie时将无法使用cookie。
(2)在存储的数据量方面:session能够存储任意的java对象,cookie只能存储String类型的对象
11.在单点登录中,如果cookie被禁用了怎么办?
单点登录的原理是后端生成一个sessionID,然后设置到cookie,后面的所有请求浏览器都会带上cookie,然后服务端从cookie里获取sessionID,再查询到用户信息。所以,保持登录的关键不是cookie,而是通过cookie保存和传输的sessionID,其本质是能获取用户信息的数据。除了cookie,还通常使用HTTP请求头来传输。但是这个请求头浏览器不会像cookie一样自动携带,需要手工处理。
12.什么是jsp,什么是Servlet?jsp和Servlet有什么区别?
Jsp本质上就是一个Servlet,它是Servlet的一种特殊形式(由SUN公司推出),每个jsp页面都是一个servlet实例。
Servlet是由Java提供用于开发web服务器应用程序的一个组件,运行在服务端,由servlet容器管理,用来生成动态内容。一个servlet实例是实现了特殊接口Servlet的Java类,所有自定义的servlet均必须实现Servlet接口。
区别:
jsp是html页面中内嵌的Java代码,侧重页面显示;
Servlet是html代码和Java代码分离,侧重逻辑控制,mvc设计思想中jsp位于视图层,servlet位于控制层
JVM只能识别Java类,并不能识别jsp代码!web容器收到以.jsp为扩展名的url请求时,会将访问请求交给tomcat中jsp引擎处理,每个jsp页面第一次被访问时,jsp引擎将jsp代码解释为一个servlet源程序,接着编译servlet源程序生成.class文件,再有web容器servlet引擎去装载执行servlet程序,实现页面交互。
13.jsp有哪些域对象和内置对象及他们的作用?
(1)page当前页面,在当前jsp页面有效,跳到其它页面失效
(2)request一次请求范围内有效,从http请求到服务器处理结束,返回响应的整个过程。在这个过程中使用forward(请求转发)方式跳转多个jsp,在这些页面里你都可以使用这个变量
(3)session当前会话有效范围,浏览器从打开到关闭过程中,转发、重定向均可以使用
(4)application只能在同一个web中使用,服务器未关闭或者重启,数据就有效
14.什么是xml,使用xml的优缺点,xml的解析器有哪几种,分别有什么区别?
xml是一种可扩展性标记语言,支持自定义标签(使用前必须预定义)使用DTD和XMLSchema标准化XML结构
优点:用于配置文件,格式统一,符合标准;用于在互不兼容的系统间交互数据,共享数据方便;
缺点:xml文件格式复杂,数据传输占流量,服务端和客户端解析xml文件占用大量资源且不易维护
Xml常用解析器有2种,分别是:DOM和SAX;
主要区别在于它们解析xml文档的方式不同。使用DOM解析,xml文档以DOM树形结构加载入内存,而SAX采用的是事件模型,
15.谈谈你对ajax的认识?
Ajax是一种创建交互式网页应用的开发技术;AsynchronousJavaScriptandXML”的缩写。
Ajax的优势:
通过异步模式,提升了用户体验。
优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用。
Ajax引擎在客户端运行,承担了一部分本来由服务器承担的工作,从而减少了大用户量下的服务器负载。
Ajax的最大特点:
可以实现局部刷新,在不更新整个页面的前提下维护数据,提升用户体验度。
16.谈谈你对restful的理解以及在项目中的使用?
一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。REST指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。
它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
17.什么是webService?
WebService是一种跨编程语言和跨操作系统平台的远程调用技术。所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用其他编程语言编写,反之亦然!跨操作系统平台则是指服务端程序和户端程序可以在不同的操作系统上。
18.常见的远程调用技术
RMI是java语言本身提供的远程通讯协议,稳定高效,是EJB的基础。但它只能用于JAVA程序之间的通讯。
Hessian和Burlap是caucho公司提供的开源协议,基于HTTP传输,服务端不用开防火墙端口。协议的规范公开,可以用于任意语言。跨平台有点小问题。
Httpinvoker是SpringFramework提供的远程通讯协议,只能用于JAVA程序间的通讯,且服务端和客户端必须使用SpringFramework。
Webservice是连接异构系统或异构语言的首选协议,它使用SOAP形式通讯,可以用于任何语言,目前的许多开发工具对其的支持也很好。
效率相比:RMI>Httpinvoker>=Hessian>>Burlap>>webservice。