接口和抽象类的区别是什么?
java提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于:
接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
类可以实现很多个接口,但是只能继承一个抽象类
类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
抽象类可以在不提供接口方法实现的情况下实现接口。
java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。
接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。
1.abstract class 在 java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。
2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
7.接口中的方法默认都是 public,abstract 类型的。
java虚拟机是一个可以执行java字节码的虚拟机进程。java源文件被编译成能被java虚拟机执行的字节码文件。
java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。
java运行时环境(jre)是将要执行java程序的java虚拟机。它同时也包含了执行applet需要的浏览器插件。java开发工具包(jdk)是完整的java软件开发包,包含了jre,编译器和其他的工具(比如:javadoc,java调试器),可以让开发者开发、编译、执行java应用程序。
“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。
java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
关于覆盖的一些举例:
(1) 父类和子类中同名的静态类
class parent{
public static void fun(){
system.out.println("parent fun()");
}
}
class child extends parent{
system.out.println("child fun()");
结论:static方法不能被覆盖,父类和子类中允许有同样的static方法!
(2)父类和子类中同样的private方法
private void xun(){
system.out.println("parent xun()");
class child extends parent
system.out.println("child xun()");
结论:private方法不能被覆盖,父类和子类中允许有同样的private方法!
(3)父类中有public final方法gun(),子类中不能有同名同参的gun()方法
public final void gun(){
system.out.println("parent gun()");
public void gun(){
system.out.println("child gun()");
(4)这样写编译是没有错的
private final void gun(){
static变量在java中是属于类的,它在所有的实例中的值是一样的。当类被java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
java语言支持的8中基本数据类型是:
byte
short
int
long
float
double
boolean
char
自动装箱是java编译器在基本数据类型和对应的对象包装类型之间做的一个转化。比如:把int转化成integer,double转化成double,等等。反之就是自动拆箱。
java中的方法重载发生在同一个类里面两个或者是多个方法的方法名相同但是参数不同的情况。与此相对,方法覆盖是说子类重新定义了父类的方法。方法覆盖必须有相同的方法名,参数列表和返回类型。覆盖者可能不会限制它所覆盖的方法的访问。
java中类不支持多继承,只支持单继承(即一个类只有一个父类)。 但是java中的接口支持多继承,,即一个子接口可以有多个父接口。(接口的作用是用来扩展对象的功能,一个子接口继承多个父接口,说明子接口扩展了多个功能,当类实现接口时,类就扩展了相应的功能)。
对象被值传递,意味着传递了对象的一个副本。因此,就算是改变了对象副本,也不会影响源对象的值。
对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象所做的改变会反映到所有的对象上。
java线程
进程是执行着的应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程。进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;反之,线程是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。 进程,是并发执行的程序在执行过程中分配和管理资源的基本单位。
有三种方式可以用来创建线程:
继承thread类
实现runnable接口
应用程序可以使用executor框架来创建线程池
实现runnable接口这种方式更受欢迎,因为这不需要继承thread类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而java不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。
线程在执行过程中,可以处于下面几种状态:
就绪(runnable):线程准备运行,不一定立马就能开始执行。
运行中(running):进程正在执行线程的代码。
等待中(waiting):线程处于阻塞的状态,等待外部的处理结束。
睡眠中(sleeping):线程被强制睡眠。
i/o阻塞(blocked on i/o):等待i/o操作完成。
同步阻塞(blocked on synchronization):等待获取锁。
死亡(dead):线程完成了执行。
集合类接口指定了一组叫做元素的对象。集合类接口的每一种具体的实现类都可以选择以它自己的方式对元素进行保存和排序。有的集合类允许重复的键,有些不允许。
java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。java集合类里面最基本的接口有:
collection:代表一组对象,每一个对象都是它的子元素。
set:不包含重复元素的collection。
list:有顺序的collection,并且可以包含重复元素。
map:可以把键(key)映射到值(value)的对象,键不能重复。
克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。
iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。
下面列出了他们的区别:
iterator可用来遍历set和list集合,但是listiterator只能用来遍历list。
iterator对集合只能是前向遍历,listiterator既可以前向也可以后向。
listiterator实现了iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出concurrentmodificationexception异常,而安全失败的迭代器永远不会抛出这样的异常。
java中的hashmap是以键值对(key-value)的形式存储元素的。hashmap需要一个hash函数,它使用hashcode()和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,hashmap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。hashmap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。
java中的hashmap使用hashcode()和equals()方法来确定键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确的实现这两个方法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现对hashmap的精确性和正确性是至关重要的。
hashmap和hashtable都实现了map接口,因此很多特性非常相似。但是,他们有以下不同点:
hashmap允许键和值是null,而hashtable不允许键或者值是null。
hashtable是同步的,而hashmap不是。因此,hashmap更适合于单线程环境,而hashtable适合于多线程环境。
hashmap提供了可供应用迭代的键的集合,因此,hashmap是快速失败的。另一方面,hashtable提供了对键的列举(enumeration)。
一般认为hashtable是一个遗留的类。
在jdk中,查看集合有很多关于快速失败的描述:注意,此实现不是同步的。如果多个线程同时访问一个哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须 保持外部同步。(结构上的修改是指添加或删除一个或多个映射关系的任何操作;仅改变与实例已经包含的键关联的值不是结构上的修改。)在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器本身的 remove 方法,其他任何时间任何方式的修改,迭代器都将抛出 concurrentmodificationexception。因此,面对并发的修改,迭代器很快就会完全失败,而不冒在将来不确定的时间发生任意不确定行为的风险。快速失败:对于非并发集合来说,在其进行迭代时,例如iterator迭代时,iterator是另起一个线程,若有其他线程(如collection)进行结构修改(修改了增减了集合中的内容),这个迭代会马上感知到,并且立即抛出 concurrentmodificationexception 异常,而不是迭代完成后才告诉你出错了,引起快速失败。若用iterator进行修改则不会出现这个问题,如iterator.move();也就是说涉及到了多个线程间的同步问题。
下面列出了array和arraylist的不同点:
array可以包含基本类型和对象类型,arraylist只能包含对象类型。
array大小是固定的,arraylist的大小是动态变化的。
arraylist提供了更多的方法和特性,比如:addall(),removeall(),iterator()等等。
对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。
arraylist和linkedlist都实现了list接口,他们有以下的不同点:
arraylist是基于索引的数据接口,它的底层是数组。它可以以o(1)时间复杂度对元素进行随机访问。与此对应,linkedlist是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是o(n)。
相对于arraylist,linkedlist的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
linkedlist比arraylist更占内存,因为linkedlist为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
也可以参考arraylist vs. linkedlist。
java提供了只包含一个compareto()方法的comparable接口。这个方法可以个给两个对象排序。具体来说,它返回负数,0,正数来表明输入对象小于,等于,大于已经存在的对象。
java提供了包含compare()和equals()两个方法的comparator接口。compare()方法用来给两个输入参数排序,返回负数,0,正数表明第一个参数是小于,等于,大于第二个参数。equals()方法需要一个对象作为参数,它用来决定输入参数是否和comparator相等。只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果是相同的时候,这个方法才返回true。
大o符号描述了当数据结构里面的元素增加的时候,算法的规模或者是性能在最坏的场景下有多么好。
大o符号也可用来描述其他的行为,比如:内存消耗。因为集合类实际上是数据结构,我们一般使用大o符号基于时间,内存和性能来选择最好的实现。大o符号可以对大量数据的性能给出一个很好的说明。
hashset是由一个hash表来实现的,因此,它的元素是无序的。add(),remove(),contains()方法的时间复杂度是o(1)。
另一方面,treeset是由一个树形的结构来实现的,它里面的元素是有序的。因此,add(),remove(),contains()方法的时间复杂度是o(logn)。
垃圾收集器(garbage collectors)
垃圾回收的目的是识别并且丢弃应用不再使用的对象来释放和重用资源。
这两个方法用来提示jvm要进行垃圾回收。但是,立即开始还是延迟进行垃圾回收是取决于jvm的。
在释放对象占用的内存之前,垃圾收集器会调用对象的finalize()方法。一般建议在该方法中释放对象持有的资源。
不会,在下一个垃圾回收周期中,这个对象将是可被回收的。
当对象对当前使用这个对象的应用程序变得不可触及的时候,这个对象就可以被回收了。
jvm的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。它在jvm启动的时候被创建。对象所占的堆内存是由自动内存管理系统也就是垃圾收集器回收。
堆内存是由存活和死亡的对象组成的。存活的对象是应用可以访问的,不会被垃圾回收。死亡的对象是应用不可访问尚且还没有被垃圾收集器回收掉的对象。一直到垃圾收集器把这些对象回收掉之前,他们会一直占据堆内存空间。
java中有两种异常:受检查的(checked)异常和不受检查的(unchecked)异常。不受检查的异常不需要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并且不受检查的异常可以传播到方法或者是构造函数的外面。相反,受检查的异常必须要用throws语句在方法或者是构造函数上声明。这里有java异常处理的一些小建议。检查异常:(编译器必须处理的异常)除error,runtimeexception及其子类以外,其他的exception类及其子类都是检查异常。该异常特点是java编译器检查,即当程序中出现异常时,要么用try-catch语句捕获,要么用throws子句声明抛出,否则编译不通过。 非检查异常:(编译器不要求处置的异常),包括运行时异常(runtimeexception及其子类)和错误(error)
exception和error都是throwable的子类。exception用于用户程序可以捕获的异常情况。error定义了不期望被用户程序捕获的异常。
throw关键字用来在程序中明确的抛出异常,相反,throws语句用来表明方法不能处理的异常。每一个方法都必须要指定哪些异常不能处理,所以方法的调用者才能够确保处理可能发生的异常,多个异常是用逗号分隔的。
45.异常处理的时候,finally代码块的重要性是什么?(译者注:作者标题的序号弄错了)
无论是否抛出异常,finally代码块总是会被执行。就算是没有catch语句同时又抛出异常的情况下,finally代码块仍然会被执行。最后要说的是,finally代码块主要用来释放资源,比如:i/o缓冲区,数据库连接。
exception对象会在下一个垃圾回收过程中被回收掉。
无论是否抛出异常,finally代码块都会执行,它主要是用来释放应用占用的资源。finalize()方法是object类的一个protected方法,它是在对象被垃圾回收之前由java虚拟机来调用的。
java小应用程序(applet)
java applet是能够被包含在html页面中并且能被启用了java的客户端浏览器执行的程序。applet主要用来创建动态交互的web应用程序。
applet可以经历下面的状态:
init:每次被载入的时候都会被初始化。
start:开始执行applet。
stop:结束执行applet。
destroy:卸载applet之前,做最后的清理工作。
applet是运行在启用了java的浏览器中,java应用程序是可以在浏览器之外运行的独立的java程序。但是,它们都需要有java虚拟机。
进一步来说,java应用程序需要一个有特定方法签名的main函数来开始执行。java applet不需要这样的函数来开始执行。
最后,java applet一般会使用很严格的安全策略,java应用一般使用比较宽松的安全策略。
布局管理器用来在容器中组织组件。1,borderlayout 2,flowlayout 3,gridlayout 4,gridbaglayout 5,cardlayout 6,boxlayout
gridbaglayout里面的元素是按照网格进行布局的。不同大小的元素可能会占据网格的多于1行或一列。因此,行数和列数可以有不同的大小。
scrollbar是一个组件,不是容器。而scrollpane是容器。scrollpane自己处理滚动事件。
只有3个线程安全的方法: repaint(), revalidate(), and invalidate()。
canvas, frame, panel,和applet支持重绘。
frame类继承了window类,它定义了一个可以有菜单栏的主应用窗口。
事件监听器接口定义了对特定的事件,事件处理器必须要实现的方法。事件适配器给事件监听器接口提供了默认的实现。
gui组件可以处理它自己的事件,只要它实现相对应的事件监听器接口,并且把自己作为事件监听器。
java使用布局管理器以一种一致的方式在所有的窗口平台上摆放组件。因为布局管理器不会和组件的绝对大小和位置相绑定,所以他们能够适应跨窗口系统的特定平台的不同。
java中的swing组件使用了mvc(视图-模型-控制器)设计模式。
jdbc是允许用户在不同数据库之间做选择的一个抽象层。jdbc允许开发者用java写数据库应用程序,而不需要关心底层特定数据库的细节。
jdbc驱动提供了特定厂商对jdbc api接口类的实现,驱动必须要提供java.sql包下面这些类的实现:connection, statement, preparedstatement,callablestatement, resultset和driver。
class.forname("com.mysql.jdbc.driver"); //加载mysq驱动
conn = drivermanager.getconnection(url,user,password);
stmt = conn.createstatement();
类装载指通过解析类(或者接口)的字节码文件来构建代表这个类(或是这个接口)的实例的过程。有些像根据蓝图制作一个产品一样的概念。类装载有如下的两种方式:
//第1种方式
class c1 = class.forname (string classname);
//第2种方式
classloader cl = new classloader();
class c1 = cl.loadclass(string classname, boolean resolve );
其中,class.forname()完成了类装载、连接以及初始化(激活类的静态变量的初始化java代码和静态java代码块。)
在jdbc链接数据库中的应用
在jdbc中加载驱动类时(class.forname(“com.mysql.jdbc.driver”),如果换成getclass().getclassloader().loadclass(“com.mysql.jdbc.driver”),就不行,因为它只是向jvm装载了driver的类信息,但是并没有进行类的初始化,也就不能执行相应的操作,因为driver是需要被初始化才能使用的。
preparedstatements是预编译的,因此,性能会更好。同时,不同的查询参数值,preparedstatement可以重用。
string sql= "insert into user (name,pwd) values(?,?)"; //sql语句不再采用拼接方式,应用占位符问号的方式写sql语句。
ps=conn.preparestatement(sql); ps.setstring(1, user.getname()); ps.setstring(2, user.getpwd()); //对占位符设置值,占位符顺序从1开始,第一个参数是占位符的位置,第二个参数是占位符的值。
像打开关闭数据库连接这种和数据库的交互可能是很费时的,尤其是当客户端数量增加的时候,会消耗大量的资源,成本是非常高的。可以在应用服务器启动的时候建立很多个数据库连接并维护在一个池中。连接请求由池中的连接提供。在连接使用完毕以后,把连接归还到池中,以用于满足将来更多的请求。数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中, 这些数据库连接的数量是由最小数据库连接数来设定的.无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量.连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
参考:http://www.cnblogs.com/xdp-gacl/p/4002804.html
servlet是用来处理客户端请求并产生动态网页内容的java类。servlet主要是用来处理或者是存储html表单提交的数据,产生动态内容,在无状态的http协议下管理状态信息。
所有的servlet都必须要实现的核心的接口是javax.servlet.servlet。每一个servlet都必须要直接或者是间接实现这个接口,或者是继承javax.servlet.genericservlet或者javax.servlet.http.httpservlet。最后,servlet使用多线程可以并行的为多个请求服务。
applet是运行在客户端主机的浏览器上的客户端java程序。而servlet是运行在web服务器上的服务端的组件。applet可以使用用户界面类,而servlet没有用户界面,相反,servlet是等待客户端的http请求,然后为请求产生响应。
genericservlet是一个通用的协议无关的servlet,它实现了servlet和servletconfig接口。继承自genericservlet的servlet应该要覆盖service()方法。最后,为了开发一个能用在网页上服务于使用http协议请求的servlet,你的servlet必须要继承自httpservlet。
对每一个客户端的请求,servlet引擎载入servlet,调用它的init()方法,完成servlet的初始化。然后,servlet对象通过为每一个请求单独调用service()方法来处理所有随后来自客户端的请求,最后,调用servlet(译者注:这里应该是servlet而不是server)的destroy()方法把servlet删除掉。
doget:get方法会把名值对追加在请求的url后面。因为url对字符数目有限制,进而限制了用在客户端请求的参数值的数目。并且请求中的参数值是可见的,因此,敏感信息不能用这种方式传递。
dopost:post方法通过把请求参数值放在请求体中来克服get方法的限制,因此,可以发送的参数的数目是没有限制的。最后,通过post请求传递的敏感信息对外部客户端是不可见的。
web应用程序是对web或者是应用服务器的动态扩展。有两种类型的web应用:面向表现的和面向服务的。面向表现的web应用程序会产生包含了很多种标记语言和动态内容的交互的web页面作为对请求的响应。而面向服务的web应用实现了web服务的端点(endpoint)。一般来说,一个web应用可以看成是一组安装在服务器url名称空间的特定子集下面的servlet的集合。
servletrequest类可以找出客户端机器的ip地址或者是主机名。getremoteaddr()方法获取客户端主机的ip地址,getremotehost()可以获取主机名。
http响应由三个部分组成:
状态码(status code):描述了响应的状态。可以用来检查是否成功的完成了请求。请求失败的情况下,状态码可用来找出失败的原因。如果servlet没有返回状态码,默认会返回成功的状态码httpservletresponse.sc_ok。
http头部(http header):它们包含了更多关于响应的信息。比如:头部可以指定认为响应过期的过期日期,或者是指定用来给用户安全的传输实体内容的编码格式。如何在serlet中检索http的头部看这里。
主体(body):它包含了响应的内容。它可以包含html代码,图片,等等。主体是由传输在http消息中紧跟在头部后面的数据字节组成的。
抽象是把想法从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现细节来创建类。java支持创建只暴漏接口而不包含方法实现的抽象的类。这种抽象技术的主要目的是把类的行为和实现细节分离开。
抽象和封装是互补的概念。一方面,抽象关注对象的行为。另一方面,封装关注对象行为的细节。一般是通过隐藏对象内部状态信息做到封装,因此,封装可以看成是用来提供抽象的一种策略。
继承给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用行,也可以在不修改类的情况下给现存的类添加新特性。
多态是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上的操作可以应用到其他类型的值上面。或者这样理解, 指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。
<![if !supportlists]>1.<![endif]>可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
封装给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。在java当中,有3种修饰符:public,private和protected。每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。
下面列出了使用封装的一些好处:
通过隐藏对象的属性来保护对象内部的状态。
提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展。
禁止对象之间的不良交互提高模块化。
参考这个文档获取更多关于封装的细节和示例。
代码开发模块化,更易维护和修改。
代码复用。
增强代码的可靠性和灵活性。
增加代码的可理解性。
面向对象编程有很多重要的特性,比如:封装,继承,多态和抽象。
jsp隐含对象是页面中的一些java对象,jsp容器让这些java对象可以为开发者所使用。开发者不用明确的声明就可以直接使用他们。jsp隐含对象也叫做预定义变量。下面列出了jsp页面中的隐含对象:
application,page,request,response,session,exception,out,config,pagecontext
jsp技术中,scriptlet是嵌入在jsp页面中的一段java代码。scriptlet是位于标签内部的所有的东西,在标签与标签之间,用户可以添加任意有效的scriplet。
在jsp中scriptlet一共分为三种:
· <%%>:定义局部变量,编写语句
· <%!%>:定义全局变量,可以编写类、方法
· <%=%>:表达式输出,专门输出变量或一个具体值
jsp动作以xml语法的结构来控制servlet引擎的行为。当jsp页面被请求的时候,jsp动作会被执行。它们可以被动态的插入到文件中,重用javabean组件,转发用户到其他的页面,或者是给java插件产生html代码。下面列出了可用的动作:
jsp:include-当jsp页面被请求的时候包含一个文件。
jsp:usebean-找出或者是初始化javabean。
jsp:setproperty-设置javabean的属性。
jsp:getproperty-获取javabean的属性。
jsp:forward-把请求转发到新的页面。
jsp:plugin-产生特定浏览器的代码。
什么是jsp指令(directive)?jsp中有哪些不同类型的指令?
directive是当jsp页面被编译成servlet的时候,jsp引擎要处理的指令。directive用来设置页面级别的指令,从外部文件插入数据,指定自定义的标签库。directive是定义在 <%@ 和 %>之间的。下面列出了不同类型的directive:
包含指令(include directive):用来包含文件和合并文件内容到当前的页面。
页面指令(page directive):用来定义jsp页面中特定的属性,比如错误页面和缓冲区。
taglib指令: 用来声明页面中使用的自定义的标签库。
下面列出了使用jsp的优点:
jsp页面是被动态编译成servlet的,因此,开发者可以很容易的更新展现代码。
jsp页面可以被预编译。
jsp页面可以很容易的和静态模板结合,包括:html或者xml,也可以很容易的和产生动态内容的代码结合起来。
开发者可以提供让页面设计者以类xml格式来访问的自定义的jsp标签库。
开发者可以在组件层做逻辑上的改变,而不需要编辑单独使用了应用层逻辑的页面。
浏览器首先要请求一个以.jsp扩展名结尾的页面,发起jsp请求,然后,web服务器读取这个请求,使用jsp编译器把jsp页面转化成一个servlet类。需要注意的是,只有当第一次请求页面或者是jsp文件发生改变的时候jsp文件才会被编译,然后服务器调用servlet类,处理浏览器的请求。一旦请求执行结束,servlet会把响应发送给客户端。
jsp页面是一种包含了静态数据和jsp元素两种类型的文本的文本文档。静态数据可以用任何基于文本的格式来表示,比如:html或者xml。jsp是一种混合了静态内容和动态产生的内容的技术。
url编码是负责把url里面的空格和其他的特殊字符替换成对应的十六进制表示,反之就是解码。
sendredirect()方法会创建一个新的请求,而forward()方法只是把请求转发到一个新的目标上。重定向(redirect)以后,之前请求作用域范围以内的对象就失效了,因为会产生一个新的请求,而转发(forwarding)以后,之前请求作用域范围以内的对象还是能访问的。一般认为sendredirect()比forward()要慢。
http隧道是一种利用http或者是https把多种网络协议封装起来进行通信的技术。因此,http协议扮演了一个打通用于通信的网络协议的管道的包装器的角色。把其他协议的请求掩盖成http的请求就是http隧道。
cookie是web服务器发送给浏览器的一块信息。浏览器会在本地文件中给每一个web服务器存储cookie。以后浏览器在给特定的web服务器发请求的时候,同时会发送所有为该服务器存储的cookie。下面列出了session和cookie的区别:
无论客户端浏览器做怎么样的设置,session都应该能正常工作。客户端可以选择禁用cookie,但是,session仍然是能够工作的,因为客户端无法禁用服务端的session。
在存储的数据量方面session和cookies也是不一样的。session能够存储任意的java对象,cookie只能存储string类型的对象。
控制反转即ioc (inversion of control),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中。当spring容器启动后,spring容器初始化,创建并管理bean对象,以及销毁它。所以我们只需从容器直接获取bean对象就行,而不用编写一句代码来创建bean对象。这种现象就称作控制反转,即应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。虽然平时只需要按要求将bean配置到配置文件中,但是了解其实现过程对理解spring的实现原理是有好处的。
使用cookie 使用url重写 使用隐藏的表单域
一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。而web 应用程序是使用 http 协议传输数据的。 http 协议是 无状态 的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。要跟踪该会话,必须引入一种机制。cookie 和 session 就是这样的一种机制。
引导类加载器(bootstrap class loader):它用来加载 java 的核心库,是用原生代码来实现的
扩展类加载器(extensions class loader):它用来加载 java 的扩展库。
系统类加载器(system class loader):它根据 java 应用的类路径(classpath)来加载 java 类
tomcat为每个app创建一个loader,里面保存着此webapp的classloader。需要加载webapp下的类时,就取出classloader来使用
jvm classloader architecture :
a、bootstrap classloader/启动类加载器
主要负责jdk_home/lib目录下的核心 api 或 -xbootclasspath 选项指定的jar包装入工作.
b、extension classloader/扩展类加载器
主要负责jdk_home/lib/ext目录下的jar包或 -djava.ext.dirs 指定目录下的jar包装入工作
c、system classloader/系统类加载器
主要负责java -classpath/-djava.class.path所指的目录下的类与jar包装入工作.
d、 user custom classloader/用户自定义类加载器(java.lang.classloader的子类)
在程序运行期间, 通过java.lang.classloader的子类动态加载class文件, 体现java动态实时类装入特性.
1.指针
java语言让编程者无法找到指针来直接访问内存无指针,并且增添了自动的内存管理功能,从而有效地防止了c/c++语言中指针操作失误,如野指针所造成的系统崩溃。但也不是说java没有指针,虚拟机内部还是使用了指针,只是外人不得使用而已。这有利于java程序的安全。
2.多重继承
c++支持多重继承,这是c++的一个特征,它允许多父类派生一个类。尽管多重继承功能很强,但使用复杂,而且会引起许多麻烦,编译程序实现它也很不容易。java不支持多重继承,但允许一个类继承多个接口(extends+implement),实现了c++多重继承的功能,又避免了c++中的多重继承实现方式带来的诸多不便。
3.数据类型及类
java是完全面向对象的语言,所有函数和变量部必须是类的一部分。除了基本数据类型之外,其余的都作为类对象,包括数组。对象将数据和方法结合起来,把它们封装在类中,这样每个对象都可实现自己的特点和行为。而c++允许将函数和变量定义为全局的。此外,java中取消了c/c++中的结构和联合,消除了不必要的麻烦。
4.自动内存管理
java程序中所有的对象都是用new操作符建立在内存堆栈上,这个操作符类似于c++的new操作符。下面的语句由一个建立了一个类read的对象,然后调用该对象的work方法:
read r=new read();
r.work();
语句read r=new read();在堆栈结构上建立了一个read的实例。java自动进行无用内存回收操作,不需要程序员进行删除。而c十十中必须由程序贝释放内存资源,增加了程序设计者的负扔。java中当一个对象不被再用到时,无用内存回收器将给它加上标签以示删除。java里无用内存回收程序是以线程方式在后台运行的,利用空闲时间工作。
5.操作符重载
java不支持操作符重载。操作符重载被认为是c十十的突出特征,在java中虽然类大体上可以实现这样的功能,但操作符重载的方便性仍然丢失了不少。java语言不支持操作符重载是为了保持java语言尽可能简单。
6.预处理功能
java不支持预处理功能。c/c十十在编译过程中都有一个预编泽阶段,即众所周知的预处理器。预处理器为开发人员提供了方便,但增加丁编译的复杂性。java虚拟机没有预处理器,但它提供的引入语句(import)与c十十预处理器的功能类似。
7. java不支持缺省函数参数,而c十十支持
在c中,代码组织在函数中,函数可以访问程序的全局变量。c十十增加了类,提供了类算法,该算法是与类相连的函数,c十十类方法与java类方法十分相似,然而,由于c十十仍然支持c,所以不能阻止c十十开发人员使用函数,结果函数和方法混合使用使得程序比较混乱。
java没有函数,作为一个比c十十更纯的面向对象的语言,java强迫开发人员把所有例行程序包括在类中,事实上,用方法实现例行程序可激励开发人员更好地组织编码。
8. 字符串
c和c十十不支持字符串变量,在c和c十十程序中使用null终止符代表字符串的结束,在java中字符串是用类对象(strinr和stringbuffer)来实现的,这些类对象是java语言的核心,用类对象实现字符串有以下几个优点:
(1)在整个系统中建立字符串和访问字符串元素的方法是一致的;
(2)j3阳字符串类是作为java语言的一部分定义的,而不是作为外加的延伸部分;
(3)java字符串执行运行时检空,可帮助排除一些运行时发生的错误;
(4)可对字符串用“十”进行连接操作。
9. goto语句
“可怕”的goto语句是c和c++的“遗物”,它是该语言技术上的合法部分,引用goto语句引起了程序结构的混乱,不易理解,goto语句子要用于无条件转移子程序和多结构分支技术。鉴于以广理由,java不提供goto语句,它虽然指定goto作为关键字,但不支持它的使用,使程序简洁易读。
l0.类型转换
在c和c十十中有时出现数据类型的隐含转换,这就涉及了自动强制类型转换问题。例如,在c十十中可将一浮点值赋予整型变量,并去掉其尾数。java不支持c十十中的自动强制类型转换,如果需要,必须由程序显式进行强制类型转换。
11.异常
java中的异常机制用于捕获例外事件,增强系统容错能力
try{//可能产生例外的代码
}catch(exceptiontype name){
//处理
其中exceptiontype表示异常类型。而c++则没有如此方便的机制。