1. 继承和实现接口分别使用的是什么关键字?
继承:extends
接口:implements
2. Java语言中的import和c语言中include除了功能上有些相似还有什么区别?
Java有若干标准的包,为使用这些包里的类,要用import语句;import与C++的include不同之处在于:Java编译时不把import的文件插入到源程序,而是产生适当代码,在class文件运行,在需要时才被动态装入。
3. java语言中的注释有哪几种方式?
对于Java注释我们主要了解两种:
// 注释一行
/* ...... */ 注释若干行
但还有第三种,文档注释:
/** ...... */ 注释若干行,并写入 javadoc 文档
通常这种注释的多行写法如下:
/**
* .........
* .........
*/
4. 是不是所有的类都可以实例化?
在java中,对象都是以类的形式体现的。而类只是被定义好的模板,需要将类实例化才能使用类的函数与方法。举个例子:有个气球的类,要用这个类的话,就要实例化,类中只是定义了需要有的数据而没有给出具体的数据,实例化就是把具体数据给体现出来。
不能把一个抽象类中的对象实例化。抽象类必须被扩展,并且在抽象类中声明的方法在扩展的类中必须被重写,否则你的扩展类也必须声明为abstract。
5. 如何控制多个并发线程对共享数据的访问?
由于线程执行的计时是不确定的,我们需要小心,以控制线程对共享数据的访问。否则,多个并发线程会互相干扰对方的更改,从而损坏数据,或者其它线程也许不能及时看到对共享数据的更改。通过使用同步来保护对共享变量的访问,我们可以确保线程以可预料的方式与程序变量进行交互。每个 Java 对象都可以充当锁,synchronized 块可以确保一次只有一个线程执行由给定锁保护的synchronized 代码。要跨线程维护正确的可见性,只要在几个线程之间共享非 final 变量,就必须使用 synchronized(或 volatile)以确保一个线程可以看见另一个线程做的更改。
可见性同步的基本规则是在以下情况中必须同步:
· 读取上一次可能是由另一个线程写入的变量
· 写入下一次可能由另一个线程读取的变量
要使多个线程在一个程序中有用,它们必须有某种方法可以互相通信或共享它们的结果。让线程共享其结果的最简单方法是使用共享变量。它们还应该使用同步来确保值从一个线程正确传播到另一个线程,以及防止当一个线程正在更新一些相关数据项时,另一个线程看到不一致的中间结果。有关两个关键字:synchronized 和volatile以及java锁。
6. 用两种方法截取java的后面两个字符va
举例:也就是一个字符串str,我想得到str.substring(0, 10); 只要不将汉字截成两半就可以了! 在JAVA中 String和Char是UNICODE的,不会出现汉字被截成两半的现象。
str.substring()
Str.getBytes()
示例一:
String s = "中文加English+,.,.,。///、全角和半角...;'-=";
int x = s.length();
for(int i=1;i<=x;i++){
System.out.println(s.substring(0,i));
}
示例二:
开发中经常遇到,字符串过长,无法完全显示的问题。这时候就需要截取我们所需要的长度,后面显示省略号或其他字符。由于中文字符占两个字节,而英文字符占用一个字节,所以,单纯地判断字符数,效果往往不尽如人意。下面的方法通过判断字符的类型来进行截取,效果还算可以:)
**********************************************************************
private String str;
private int counterOfDoubleByte;
private byte b[];
/**
* 设置需要被限制长度的字符串
* @param str 需要被限制长度的字符串
*/
public void setLimitLengthString(String str){
this.str = str;
}
/**
* @param len 需要显示的长度(<font color="red">注意:长度是以byte为单位的,一个汉字是2个byte</font>)
* @param symbol 用于表示省略的信息的字符,如“...”,“>>>”等。
* @return 返回处理后的字符串
*/
public String getLimitLengthString(int len, String symbol) throws UnsupportedEncodingException {
counterOfDoubleByte = 0;
b = str.getBytes("gb2312");
if(b.length <= len)
return str;
for(int i = 0; i < len; i++){
if(b < 0)
counterOfDoubleByte++;
}
if(counterOfDoubleByte % 2 == 0)
return new String(b, 0, len, "gb2312") + symbol;
else
return new String(b, 0, len - 1, "gb2312") + symbol;
}
7. 怎么实例化内部类,例如现在有类A,类B是它的内部类?
Java内部类(Inner Class)
类成员有两种static , non-static,同样内部类也有这两种:
Ø non-static内部类的实例,必须在外部类的事例中创建或通过外部类的实例来创建OuterClassInstanceName.new innerClassName(),并且可直接访问外部类的信息,外部类对象可通过OuterClassName.this来引用
Ø static 内部类的实例, 直接创建即可,没有对外部类实例的引用。
Ø 内部类不管static还是non-static都有对外部类的引用.
Ø non-static内部类不允许有static成员
Ø
方法中的内部类只允许访问方法中的final局部变量和方法的final参数列表,所以说方法中的内部类和内部类没什麽区别。但方法中的内部类不能在方法以外访问
方法中不可以有static内部类
Ø 匿名内部类如果继承自接口,必须实现指定接口的方法,且无参数
Ø 匿名内部类如果继承自类,参数必须按父类的构造函数的参数传递.
示例:
class OuterClass{
static class A{//静态内部类
public A( ){
System.out.println("Test$A !");
}
}
class B{//非静态内部类
public B(){
System.out.println("Test$B !");
}
}
public void disp( ) {
final int a=10; int b;
class C{ //成员函数中的局部内部类
public C( ) {
System.out.println(“in class C a="+a);
//System.out.println(b);
}
}
C c=new C( );
}
}
public class Test extends OuterClass
{
public static void main(String args[])
{
OuterClass.A a=new OuterClass.A(); //建立静态内部类对象
B b=new OuterClass( ).new B();
//建立非静态内部类的对象
//注意这个OuterClass().new B();相当于生成一个外部类的对象,然后在利用外部类对象生成内部类对象
OuterClass t=new OuterClass( );
t.disp( );
//通过外部对象调用一个对象方法的形式,新建立了对象C.
}
}
注意在上面的b在运行时会为0,因为是类属性.
class OuterClass
{
static class A { } //静态内部类
class B { } //非静态内部类
public void disp( )
{
class C{ } //局部内部类
}
}
编译后的将产生下面的一些类文件:
OuterClass.class
OuterClass$A.class
OutClass$B.class
OuterClass$1$C.class
记住以下几句话:
Ø 一个内部类的对象能够访问创建它的外部类对象的所有属性及方法(包括私有部分)。
//可以闭上眼镜,把这个内部类等同于一个类的一个方法,当然就可以访问这个外部类的
//所有方法和属性,私有方法和属性是属于外部类的,当然也就等同于内部类的.
Ø 对于同一个包中的其它类来说,内部类能够隐藏起来。(将内部类用private修饰即可)
//只有在内部类中,才能定义一个为private类型的class,因为这时编译器已经把这个类看作这个类的成员了,但是在一般使用时,就是所谓的”顶级类时”,不能使用private,只能是public 或者是friendly. 如果要是想保证一个类不产生任何的对象,请在构造函数中,把构造函数声明成private.
Ø 内部类可定义在方法中,称为局部内部类,但它只能使用方法中的final常量。
// 定义在一个方法内的类,又被成为局部内部类,这个类只能使用在方法中的final常量,注意,这个常量是在一个方法中的,那么能否使用一个类中的常量呢? 当然是可以的,因为类中的常量在在一个方法中是可见的.
Ø 内部类可以被定义为抽象类
// abstract 类同样可以在内部类中
Ø 非静态内部类不能声明本类的static成员
//只有一个静态的内部类,才可以声明一个static成员
8. 简要介绍private,protected,public三个关键字定义的变量有何区别?
Ø public、protected和private可以用来修饰类成员变量、方法、构造方法和内部类;
Ø public可以用来修饰顶级类,但protected和private则不行。
Ø 类成员访问控制可见下表:
| Private成员 | 默认成员 | Protected成员 | Public成员 |
同一类中可见 | 是 | 是 | 是 | 是 |
同一包中对子类可见 | 否 | 是 | 是 | 是 |
同一包中对非子类可见 | 否 | 是 | 是 | 是 |
不同包中对子类可见 | 否 | 否 | 是 | 是 |
不同的包中对非子类可见 | 否 | 否 | 否 | 是 |
简单总结一下,(按它们的访问范围由大到小排列):
public: 任何地方均可访问
protected:同一包和子类可见
默认: 同一包中可见
private: 仅该类内部可见
Ø this:
Java中定义了this关键字来访问当前对象实例内的成员。当局部变量和类实例内的类变量同名时,在这个局部变量所作用区域内类变量就被隐藏了,必须使用this来指明。
Ø static:
有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象。通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它所在类使用,而不必引用所在类的实例。将类中的成员声明为static就能实现这样的效果。声明为static的变量实质就是全局变量。当声明一个对象(某个类的实例)时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。
声明为static的方法有以下三条限制:
* 它们只能访问static数据
* 它们仅能调用其他的static方法
* 它们不能以任何方式引用this或super
Ø final:
一个变量可以被声明为final,这样做的目的是阻止它的内容被修改。这意味着在声明final变量的时候,你必须初始化它。一个final变量实质上是一个常数,为final变量的所有字母选择大写是一个普遍的编码约定。声明为final的变量在实例中不占用内存。
声明成final的方法不能被重载。通常,Java在运行时动态的调用方法,这叫做后期绑定(late binding);由于被声明为final的方法不能被重载,那么对final方法的调用可以在编译时解决,这叫做早期绑定(early bingding)。
声明为final的类不能被其他类继承。声明一个final类含蓄的宣告了它的所有方法也都是final的。所以,声明一个既是abstract的,又是final的类是不合法的,因为抽象类本身是不完整的,它依靠它的子类提供完整的实现。
Ø strictfp:
Java2向Java语言增加了一个新的关键字strictfp。与Java2同时产生的浮点运算计算模型很轻松的使某些处理器可以以较快速度进行浮点运算(例如奔腾处理器)。这个浮点运算计算模型在计算过程中,不需要切断某些中介值。如果用strictfp来修饰类或方法,可以确保浮点运算(以及所有切断)正如它们在早期Java版本中那样准确(即使用原始的浮点运算模型)。切断只影响某些操作的指数。当一个类被strictfp修饰,所有该类的方法都自动被strictfp修饰。坦白说,很多程序员从未用过strictfp,因为它只对非常少的问题有影响。
Ø native:
有时你希望调用不是用Java语言写的子程序,或者你希望调用一个专用的第三方的库,例如统计学包。虽然这种情况比较少,但Java提供了native关键字,该关键字用来声明本机代码方法。
9. extends关键字可以继承多个类吗?Implements可以实现多个接口吗?
Extends不能继承多个类,但是implements可以实现多个接口
java没有多继承,用接口来实现多继承的功能。所谓的接口,实际上也是一个类,只是在接口中声明了一组常量和方法,但事实上没有实现任何方法。这有点类似抽象类,接口需要其他类来提供实现自己所定义方法的过程,而不是自己提供。
示例:
public class ShowTestItem extends JScrollPane implements ItemListener,MouseListener,ActionListener{ //但是不知道这个接口的作用!
JPanel jPanel1 = new JPanel();
VerticalFlowLayout verticalFlowLayout1 = new VerticalFlowLayout();
public int countItems;
.............
.............
public void itemStateChanged(ItemEvent evt){
Object source =evt.getSource();
if(source instanceof JCheckBox){
Object newSource =evt.getItem();
}
}
...............
}
10. 下面语句是当a等于0的时候打印HELLO WORLD!,看看有没有问题
if(a=0){System.out.println("HELLO WORLD!");}
有问题:
a=0错误,不能从 int 转换为 boolean
应该改为a==0
11. 启动线程的方法是start(),还是run()?
java语言已经内置了多线程支持,所有实现Runnable接口的类都可被启动一个新线程,新线程会执行该实例的run()方法,当run()方法执行完毕后,线程就结束了。一旦一个线程执行完毕,这个实例就不能再重新启动,只能重新生成一个新实例,再启动一个新线程。
Thread类是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法:
Thread t = new Thread();
t.start();
start()方法是一个native方法,它将启动一个新线程,并执行run()方法。Thread类默认的run()方法什么也不做就退出了。注意:直接调用run()方法并不会启动一个新线程,它和调用一个普通的java方法没有什么区别。
因此,有两个方法可以实现自己的线程:
方法1:自己的类extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:
public class MyThread extends Thread {
public run() {
System.out.println("MyThread.run()");
}
}
在合适的地方启动线程:new MyThread().start();
方法2:如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口:
public class MyThread extends OtherClass implements Runnable {
public run() {
System.out.println("MyThread.run()");
}
}
为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:
MyThread myt = new MyThread();
Thread t = new Thread(myt);
t.start();
事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:
public void run() {
if (target != null) {
target.run();
}
}
12. 怎么才能让一段语句在抛异常和不抛异常的情况下都能被执行到?
Java的异常处理是通过5个关键字来实现的:try,catch,throw,throws,finally。JB的在线帮助中对这几个关键字是这样解释的:
Throws: Lists the exceptions a method could throw.
Throw: Transfers control of the method to the exception handler.
Try: Opening exception-handling statement.
Catch: Captures the exception.
Finally: Runs its code before terminating the program.
Ø try语句
try语句用大括号{}指定了一段代码,该段代码可能会抛出一个或多个例外。
Ø
catch语句
catch语句的参数类似于方法的声明,包括一个例外类型和一个例外对象。例外类型必须为Throwable类的子类,它指明了catch语句所处理的例外类型,例外对象则由运行时系统在try所指定的代码块中生成并被捕获,大括号中包含对象的处理,其中可以调用对象的方法。catch语句可以有多个,分别处理不同类的例外。Java运行时系统从上到下分别对每个catch语句处理的例外类型进行检测,直到找到类型相匹配的catch语句为止。这里,类型匹配指catch所处理的例外类型与生成的例外对象的类型完全一致或者是它的父类,因此,catch语句的排列顺序应该是从特殊到一般。也可以用一个catch语句处理多个例外类型,这时它的例外类型参数应该是这多个例外类型的父类,程序设计中要根据具体的情况来选择catch语句的例外处理类型。
Ø
finally语句
try所限定的代码中,当抛出一个例外时,其后的代码不会被执行。通过finally语句可以指定一块代码。无论try所指定的程序块中抛出或不抛出例外,也无论catch语句的例外类型是否与所抛出的例外的类型一致,finally所指定的代码都要被执行,它提供了统一的出口。通常在finally语句中可以进行资源的清除工作。如关闭打开的文件等。
Ø
throws语句
throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常。对大多数Exception子类来说,Java 编译器会强迫你声明在一个成员函数中抛出的异常的类型。如果异常的类型是Error或 RuntimeException,或它们的子类,这个规则不起作用,因为这在程序的正常部分中是不期待出现的。如果你想明确地抛出一个RuntimeException,你必须用throws语句来声明它的类型。
Ø
throw语句
throw总是出现在函数体中,用来抛出一个异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
13. final类可不可以被继承?
Ø 在类的声明中使用final
使用了final的类不能再派生子类,就是说不可以被继承了。有些java的面试题里面,问String可不可以被继承。答案是不可以,因为java.lang.String是一个final类。这可以保证String对象方法的调用确实运行的是String类的方法,而不是经其子类重写后的方法。
Ø 在方法声明中使用final
被定义为final的方法不能被重写了,如果定义类为final的话,是所有的方法都不能重写。而我们只需要类中的某几个方法,不可以被重写,就在方法前加final了。而且定义为final的方法执行效率要高的啊。
Ø 在变量声明中使用final
这样的变量就是常量了,在程序中这样的变量不可以被修改的。修改的话编译器会抱错的。而且执行效率也是比普通的变量要高。final的变量如果没有赋予初值的话,其他方法就必需给他赋值,但只能赋值一次。
Ø 总结:
这个关键字并不是很难理解,final的英文意思是“最终的”。他修饰了什么东西都是最终的。不可以改变的。效率也比较高。通常在java的优化编程中往往会提及到这一点。
14. 类的main方法是如何声明的?
首先是main前面的单词,因为main方法是由java虚拟机调用的,所以必须为public,
又因为虚拟机调用main方法的时候不需要产生任何对象,所以声明为static ;
且不需要返回值,所以声明为void
所以最终为: public static void main(String[] args)
15. 单独出现super和this关键字分别是用来做什么的?
Ø Java关键字this只能用于方法方法体内。当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是this。因此,this只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现this。并且this只和特定的对象关联,而不和类关联,同一个类的不同对象有不同的this。
n 通过this调用另一个构造方法,用发是this(参数列表),这个仅仅在类的构造方法中,别的地方不能这么用。
n 函数参数或者函数中的局部变量和成员变量同名的情况下,成员变量被屏蔽,此时要访问成员变量则需要用“this.成员变量名”的方式来引用成员变量。当然,在没有同名的情况下,可以直接用成员变量的名字,而不用this,用了也不为错。
n 在函数中,需要引用该函所属类的当前对象时候,直接用this。
n 其实这些用法总结都是从对“this是指向对象本身的一个指针”这句话的更深入的理解而来的,死记不然容易忘记而且容易搞错,要理解!
Ø super关键和this作用类似,是被屏蔽的成员变量或者成员方法或变为可见,或者说用来引用被屏蔽的成员变量和成员成员方法。不过super是用在子类中,目的是访问直接父类中被屏蔽的成员,注意是直接父类(就是类之上最近的超类)。
n 在子类构造方法中要调用父类的构造方法,用“super(参数列表)”的方式调用,参数不是必须的。同时还要注意的一点是:“super(参数列表)”这条语句只能用在子类构造方法体中的第一行。
n 当子类方法中的局部变量或者子类的成员变量与父类成员变量同名时,也就是子类局部变量覆盖父类成员变量时,用“super.成员变量名”来引用父类成员变量。当然,如果父类的成员变量没有被覆盖,也可以用“super.成员变量名”来引用父类成员变量,不过这是不必要的。
n 当子类的成员方法覆盖了父类的成员方法时,也就是子类和父类有完全相同的方法定义(但方法体可以不同),此时,用“super.方法名(参数列表)”的方式访问父类的方法。
16. 当捕获到异常的时候用什么方法打印错误堆栈?
调用异常的对象的printStackTrace()方法,打印方法调用栈的异常信息。
示例:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class MainClass {
public static void main(String[] args) {
try {
File tempFile = File.createTempFile("myfile", ".tmp");
FileOutputStream fout = new FileOutputStream(tempFile);
PrintStream out = new PrintStream(fout);
out.println("some text");
} catch (IOException ex) {
System.out.println("There was a problem creating/writing to the temp file");
ex.printStackTrace();
}
}
}
17. 一个try模块是能对应多个catch模块还是只能对应一个?
catch语句可以有多个,用来匹配多个异常,结构如下:
try{
程序代码
}catch(异常类型1 异常的变量名1){
程序代码
}catch(异常类型2 异常的变量名2){
程序代码
}finally{
程序代码
}
18. 请说明循环中break和continue的区别?
break可以离开当前switch、for、while、do while的程序块,并前进至程序块后下一条语句,在switch中主要用来中断下一个case的比较。在for、while与do while中,主要用于中断目前的循环执行。
continue的作用与break类似,主要用于循环,所不同的是break会结束程序块的执行,而continue只会结束其之后程序块的语句,并跳回循环程序块的开头继续下一个循环,而不是离开循环。
19. 是不是每个类都有构造方法?那为什么经常看不到?
构造函数是和类同名的函数,没有返回类型,构造函数不能在普通的程序里面调用,只有当这个类被应用new实例化的时候才会被运行。构造函数没有返回类型,实际上,构造函数返回的就是这个class本身。
如果类没有构造方法呢?在这种情况下,一个缺省的构造方法(也叫"无参构造方法")由java编译器自动生成。缺省构造方法只有在类没有任何其它的构造方法时才产生。
“什么是对父类的构造方法的隐含调用”。这意味着如果你的构造方法的第一行不是下面内容之一:
super();
super(args);
this();
this(args);
则有下面的调用:
super();
提供给构造方法的第一行。
示例:
public class Sample {
private int x;
public Sample() { // 不带参数的构造方法
this(1);
}
public Sample(int x) { //带参数的构造方法
this.x=x;
}
public int Sample(int x) { //不是构造方法
return x++;
}
}
20. 一个类可不可以有多个构造方法?这些方法有和区别?
可通过重载构造方法来表达对象的多种初始化行为。在一个类的多个构造方法中,可能会出现一些重复操作。为了提高代码的可重用性,Java语言允许在一个构造方法中,用this语句来调用另一个构造方法。
21. java中所有类的父类是哪个类?
java.lang.Object
22. jsp生命周期分为哪几步?
解释和编译的工作完成之后,JSP的生命周期将分为三个阶段:
◆装载和实例化:服务端为JSP页面查找已有的实现类,如果没找到则创建新的JSP页面的实现类,然后把这个类载入JVM。在实现类装载完成之后,JVM将创建这个类的一个实例。这一步会在装载后立刻执行,或者在第一次请求时执行。
◆初始化:初始化JSP页面对象。如果你希望在初始化期间执行某些代码,那么你可以向页面中增加一个初始化方法(method),在初始化的时候就会调用该方法。
◆请求处理:由页面对象响应客户端的请求。需要注意的是,单个对象实例将处理所有的请求。在执行完处理之后,服务器将一个响应(response)返回给客户端。这个响应完全是由HTML标签和其他数据构成的,并不会把任何Java源码返回给客户端。
◆生命周期终止:服务器不再把客户端的请求发给JSP。在所有的请求处理完成之后,会释放掉这个类的所有实例。一般这种情况会发生在服务器关闭的时候,但是也有其他的可能性,比如服务器需要保存资源、检测到有JSP文件更新,或者由于其他某些原因需要终止实例等情况。如果想让代码执行清除工作,那么可以实现一个方法,并且在这个类实例释放之前调用该方法。本章随后一节“处理JSP的初始化和终止”将对此加以讨论。
在第6章中,你将看到Servlet的生命S周期和JSP的生命周期是一样的。这是因为容器把JP转化为Servlet;而JSP页面实现类就是一个Servlet类。图3ˉ1说明了JSP生命周期中处理请求的过程。
当客户端发送一个JSP的访问请求时,Web服务器会把这个请求转发给JSP容器,然后JSP容器将决定由哪个JSP页面实现类来处理这个请求。然后,JSP容器调用JSP页面实现类的一个方法对这个请求进行处理,并且通过容器和Web服务器把响应返回给客户端。通常,这个过程可以简单说成“向JSP发送一个请求”。
|
图3ˉ1 JSP源文件被编译成JSP页面实现类。服务器收到一个JSP的访问请求后,把这个请求发到容器,然后容器再把这个请求传递给相应的JSP。产生的响应则按相反的路径返回给客户端 |
23. ajax主要是针对什么问题提出的?
Ajax 由 HTML、JavaScript™ 技术、DHTML 和 DOM 组成,这一杰出的方法可以将笨拙的 Web 界面转化成交互性的 Ajax 应用程序。
下面是 Ajax 应用程序所用到的基本技术:
- HTML 用于建立 Web 表单并确定应用程序其他部分使用的字段。
- JavaScript 代码是运行 Ajax 应用程序的核心代码,帮助改进与服务器应用程序的通信。
- DHTML 或 Dynamic HTML,用于动态更新表单。我们将使用 div、span 和其他动态 HTML 元素来标记 HTML。
- 文档对象模型 DOM 用于(通过 JavaScript 代码)处理 HTML 结构和(某些情况下)服务器返回的 XML。
Ajax,使用它可以构建更为动态和响应更灵敏的Web应用程序。该方法的关键在于对浏览器端的JavaScript、DHTML和与服务器异步通信的组合。术语Ajax用来描述一组技术,它使浏览器可以为用户提供更为自然的浏览体验。在Ajax之前,Web站点强制用户进入提交/等待/重新显示范例,用户的动作总是与服务器的“思考时间”同步。Ajax提供与服务器异步通信的能力,从而使用户从请求/响应的循环中解脱出来。借助于Ajax,可以在用户单击按钮时,使用JavaScript和DHTML立即更新UI,并向服务器发出异步请求,以执行更新或查询数据库。当请求返回时,就可以使用JavaScript和CSS来相应地更新UI,而不是刷新整个页面。最重要的是,用户甚至不知道浏览器正在与服务器通信:Web站点看起来是即时响应的。