java程序员面试宝典1

java基础知识

java开发环境

JRE和JDK的区别?各自的作用

分析:JRE:Java Runtime Environment的缩写,是java程序运行环境
JDK:Java Development Kit,是java的开发工具包,包含了各种类库,同时也包含JRE,具备开发功能的JDK所包含的JRE同时有client的JVM和server的JVM,而仅仅作为运行环境的JRE下只有client的jvm.dll就够了。
JDK需要进行环境变量的配置,JRE安装时会自动经JRE的java.exe添加到系统变量Path中。
【答案】
JDK是java开发工具,不仅提供了java程序运行所需要的JRE,还提供了一系列的编译、运行等工具,如javac java javaw等。JRE只是java程序的运行环境,其最核心的内容就是JVM(java虚拟机)及核心类库。

如何用JDK编译和运行应用程序

编译:javac,将源码编译为class文件
运行:java,运行包含主方法的class文件
注意 需要将JDK的安装目录/bin配置到Path环境变量中

环境变量ClassPath的作用

ClassPath环境变量是用来指定java程序搜索类的路径的,对于java应用程序来说,该变量的意义是非常重要的。
CLASSPATH环境变量在编译java源码和运行程序是使用,也就是为java程序所依赖的接口、类等指定一个搜索路径。
例如:.;c:\jar\logj4.jar;d:\work\java 指定了三个搜索路径,分别为:当前目录、logj4.jar文件的路径和d:\work\java文件夹下的所有的类。在java程序编译和运行时,不仅会在CLASSPATH中搜索类,还会在JRE的目录下去找一个名为rt.jar的文件,器路径为jre/lib/rt.jar。并且 会先搜索rt.jar 再搜索CLASSPATH指定的目录

如何为java程序动态指定类搜索路径

JDK中的java和javac命令提供了 cp 和 classpath 选项为java程序动态指定类搜索路径。如
javac -cp D:\work\java\logj3.jar HelloWorld.java
或者 java -cp D:\work\java\logj3.jar HelloWorld.java
cp 也可以用classpath代替

java和c++程序在编译和运行有什么区别

C++源码编译以后生成的特定机器可以直接运行的文件,而java编码经过编译后生成的中间字节码文件,这些字节码文件需要放到JVM中运行,而JVM是有多个平台版本的所以说java鱼油跨平台性。
java是解释型语言 c++是编译性语言

什么是JVM及其工作原理

JVM是一种用软件模拟出来的计算机,用于执行java程序编译后生成的中间字节码文件,是java跨平台的依赖基础。java虚拟机有自己想象的硬件,如处理器、堆栈、寄存器等,还具有相应的指令系统,它运行java程序好像一台计算机运行C++或C程序一样,它屏蔽底层系统实现的细节。

java程序为何无须使用delete语句进行内存回收

JVM在内存存储对象的原理:java除了8中基本类型外,其他的类型都是对象类型的数据。JVM会把程序中的对象放在堆空间。
堆是一个运行时的数据存储区,一般,运行时的数据存储区包含堆和堆栈,栈中存放非static的自动变量、函数参数、表达式的临时结果和函数返回值。栈中的这些实体数据的分配和释放都是由系统自行完成的。堆中存放的实体数据都是程序中由程序员显示分配的,没有自动垃圾回收机制的系统必须由程序员显式释放这些实体。
JVM具有垃圾回收机制,也就是堆内存的管理的自动运行。—提出:如何确定对象已经回收?
java中根父类java.lang.Object中有个finalize()方法,它会在垃圾回收期认为这个对象是垃圾的之后,真正回收之前被调用。因为所有的类都继承自OBject,所以它们都会有finalize()方法。所以程序员可以在这个方法中实现一些对象被回收之前的事,如关闭数据库连接等,finalize()方法的原型为
protected void finalize()throws Throwable
另外java.lang.System类中有一个gc()方法,也对垃圾回收有一定的影响。通过显式的调用它可以请求开始垃圾回收线程,开始垃圾回收,但是垃圾回收线程是否立即开始还是有JVM算法决定。
java,kabg.Runtime类中gc()方法与System的作用一样,只不过是Runtime是一个单例模式的类,需要用getRunTime()方法先获得实例,然后调用gc方法
【答案】
java的堆内存的数据释放功能由垃圾回收器自动完成,无需程序员显式的调用delete方法。该机制有效的避免了程序员因忘记释放内存而造成的内存溢出的错误,是一项改进。

生成、部署

如何利用命名提示符把java程序打包成jar文件

【分析】
jar文件是java程序打包以后的格式文件,它一般保存的有class文件、配置文件等。jar文件的主要是方便程序的发布和部署。

jar {c t x u f } [v m e 0 M i][-c 目录] 文件名...

{ctxuf}必选其一[vmeOMi]可选其一
【答案】
利用JDK的bin目录下的jar命令就可以对java程序进行打包,一般需要包含程序所需要的class文件、配置文件和manifest.mf文件。其中C -V 和 -f三个命令较为常见(创建、生成详细报告、指定jar包的文件名)

jar cf test.jar 
创建并生成 test.jar

关于java web项目的生成、部署和配置问题

一个标准的java web应用程序的规范包括:目录结构、web配置文件、打包和部署、Servlet JSP 等
文件夹的目录机构必须包含一个WEB-INF目录(classes、lib)以及Web描述文件web.xml;与WEB-INF同一层的目录存放的是JSP、HTML等文件。
Web配置文件定力了Servlet、过滤器、监听器和一些参数信息。
Servlet是服务器端处理HTTP请求的基本组成单元,包括JSP、过滤器等在内的许多技术都基于Servlet实现。Servlet是符合一定规范的Java类,存活在Web容器中,由容器来控制Servlet的生命周期。
JSP是参考其他动态语言而设计,脚本语言就是java,但是本质也是Servlet,它比其他动态语言更加强大,严格意义来说,熟悉JSP开发,并意味值熟悉Java Web开发,只能说是使用动态语言开发Web乘车,JSP作为Java Web开发是不可或缺的一部分,在大多数的开发中,它往往是用于显示处理后的结果。
打包与部署:web应用程序也可以打包,只是后缀是War,与jar打包原理一样,都可以通过JDK提供的jar命令进行打包。
部署:将java Web应用程序的文件夹或打包文件放在Tomcat的安装目录项/webapps下面即可完成部署
【答案】
java Web应用程序的生成、需要把它所需要的class文件编译好存放在WEB-INF/classes下,然后按照以上介绍的目录结构放置各类文件,如果需要添加自己的配置,需要增加或修改WEB-INF/web.xml文件。对于JAVA WEB应用程序的部署,可以使用文件夹夏河War文件两种部署方式,其中War就是把文件夹按照jar的方法进行打包,只不过后缀为War。

EJB项目的生成和部署

【答案】
EJB项目的生成过程主要有两个步骤:编译class文件和特定位置中存放配置文件,例如:对于EJB 3.0程序的JPA,就需要在META-INF文件夹下存放持久化的配置文件persistence.xml。部署的过程也比较简单,就hi把打包好的jar文件或未打包的文件夹存放在java EE服务器指定的路径下即可。

Java语法基础

基础类型和语法

变量及其作用范围

【答案】
静态变量:由类决定
成员变量:由对象决定
局部变量:定义在方法中的变量、方法的参数或代码块里定义的变量,作用范围用{}来界定
局部变量不能与上一层局部变量同名会编译错误
局部变量可以与成员变量和静态变量重名,此时如果想要调用成员变量使用this指针,使用静态变量可以使用类名。

java变量分哪两种大的数据类型

基本数据类型:直接存放数据的值:byte char short int long float double boolean
引用数据类型:存放数据所在的地址

class Student{
    public String name;
    public int age;
    public Student(String name,int age){
        this.name = name;
        this.age = age;    
    }
}
public class RefTest{
    private static void refChange(Student stu){
        stu.name = "wang";
        stu.age = 10;    
    }
    public static  void main(String[] args){
        Student stu1 = new Student("zhang",12);
        Student stu2 = stu1;
        refChange(stu2);
        System.out.println(stu1.name+","+stu1.age);//wang,10;
        即stu1 和 stu2指向的是同一个地址,所以改变stu2,stu1也会跟着改变。   
    }
}

java中的基本类型和包装类

byte char int short long float double boolean
Byte Character Integer Short Long Float Double Boolean

java中的装箱和拆箱

java 5.0 提供了自动装箱和拆箱的功能,可以使用以下语句进行打包基本类型
Integer integer = 10;
【答案】
java中的装箱和拆箱指的是基本数据类型和包装类型的自动相互转换,它为开发者提供了方便。开发人员也可以不使用它,而手动的进行数据类型转换。并且,这个自动转换的过程是在编译阶段。

java的引用和C++的指针有什么区别

【分析】
+ 类型:引用其值为地址的数据元素,java封装了的地址可以转换成字符串看,长度可以不用关心。C++指针是一个装地址的变量,长度一般是计算机字长,可以认为是个int
+ 所占内存:引用声明是没有实体,不占空间。c++指针如果声明后会到用时餐赋值,不用则不会分配内存。
+ 初始值:引用的初始值 null,指针初始值不固定所以比较危险
+ 计算:引用是不可以计算的。C++指针是int,可以计算
+ 控制:引用不可以计算,所以它只能在自己程序中,可以被控制。C++指针是可以计算,所以比较危险
+ 内存泄露:java引用不会产生内存泄露,c++指针容易产生
+ 作为参数:java的方法参数只是传值,引用作为参数是,返回给函数内引用的值的拷贝,所以在喊内交换两个引用是没有意义的,但是改变引用的属性是有用的,因为拷贝和引用的引用对象是同一个对象。

【答案】
java的易用与C++指针主要有类型、所占内存、内存泄露、初始值、计算和控制以及作为参数8个方面。本质上,它们两者都是想通过一个叫做引用或者指针的东西,找到要操作的目标,方便在程序中操作。java中的引用更加安全一些。

简述java中的main方法

public static void main(String[] args)
【答案】
main()方法是java程序的执行入口,它是一个定义在类中的、公开的、静态的、无返回值的、参数为一个字符串数组的方法,它的参数args与执行参数一一对应。

java中的equal和==的区别

【答案】
equal和== 都表示相等的意义
== 运用在基本数据类型比较时,比较的是实际的值,当用于比较引用类型是,则比较两个引用的地址是否相等
equal 方法是java.lang.Object的方法,可以被程序员覆盖重写通过自定义的方式来判断两个对象是否相等,对于字符串java.lang.String类来说,它的equal方法用来比较字符串的字符序列是否完全相等。

java中提供几种循环结构?各自的特点

for,适合循环次数的循环结构
while 适合单条件的循环
do while 适合在执行某段代码之后,再循环的时候更适合一些。

三元操作符

注释

// /* / /* */

对象和类型

类和对象有什么区别

java的类通过class关键字进行定义,它代表了一种抽象的集合
对象,指的是某一个特定抽象的实例,它属于某一种类型

java中如何使用继承来重写代码

【答案】
java采用的是单继承机制,使用extend关键字。通过继承以后,子类就拥有了父类除了私有成员以外的所有成员,从而达到代码重用的目的。在继承过程中,可以通过方法的覆盖来实现多态,让子类拥有自己独特的方法实现方式。

简述java中的多态

【答案】
多态 一词按照字面意思是来理解为“多种形式,多种状态”。它的本质是,发送消息给某个对象。让该对象自行决定响应何种行为。通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。

介绍java中静态成员的特点

静态成员是一组比较特殊的成员,它不属于某个特定的类的实例,而是属于一个类所有,这个类的所有实例可以共享他们。在类加载时,就进行创建好初始化或执行代码。对于一个类来说,都只有一份

简述java派生类中的构造方法如何为父类传递参数

在java中,使用super关键字加括号()的形式来为父类的构造方法提供参数,通过参数的数据和类型来决定调用哪一个构造方法。如果调用的是父类的默认的无参数构造方法,则可不必显式地使用 super()

简述接口与抽象类的区别

【答案】
抽象类是一种功能不全的类,接口只是一个抽象方法声明和静态不能被修改的数据的集合,两者都不能被实例化。从某种意义上说,接口是一种特殊形式的抽象类,在java中,抽象类表示一种继承关系,一个类只能继承一个抽象类,而一个类可以实现多个接口。
抽象类中不仅有方法,还可以成员变量,抽象类中也可以有非抽象方法,包含抽象方法的类一定是抽象类,抽象类不能被实例化
接口中的所有方法都是抽象方法,但是可不必显式用abstract 定义,只能包含静态变量,并且这些变量的值不可修改。

简述内部类的实质

【分析】
内部类的含义:内部类就像一只寄生虫一样,寄生于其他类的内部。缩小了可见性。
内部类的分类:局部式和成员式。成员内部类指的是它们定义的的地方与成员变量和成员方法类型,就好像是类的一个成员一样。局部式内部类则是定义在方法体中,仅属于局部范围所有。
成员式内部类又分为:静态内部类和成员内部类。
局部式内部类又分为:普通局部式和匿名内部类。
【答案】
静态内部类:相当于外部类的静态成员一样,使用static修饰的内部类,它隶属于外部类,使用起来相当于一个独立的外部类。
成员内部类:相当于外部类的普通成员一样,隶属于外部类的具体事例,在定义时,需要先创建外部类的对象,再创建它的实例。
局部内部类:定义在一个方法体中,它往往仅作为方法短暂的使用,只能访问用final修饰的局部变量。
匿名内部类:它也定义在方法体中,但是它没有一个具体的名字,具有非常大的灵活性,工作本质与局部内部类类似。

包和访问控制

包应该如何被创建及使用

包是java程序中关于命名空间的一种手段,它可以有效的解决类重名的问题。当需要把一个类定义在某个包下的时候,需要使用package关键字进行定义;当需要使用其他包下的类的时候,则需要使用import关键字进行导入。

寿命private、protected、public和default的区别

     类内部     本包      子类       外部包

public y y y y
protected y y y n
default y y n n
private y n n n

数据类型及类型转换

整型数据

int和Integer的区别

【分析】
int通过new 包装类或静态的valueOF方法转换成包装类–装箱
Integer通过调用intValue方法转换为int类型—拆箱
【答案】
int是基础类型,字节长度为4,它的创建不会在堆内存中开辟空间,一般保存在栈中,可以进行算术运算,在参数传递时,直接传递它的值。
Integer是int的包装类,本质是一个类。它的创建会在堆中开辟一块新的空间。不能进行算术操作。传参时传递的是它所代表的对象的一个引用。

int的取值范围

-2^31 – (2^31-1)

如何使用八进制和十六进制数来表示整型数据

【答案】java中八进制以0开头,十六进制以0x开头

long的取值范围

-2^61 — (2^61-1)

实型数据

float和double的取值范围

float:3.4E+10^-38 — 3.4E+10^38
double:1.7E+10^-308 — 1.7E+10^308
小数默认是 double,所以float需要显式定义:float i= 2.3f;而不是 float i= 2.3;

实型与整型的转换

如何使用BigDecimal类进行精确运算

【答案】
1 用float或double变量构建BigDecimal对象,通过构造方法或者valueOf方法
2 通过调用BigDecimal的加、减、乘法、除法等。
3 把BigDecimal对象转换为float int等基本类型,是使用xxxValue()等方法

布尔型数据

java中可以使用非0代表true吗?

【答案】不能,java中非0不能代表true,只能使用布尔型的true和false进行条件判断。

boolean和Boolean的区别

【答案】
1 boolean是基础数据类型,Boolean是包装类
2 boolean一般存放在栈中,Boolean存放在堆中
3 boolean有true和false两种值,Boolean还有null

字符串数据

char 的取值范围

java中的char采用Unicode编码格式,用两个字节表示一个字符,16位。所能表示的最大数量为2^16

char能否存放汉字

char可以存放汉字,每个汉字都有相应的Unicode,而char是用Unicode表示的,所以可以表示汉字。

如何使用转义字符

使用反斜杠”\”字符 一起构成转义字符 \b \r回车 \n换行等

String类型

字符串可以使用+号,String类不能被继承

字符串变量是否自动生成一个String对象

【答案】可以。字符串类具有一定的特殊性,JVM在执行双引号操作符的时候,会自耦东创建一个String对象,并返回该对象的引用。

字符串对象池的作用是

使用双引号和new创建字符串对象的区别在于,前者在对象池中取对象,后者直接生成新对象。

String str1 = "abc";
String str2 = "abc";
str1 == str2//true;因为会先去对象中检测有没有值相等的对象,有就取,没有再创建
String str3 = new String("abc");
str1 == str3//false;new 会直接创建新对象,所以此处引用不同。

StringBuffer 和 StringBuilder存在的作用

【分析】Java中的字符串对象有一个对象,为不变形,即它只能被创建,而不能被改变,因此,一些大量使用字符串的程序可能出现性能瓶颈,甚至内存溢出。
【答案】
在java中,如果有大量拼接字符串的需要的话应该使用StringBuffer和StringBuilder类,它们可以避免不必要的String对象的产生,以提供性能,StringBuffer线程不安全。StringBuilder线程安全

如何输出反转后的字符串

【分析】常规算法:遍历逆序打印,或者转换为char数组toChar方法,逆序打出。
但是java中使用StringBuffer可以更容易实现调用其reverse()方法。

如何使用指定的字符集创建String对象

String a = "中文";
String b = new String(a.getBytes(),"GBK");
String c = new String(a.getBytes(),"UTF-8");

数组和集合的使用

java数组

如何理解数组在java中作为一个类

int[] arr = new int[]{1,2,3,4};
int[] ar1= new int[4];

数组的类名可以通过获取数组的Class类型来获取

arr.getClass.getName();//[I
str.getClass.getName();//[Ljava.lang.String

【答案】
java的数组本质是一个类,该类保存了数据类型的信息。该类通过成员变量的形式来保存数据。并且通过[]符号,使用下表来访问数据。在处理基本类型数据时,数组保存的是变量的值,如果未提供初始值,数组会将int型初始为0,如果处理引用类型时,数组保存的是数据的引用,如果程序员为提供初始值,数组会把这些变量的值初始化为null

new Object[5]语句是否创建了5个对象

java数组的本质是一个Java类,它也是通过 new 语句进行 实例化。但是这个new语句却不会实例haul数组中的对象。
【答案】不会,题目语句实际上创建了一个数组实例,长度为5,每个数组元素的值为null,并没有创建5个Object实例。

如何拷贝数组的数据

如果用= 号 ,则只是复制了引用,并没有把数组进行拷贝,改变的同一块地址
【答案】使用System.arraycopy()方法,或者重新创建一个数组,循环赋值。

二维数组的长度是否固定

int[][] arr = new int[3][];
arr[0] = new int[]{4};
arr[1] = new int[]{1,2};
arr[2] = new int[]{1,2,3};

【答案】长度不固定,java数组的长度可以动态变化,程序员可以任意扩展数组的维度,每一维度的元素个数可以不同。

集合框架

什么是集合

collection - set(sortedSet),list
map(sortedMap)
List:有序存放,允许重复,可以存放不同类型的对象
Set:无序存放,不允许重复,可以存放不同类型的对象
SortedSet:排序的Set
Map:键值对
SortedMap:排序好的Map
【答案】
集合是用来存放其他对象的对象,代表一种底层结构,用于扩展数组的功能。结合框架由一系列的接口和实现类组成,包括列表、集合、映射等,它们大多具有可迭代性和可比较性

迭代器是什么

【分析】
迭代器模式,又叫游标模式,提供一种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节。

Iterator<String> it = list.iterator();
while(it.hasNext()){
    System.out.println(it.next());
}

【答案】
迭代器,提供一种访问集合对象的方法,同时又不用暴露该对象内部细节。java中通过提供Iterable和Iterator两个接口来实现集合类的可迭代性。hasNext() next() remove()

比较器是什么

【答案】
比较器是把集合或数组的元素强行按照指定方法进行排序的对象,它是实现了Comparator接口类的实例。如果一个集合元素的类型是可比较的(实现了Comparable接口),那么它就具有默认的排序方法,比较器则是强行改变它默认的比较方式来来进行排序。或者有的集合元素不可比较,则可用比较器来实现动态的排序。

Vector与ArrayList的区别

Vector与ArrayList都是List接口的实现类,它们都代表链表形式的数据结构。但是Vector的大多数成员方法都会加上synchronized关键字,即vector是线程安全的。
ArrayList的效率要高一些。

HashMap和HashTable的区别

1 HashTable线程同步,HashMap不能同步
2 HashTable不允许有null值,HashMap可以
3 HashTable有一个contains方法与containsValue功能一样
4 HashTable使用Enumeration ,HashMap使用Iterator
5 HashTable中的hash数值初始化大小及其增长方式不一样
6 哈希值的使用不同,hashTable直接使用对象的hashCode,而hashMap会重新计算hash值。

集合使用泛型带来什么好处

泛型,在c++中被称为模板,就是一种抽象的编程方式,当开发者定义类和方法的时候,可以用一种通用的方式进行定义,而不必写出具体的类,这些未知的东西会在真正使用的时候再确定。

List list1 = new ArrayList();
list1.add("a");
list1.add("b");
Iterator it = list.iterator();
while(it.hasNext()){
    Object obj = it.next();
    String val = (String) obj;
    System.out.println(val);
}
List<String> list2 = new ArrayList<String>();
list2.add("a");
list2.add("b");
for(String str:list2){
    System.out.println(str);
}

list1 没有使用泛型,它存放的都是Object,在使用时需要进行类型的强制转换。
list2 创建时就提供了元素的类型,因此获取元素时,类型也会自动转换。
【答案】集合使用泛型以后,可以达到元素类型明确的目的,避免了手动类型转换的过程,同时,也让开发者更加明确容器保存的是什么类型的数据。

如何把集合对象中的元素进行排序

【答案】
对于没有排序功能的集合来说,都可以通过java.util.Collections.sort()方法进行排序,它除了集合外,还需要提供一个比较器。如果列表中的元素全都是相同的类型,并且这个类实现了comparable接口,可以简单地调用Collections.sort()。如果这个类没有实现Comparator,就可以传递一个Comparator实例作为sort的第二个参数进行排序。另外,如果不想使用默认的分类顺序进行排序,则可传递一个Comparator实例作为参数进行自定义排序。

符合什么条件的数据集合可以使用forEach循环

【答案】数组或者实现了Iterable接口的类实例,都可以使用foreach循环,而java集合框架中的集合类大多都实现了迭代器,所以可以用foreach。

Java高级特性

输入/输出流-File类

目录和文件操作

【答案】
java提供了java.io.File类对目录和文件进行操作。主要的操作方法包括:路径字符串构造方法、isDirectory、isFile、createNewFile、list、getName、delete

写一个复制文件的程序

【答案】
(1)用被复制文件的路径创建一个InputStream对象。
(2)用复制的文件的新路径创建一个OutoutStream对象
(3)用read方法循环把数据读入到一个波耶特数组,直到读出数据的长度小于0,
(4)用write方法把byte数组中的字节写入输出流。
(5)最后关闭输入流和输出流。

如何使用随机存取文件RandomAccessFile类

1 使用length方法获取文件的内容长度
2 用seek方法随机的到达任何需要存取数据的地方
3 调用read方法获取当前位置的数据,用write方法写入数据
4 关闭文件close()

Stream 类

字节流的处理方式

【答案】
字节流处理的计算机最基本的单位byte,它可以处理任何数据格式的数据。主要的操作对象就是byte数组,通过read()和write()方法吧波耶特数组中的数据读入或读出。

字符流的处理方式

1 根据输入或输出流对象,可以从File得到,也可以从网络或其他地方得到。
2 根据特定的字符格式创建InputStreamReader或InputStreamWriter对象
3 使用read或readLine方法,得到数据。
4 最后关闭reader或writer。

序列化

什么是序列化

【答案】
序列化的本质就是把对象内存中的数据按照一定的规则,变成一系列的字节数据,然后再把这些字节数据写入到流中。
所有需要进行序列化的类,都必须进行Serializable接口,必要时还需要提供静态的常量 serialVersionUID

怎么序列化

1 需要序列化的类实现java.io.Serializable接口
2 提供静态的long型的常量serialVersionUID
3 如果是序列化对象,则用一个输出流创建一个ObjectOutputStream对象,然后调用writeObject方法
4 如果是反序列化,首先使用一个输入流创建一个ObjectInputStream对象。然后调用readObject方法,得到一个Object类型的对象。最后再做类型的强制转换。
5 关闭流

多线程编程

多线程编程的基本概念

什么是线程

【答案】
线程是进程中的一个执行单元,又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度。
多线程是这样一种机制:它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,多线程机制下的线程彼此间相互独立,比较容易共享数据,通过并发执行的方式来提高程序的效率和性能

进程和线程的区别

1 线程的划分尺度小于进程,线程隶属于某个进程。
2 进程是程序的一种动态形式,是CPU、内存等资源占用的基本单位,而线程是不能独立的占用这些资源的,共享内存的资源
3 进程之间相互独立,通信比较困难,而线程之间共享一块内存空间,通信比较方便。
4 进程在执行过程中,包含比较固定的入口,执行顺序,和出口,而线程的这些过程被应用程序所控制是不固定的。

java中的多线程编程

如何使一个类成为线程类

【答案】
让一个类成为线程类的两种方式:
一个是实现java.lang.Runnable接口,
另一个继承java.lang.Thread.
它们都要实现run方法,其实Thread是实现了Runnable接口的类。

解释Runnable接口与Thread类的区别

1 线程类继承自Thread则不能继承其他类,而可以实现多个Runnable接口
2 线程类继承自Thread相对于Runnable来说,使用线程的方法更方便一些,因为它内置了很多方法
3 实现Runnable即可的线程类的多个线程,可以更方便的访问同一个变量。而Thread类则需要内部类来进行替代。

如何启动一个线程

两种方式

public class ThreadStartTest{
    public static void main(String[] args){
        ThreadTest t1 = new ThreadTest();
        Thread t2 = new Thread(new RuunableTest());  
        //启动线程
        t1.start();
        t2.start();  
    }
}
class ThreadTest extends Thread{
    public void run(){...}
}
class RunnableTest implements Runnable{
    public void run(){...}
}

【答案】
继承自Thread的线程类,可以通过new关键字创建一个线程后,执行start方法启动。
实现了Runnable接口的线程类,需要用它的对象实例,作为Thread类构造方法的参数,创建一个Thread对象后,调用start方法启动。

如何使用sychronized来让线程同步

class MyThread extends Thread{
    public static int index ;
    public void run(){
        for(int i = 0;i<10;i++){
            System.out.println(getName()+":"+index++);        
        }
    }
}
public class SyncTest{
    public static void main(String[] args){
        new MyThread().start();    
        new MyThread().start();    
        new MyThread().start();    
    }
}
//运行结果
Thread-0:0
Thread-2:1
Thread-0:3
Thread-2:4
Thread-0:5
Thread-2:6
Thread-0:7
Thread-0:8
Thread-1:9
Thread-2:10
线程会交织执行,而不会顺序执行,因为它们获取系统时间pain的时刻是不确定的
改进使用synchronized关键字来保证
class MyThread extends Thread{
    public static int index ;
    public static Object obj = new Object();//使用任意一个对象来加锁
    public void run(){
        synchronized(obj){      
            for(int i = 0;i<10;i++){
                System.out.println(getName()+":"+index++);        
             }
         }
    }
}

【答案】
synchronized关键字代表要为某一段代码加上一个同步锁,这样的锁是绑定到某一个对象边上的,如果是同步代码段,需要为该synchronized关键字提供一个对象的引用;如果是同步方法,只需要添加一个synchronized关键字修饰。
synchronized为某段代码加锁后,某个线程进入到该段代码之前,首先要检查该锁是否被占用,如果没有被占用则继续执行;如果已经被占用,则需要等到该所被释放以后才能继续执行。其中,线程执行完这段代码就是释放锁的标志。

编写一个生产者消费者模型的多线程子程序

一般使用 notify和wait方法解决该问题
【分析】
每个生产者线程添加货物前先要检查货架是否已满,如果已满则等待并通知消费者进行消费,直到消费者消费了一个货物后,继续添加。
每个消费者在消费时,要先检查货架是否为空,如果为空则等待并通知生产者进行生产,直到生产者添加了货物以后再进行消费

//仓库类
public class Store{
    private final int MAX_SIZE;
    private int count;
    public Store(int n){
        MAX_SIZE = n;
        count = 0;    
    }
    //添加货物
    public synchronized void add(){
        while(count>=MAX_SIZE){
            pirnt("已经满了");
            try{
                this.wait()            
            }catch(InterruptedException e){
                e.printStackTrace()            
            }
        }    
        count++;
        print(Thread.currentThread().toString()+"put"+count);
        this.notifyAll();
    }
    //取走货物
    public synchronized void remove(){
        while(count<=0){
            print("已经为空");
            try{
                this.wait();
            }catch(InterruptedException e){
                e.printStackTrace();            
            }
        }    
        count--;
        print(Thread.currentThread().toString()+"get"+count);
        this.notifyAll();
    }
    public static void main(String[] args){
        Store s = new Store(5);
        Thread pro = new Producer(s);
        Thread con = new Consumer(s);
        Thread pro2 = new Producer(s);
        Thread con2 = new Consumer(s);
        pro.setName("producer");
        con.setName("Consumer");
        pro2.setName("producer2");
        con2.setName("consumer2");
        pro.start();
        pro2.start();
        con.start();
        con2.start();

    }
}
class Producer extends Thread{
    private Store s;
    public Producer(Store s){
        this.s = s;    
    }
    public void run(){
        while(true){
            s.add();
            try{
                Thread.sleep(1000);            
            }catch(InterruptedException e){
                e.printStackTrace()            
            }
        }    
    }
}
class Consumer extends Thread{
    private Store s;
    public Consumer(Store s){
        this.s = s;    
    }
    public void run(){
        while(true){
            s.remove();
            try{
                Thread.sleep(1500);            
            }catch(InterruptedException e){
                e.printStackTrace()            
            }
        }    
    }
}

使用了wait和notify的方法,需要加synchronized关键字,否则会报java.lang.IllegalMonitorStateException 异常

如何使用java线程池

【答案】java提供了java.util.concurent.ThreadPollExecutor类来使用线程池,通过它构造的对象,可以很容易地管理线程,并把线程代码与业务代码进行分离。

java的反射机制

元素完全可以在运行时动态的创建或调用,而不必在JVM运行时就进行确定。

反射基础

反射的原理

【答案】
反射是为了能够动态地加载一个类,动态地调用一个方法,动态地访问一个属性等动态要求而设计的。它的出发点就在于JVM会为每个类创建一个个java.lang.Class类的实例,通过该对象就可以获取这个类的信息,然后通过使用java.lang.reflect包下的API以达到各种动态需求。

Class类的含义和作用是什么

【答案】
每一个Class类的对象就代表了一种被加载到JVM的类,它代表了该类的一种信息映射。开发者通过以下三种方式获取Class对象
1 Class类的forName方法的返回值
2 访问所有类都会有的静态的class属性
3 调用所有对象都会有的getClass方法
在Class类中,定义了许多关于类信息的方法。如getName、getMethod、getConstructor、和newInstance等方法,可以用于反射开发,还有isInstance和isInterface等一些关于类的功能方法。

如何操作类的成员变量(Field)

【答案】
Field提供了有关类或接口的单个静态或实例字段的信息,它通过Class类的getDeclaredField或getDeclaredFields方法获取,再置于java.lang.reflect包下。Field的方法主要分为getXXX和setXXX,它们都需要提供相应的对象实例,setXXX还需要提供需要设置的值

class FieldClassTest{
    String  name ;
    int age;
    public FieldClassTest(String name,int age){
        this.name = name;
        this.age = age;
    }
}
public class FieldTest{
    public static void main(String[] args){
        FieldClassTest t1= new FieldClassTest("ba",11);
        FieldClassTest t2 = new FieldClassTest("ma",12);
        print(compare(t1,t2) +"is Bigger");
    }
    public static FieldClassTest compare(FieldClassTest t1,FieldClassTest t2){
        try{
            Field field = t1.getClass().getDeclaredField("age");
            Field field2 = FieldClassTest.class.getDeclaredField("age");
            int val1 = (Integer)field.get(t1);
            int val2 = (Integer)field2.get(t2);
            if(val1>val2){
                return t1;
            }else{
                return t2;
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

如何操作类的方法(Method)

class MethodTestClass{
    public void m1(){
        print("m1 is called");
    }
    public void m2(){
        print("m2 is called");
    }
}
public class CallMethodTest{
    public static void main(String[] args){
        args = new String[]{"m2"};
        String methodName = args[0];
        if(methodName!=null){
            Class<MethodTestClass> clazz = MethodTestClass.class;
            try{
                Method m = clazz.getDeclaredMethod(methodName);
                if(m!=null){
                    MethodTestClass obj = clazz.newInstance();
                    m.invoke(obj);
                }
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

如上的程序,如果命令行输入参数m1则调用m1方法,输入m2则调用m2方法
【答案】
Method提供关于类或接口中的某个方法的信息,包括了静态方法和成员方法。它通过Class的getMethod或getMethods方法获取到,该类在java.lang.reflect下。Method类的常用方法为invoke,正是通过它来完成方法被动态调用的目的。

反射的应用

如何利用反射实例化一个类

Class类的newInstance方法的使用
Constructor类的使用

class Student{
    private String name;
    private int age;
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    public Student(){
        super();
    }
    public String toString(){
        return "stu"+name+","+age;
    }
}
public class NewInstanceTest{
    public static void main(String[] args){
        //使用无参数的构造方法
        Class<Student> clazz = Student.class;
        Student obj = clazz.newInstance();
        print(obj);
        //使用带参数的构造方法
        Constructor<Student> con = clazz.getConstructor(String.class,int.class);
        //使用构造器创建对象
        obj = con.newInstance("zhang",30);
        print(obj);
    }
}

【答案】
根据调用构造方法的不同,用反射机制来实例化一个类,可以有两种途径。如果使用无参的构造函数,则直接使用Class的newInstance方法即可;如果需要指定特定的构造方法来创建对象,则先获取Constructor实例,在调用其newInstance方法创建对象。

如何利用反射机制来访问一个类的私有成员

class PrivateTestClass{
    private String field1;
    public PrivateTestClass(String field1){
        super();
        this.field1 = field1;
    }
}
public class PrivateTest{
    public static void main(String[] args) throws Exception{
        PrivateTestClass obj = new PrivateTestClass("hello");
        Class clazz = obj.getClass();
        Field f = clazz.getDeclaredField("field1");//获取Field对象
        f.setAccessible(true);//把它的可访问性设置为true
        System.out.println(f.get(obj));
    }
}

【答案】
在使用反射机制方位私有变量的时候,它们原有的可访问性为false。需要调用setAccessible(true)方法,将其改为true,即可访问私有成员。

如何使用反射来覆盖数据对象的toString方法

class DataObject{
    private String name;
    private String desc;
    private int age;
    private String other;
    public DataObject(String name,String desc,int age,String other){
        super();
        this.name = name;
        this.desc = desc;
        this.age = age;
        this.other = other;
    }
    public String toString(){
        StringBuffer sb = new StringBuffer();
        Field[] fields = this.getClass().getDeclaredFields();
        for(Field f :fields){
            sb.append(f.getName());//获取变量的名
            sb.append("=");
            try{
                sb.append(f.get(this));//获取变量的值
            }catch(IllegalArumentException e){
                e.printStackTrace();
            }catch(IllegalAccessException e){
                e.printStackTrace();
            }
            sb.append("\n");
        }
        return sb.toString();
    }
}
public class DataObjectTest{
    public static void main(String[] args){
        Object obj = new DataObject("zhs","desc",10,"other");
        System.out.println(obj);//会调用对象的toString方法
    }
}

【答案】
1 通过getDeclaredFields()方法得到所有的Field对象
2 对fields进行遍历
3 每一次取出对象字段名和字段值并用=号相连
4 返回循环叠加以后的字符串结果
注意:使用StringBuffer,减少中间连接字符串的开销

Java网络编程

网络编程基础

TCP/IP 协议的理解

【答案】
TCP/IP协议定义了计算机接入因特网的标准,以及数据如何在它们之间传输的标准,即使互联网中的基本通信语言或协议也是局域网通信协议。
TCP/IP是一组包括TCP、IP、UDP、ICMP协议和其他一些协议组。需要进行网络通过的计算需要提供符合这些协议标准的程序以后,才能进行网络通信。
【拓展】
TCP/IP四层结构
应用层:应用程序沟通层,WWW、SMTP、FTP、Telnet
传输层:节点间,应用程序之间的通信服务。主要功能是数据格式化、数据确认与丢失重传等。包括TCP、UDP
网络层:负责提供基本的数据封装包传送功能,让每一块数据报都能够到底目的主机,但不检查是否被正确接收,主要体现为IP协议。
网络接口层:接收IP数据报并间传输,从网络上接收物理帧,抽取IP数据报转交给下一层,对实际的网络媒体的管理,定义如何使用物理网络,如以太网

TCP协议的通信特点是什么

【答案】
TCP是一种面向连接的、可靠的、基于字节流的端到端的应用层协议

java的TCP编程模型是什么

public class TCPServarA{
    public static void main(String[] args) throws Exception{
        //用端口号创建一ServerSocket对象
        ServerSocket ss = new ServerSocket(8888);
        Socket s = ss.accept();
        OutputStream os = s.getOutputStream();
        PrintWriter pw = new PrintWriter(os);
        pw.print("now time = "+new Date());
        pw.flush();//清空缓存
        pw.close();
        s.close();
        ss.close();
    }
}
//客户端
public class TCPClientA{
    public static void main(String[] args) throws Exception{
        Socket s = new Socket("localhost",8888);
        InputStream is = s.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String str = br.readLine();
        System.out.println(str);
    }
}

【答案】
服务器端:
1 创建一个服务器端的socket,指定一个端口号
2 开始监听客户端的请求,accept
3 获取输入或输出流
4 调用write或read方法
5 释放资源
客户端
1 创建Socket对象,建立与服务器端的连接
2 获得输入或输出流
3 调用read或write方法
4 关闭输入或输出流,释放资源

UDP通信的特点是什么

【答案】
1 UDP是一个无连接的协议,传输数据之前源端口和目的端口不建立连接,尽可能快的传输数据
2 不需要维护连接状态
3 字节开销小
4 吞吐量主要受软件生成数据的速率、传输带宽、源端和目的端主机性能所限制

java的UDP编程模型是什么

public class UDPServarA{
    public static void main(String[] args) throws Exception{
        //创建DatagramSocket,指定端口
        DatagramSocket ds = new DatagramSocket(9999);
        byte[] buff = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buff,1024);//创建一个数据包对象
        ds.receive(dp);
        String str = new String(dp.getData(),0,dp.getLength());
        System.out.println(str);
        ds.close();
}
//客户端
public class UDPClientA{
    public static void main(String[] args) throws Exception{
        DatagramSocket ds = new DatagramSocket(9998);
        String str = "abc";
        DatagramPacket dp = new DatagramPacket(str.getBytes(),0,str.length(),InetAddress.getByName("localhost"),9999);
        ds.send(dp);
        ds.close();
    }
}

【答案】
1 创建数据Socket,指定一个端口
2 对于接受消息的一端来说,提供一个byte数组进行数据的存储;对于发送数据的一端来说,除此之外还要提供对端的IP地址和端口号。
3 调用DatagramPacket的receive或send方法进行数据的接收或发送
4 调用DatagramPacket的getData方法得到byte数据的数据。
5 释放资源

用TCP通信模型创建一个Web服务器

【分析】
HTTP是一个应用层协议,是基于TCP的,它的底层的通信原理依然遵循TCP的编程模型。

//服务器端
public class Main11 {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        ServerSocket ss = new ServerSocket(80);
        Socket s = null;
        while((s = ss.accept())!=null){
            new HTTPThread(s).start();
        }
        ss.close();
    }

}
class HTTPThread extends Thread{
    private Socket socket;
    public HTTPThread(Socket socket){
        super();
        this.socket = socket;
    }
    //线程方法
    public void run(){
        try{
            OutputStream os = socket.getOutputStream();//获取输出流
            PrintWriter pw = new PrintWriter(os);//创建PrintWriter对象
            pw.println("<html>");
            pw.println("<body>");
            pw.println("hello this is my web sit");
            pw.println("</body>");
            pw.println("</html>");
            pw.flush();//清空缓存
            pw.close();
            socket.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

使用UDP模拟聊天软件

为接受用户输入和打印聊天记录两个界面创建两个不同的线程,它们分别使用DatagramPacket通信。创建一个发送消息的线程(SendThread)和一个接收消息的线程(ReceiveThread),分别的作用是循环监听用户的输入并把用户输入的数据通过调用DatagramSocket的send方法发出和循环的调用DatagramSocket的receive方法,接收另一端的数据。

如何使用java访问网络站点

1 用URL类创建一个资源定位的对象
2 调用URL的openConnection方法得到HttpURLConnection对象。
3 调用HttpURLConnection的open方法打开链接。
4 调用getHeaderFields方法得到响应结果的头部信息
5 用getInputStream方得到输入流对象,得到响应内容。

java对数据库的操作

SQL基础

查询语句

SELECT<列名>
FROM <表名/视图>
WHERE <筛选条件>
ORDER BY<列名>

更新语句

insert into 表名(列名)values(值列表)
update 表名 set (键值对) where 条件
delete from 表名 where 条件

JDBC

JDBC的工作原理

【答案】
JDBC(Java Data Base Connectivity)采用了一种驱动模式的设计,提供了两套的接口:开发者使用的API和数据库厂商使用的SPI(Service Provider Interface),充分体现了面向对象的好处。程序员无需关心具体数据库的连接和调用。只需要使用JDK中提供的标准API编程即可,而具体的实现由特的数据库生产商提供,也就是JDBC驱动。

简述JDBC操作数据库的编程步骤

//第一步,注册驱动程序
Class.forName("数据库驱动的完整类名");
//第二步,获取一个数据库的连接
Connection conn = DriverManager.getConnection("URL","用户名","密码");
//第三步,创建一个会话
Statement stmt = conn.createStatement();
//第四步,执行SQL语句
stmt.executeUpdate("增加 删除 修改记录的SQL语句");
//或者查询记录
ResultSet rs = stmt.executeQuery("产需记录的语句");
//第五步,对查询的结果进行处理
while(re.next()){
  ....
}
//第六步,关闭连接
rs.close();
stmt.close();
conn.close();

【答案】
1 注册驱动程序
2 获取数据库连接
3 创建会话
4 执行SQL语句
5 处理结果集
6 关闭连接

如何使用JDBC事务

事务是指作为逻辑工作单元执行的一系列操作。满足ACID(原子性、一致性、隔离性、持久性)
事务的结束只有两种形式:提交和回滚
(1)关闭自动提交事务,通过设置连接的自动提交事务属性为false

Connection conn = DriverManager.getConnection("url","username""password");
conn.setAutoCommit(false);

(2)捕获执行代码,成功则提交否则回滚

tyr{
    conn.setAutoComit(false);
    stmt = conn.createStatement();
    stmt.executeUpdate('sql');
    conn.commit();
}catch(Exception e){
    e.printStackTrace();
    conn.rollback();
}

(3)关闭连接,最好放在finally中

finally{
    if(stmt!=null)
        stmt.close();
    if(conn !=null)
        conn.close();
}

如何使用JDBC实现数据访问对象层(DAO)

DAO的设计意图就是让上层对待底层数据的时候,能够再用一个对象的眼光来看待。因此,DOA要做的事情就是吧数据报装成对象和把对象拆分成数据。增、删、改、差是DAO需要做的最基本的4种操作。它们的实现可以参照一首的示例。除此之外,如果开发发者还需要为DAO类添加其他的方法,也是需要体现一种对象观的概念。

如何使用连接池技术

【分析】
数据库连接池就好像一个池子一样,这个池子中装的是数据库的连接,程序员需要连接数据库的时候,只需要从池子中取出一个即可。当程序员调用Connection.close方法时,这个连接就会返回到池子中,而没有真正的与数据库端口连接。当连接不够用的时候,它就会创建一个新的连接;同理当连接太多以后,它会自动关闭一些不必要的连接。
【答案】
数据库连接池技术是为了避免重复创建连接而设计的,它作为一个单独的程序模块进行运行,负责维护池子中的数据库的连接。程序员打开连接和关闭连接并不会造成真正意义上的连接创建和关闭,而只是连接池对连接对象的一种维护手段。
对于开发者来说,连接池与传统的JDBC提供的连接不太一样,程序员必须使用数据源的形式获取连接池的连接,而数据源对象往往是以JNDI的形式而提供的。对于Java Web和EJB开发人员来说,需要参考一下具体的JavaEE服务器关于连接池的使用手册。

如何使用可滚动的结果集

JDBC的结果集最开始是不支持回滚的。从JDBC2.0开始才支持回滚的结果集,它运行结果集的指针任意游动。它的使用方法比较简单,在创建会话的时候,为它指定结果集的可滚动性,包括以下3种
+ TYPE_FORWORD_ONLY:结果集不可滚动
+ TYPE_SCROLL_INSENSITIVE:可以滚动,但是对数据库变化不敏感,数据库查询生成结果集后发生了变化,结果集不发生变化。
+ TYPE_SCROLL_SENSITIVE:可以滚动,但是对数据库变化敏感

如何使用可更新的结果集

指定可更新性
+ CONCUR_READ_ONLY:结果集不可用于更新数据库
+ CONCUR_UPDATABLE:结果即可以用于更新数据库

JDBC操作各类数据源

如何操作Oracle数据库

String strurl = “jdbc:roacle:thin:@localhost:1521:tiger”);
Class.forName(“oracle.jdbc.driver.OracleDriver”);

如何操作MySQL数据库

String strurl=”jdbc:mysql://localhost:3306/test”;
Class.forName(“com.mysql.jdbc.Driver”);

如何操作SQL server数据库

String strurl = “jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=Northwind”;
Class.forName(“com.microsoft.jdbc.sqlserver.SQLServer-Driver”);

如何使用JDBC操作EXCEl

JDBC连接和使用excel的时候,依然遵循JDBC标准的API使用方式,它与其他数据库的区别主要在于驱动文件和连接URL不同,它使用的是JDBC-ODBC桥驱动,在使用之前还需要进行ODBC的相关配置,以下是一个JDBC访问Excel的例子

public class Excel{
    public static void main(String[] args){
        try{
            String strurl = "jdbc:odbc:testExcel";
            Class.forName("sun.jdbc.odbc.JdbcOdbcDirver");
            Connection conn = DriverManager.getConnection(strurl);
            Statement stmt = conn.createStatement();
            ResultSet = rs = stmt.executeQuery("select * from books");
            if(re.next()){
                System.out.println(rs.getString("name"));
            }
            conn.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

java EE 相关问题

Servlet与Web容器

一个Web程序应该遵循哪些规范

java web应用程序的目录结构

属性说明
WEB-INF对于用户来说该文件夹是不可见的,存放着class文件、jar文件和配置文件
WEB-INF/web.xmlweb.xml是整个web应用程序的描述文件,通过它配置该应用程序的信息资源,如Servlet、过滤器、监听器、系统参数等等
WEB-INF/classes/存放class文件,也是该web应用程序的类加载路径
WEB-INF/lib/存放第三方的类库jar文件

什么是Servlet

【答案】
Servlet在java web服务器中就充当了信息资源的最小表示单位,代表了一个用户可以通过浏览器获取的资源。Servlet可以进无限的扩展,它可以使用java的所有类库资源,为用户返回文本、图片、音频、视频等各类信息资源。
从编程角度来看,Servlet是一个java类,这个类需要实现Servlet接口,提供一个公开的无参数的构造方法。有web容器来控制它的创建、初始化、提供访问、销毁等。它的各种行为方式通过在web.xml中配置决定。

Servlet的生命周期是?

【答案】
Servlet分为四个阶段
加载、初始化、提供服务和销毁。这些过程都是有web容器来掌控。开发者关注最多的是初始化和提供服务两个阶段。在init中,开发者可以获取配置在web.xml中的初始化参数;service方法中的代码,会在Servlet的请求来到时被调用。

Servlet接口由哪些实现类

【答案】主要有3个Servlet接口的实现类
javax.face.webapp.FacesServlet;
javax.servlet.GenericServlet;
javax.servlet.http.HttpServlet

如何在Servlet中获取请求参数的值

【答案】
在Servlet中,任何负责作出响应的方法(如:service、doPost、doGet)都会包含一个ServletRequest对象参数,不管是Post方法还是get方式,Servlet都可以同ServletRequest接口的getParameter或getParameterValues方法获取到,前者适合一个值的参数,后者用于多个值的参数如复选框

forward和redirect的区别

直接请求转发 forward和间接请求转发redirect
【答案】
Forward和Redirect代表了两种请求转发的方式:直接请求转发和间接请求转发。对应到代码里分别是RequestDispatcherh类的forward方法和HttpServletResponse人类的sendRedirect方法。
对于间接转发方式,服务器端在响应第一次请求时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。它的本质是两次http请求,对应两个request对象。
对于直接转发方式,客户端浏览器只发出一次请求,Servlet就请求转发给Servlet、HTML、JSP或其他信息资源,有第2个信息资源响应该请求,两个信息资源共享同一request对象。

过滤器的作用和工作原理

当web容器收到一个对某个信息资源的请求时,先会判断是否有过滤器与该信息资源关联。如果有的话,会把请求一一交给这些过滤器处理,然后再交给目标资源,同样,响应的时候也会以相反的顺序交给过滤器处理一下,再返回给用户浏览器。
注意:过滤器是一种很重要的设计模式,不仅仅应用于web开发中,其他的软件开发领域也会用到过滤器模式,它可以在不入侵原有代码的基础上为它们提供一些功能。
【答案】
对于web应用程序来说,过滤器是处于web容器内的一个组件,它会过滤特定的请求资源请求信息和响应信息。一个请求来到时,web容器会先判断是否与过滤器与该信息资源关联,如果有,则交给过滤器一一处理,然后再交给目标资源。响应时以相反的顺序交给过滤器处理,最后再放回给浏览器。
过滤器对应Filter接口,开发者一般需要实现doFilter()方法,并在web.xml中提供相应的配置。

监听器的作用和工作原理是什么

监听器也是一种很重要的设计模式,web容器也提供了一些监听器组件。它负责监听各种事件的发生并作出相应的响应。而开发者需要做的就是面向这些事件进行编程。

名称作用范围描述
Request请求代表一次http请求,它的生命周期从请求开始到请求的响应结束。中间可能会穿插很多信息资源如过滤器、Servlet、JSP等等
Session会话代表一次会话,也可以认为是一个用户,一次会话中可以包含多次请求。如果用户长时间不发出请求,可能导致会话超时而过期,超时时长可进行设置。因为它代表一个用户,所以一般使用session保存用户的数据,如购物车
Application应用代表一个web应用,它的生命周期从Web容器启动或者部署该应用开始,以web容器停止或取消部署而结束。它具有最大作用范围,一般用于存放应用标题、其他外部资源连接器等

【答案】
对于web应用程序来说,监听器处于web容器的一个组件,它会对web容器中的3种范围对象进行监听:request、session、application。当这些范围对象在创建或销毁的时候,web容器会主动调用它们的初始化或销毁的回调函数,从而达到事件响应的效果,javaEE为开发者提供了一些监听器接口
request事件的监听接口:ServletRequestListener
Session事件的监听接口:HttpSessionListener
Application事件监听接口:ServletContextListener

##JSP动态语言 ###JSP的运行机制是什么 【分析】 JSP(java server page)是一种建立在Servlet规范提供的功能之上的动态网页技术。与ASP和PHP类似,都是在网页文件中嵌入脚本代码,产生动态的内容,只不过JSP采用的脚本语言是java JSP文件在用户第一次请求时,web容器会将其编译为Servlet,再有Servlet处理用户请求。所以JSP本质上是Servlet。但是Servlet在处理静态内容时非常笨拙,而JSP可以很好的实现动态和静态内容的分离。所以JSP是很必要的。 【答案】 当客户端发出一次对某个JSP的请求时,web容器的处理过程是 (1)web容器会检验JSP的语法是否正确 (2)将JSP转换为Servlet源码文件 (3)将Servlet源码文件编译为Class文件 (4)创建一个该Servlet类的实例,以Servlet的方式为请求提供服务返回给客户端。 ###JSP的内置对象及其用途 【分析】 JSP除了在处理HTML等文件比Servlet强大之外,还内置了很多服务器端组件方便用户使用 JSP内置对象列表
对象类型说明
applicationjavax.servlet.ServletContext它代表了整个web应用程序,与servlet上下文是同一个概念
sessionjavax.servlet.http.HttpSessionHttp会话对象
requestjavax.servlet.http.HttpServletRequest请求对象
responsejavax.servlet.http.HttpServletResponse返回对象
outjavax.servlet.jsp.jspWriter写出流对象,用于返回数据给客户端
pagejava,lang.Object普通的页面对象
pageContextjavax.servlet.jsp.PageContext页面上下文,代表页面的一个运行环境,通过它可以获取到其他对象,如会话,请求等。
exceptionjavax.lang.Throwable用于错误页面,通过该对象可以获得异常的详细信息
configjavax.servlet.ServletConfig配置项对象,用于获取初始化参数等数据
###page和request作用范围的区别是什么 【答案】 Page范围指的是当前JSP页面的范围,一旦该JSP页面处理完以后,该范围也就结束了。它对应了JSP中的pageContext内置对象。 Request范围指的是一次请求,如果请求指向一个单一的JSP文件,则此时的page和request的生命周期是一样的,但是一个请求往往不是由单一的JSP组成的,因此,可以说,一次request的周期可以是若干个JSP或其他资源的周期之和。 ###JSP如何使用javaBean 【分析】 javabean是JSP扩展的一种方式,它最大的特点就是可重用性,JSP+javabean是java web开发的一种常见模式。 可重用组件指的是能够完成某种特定的功能,并提供了一个或多个访问接口的聚合模块程序,可重复使用是它最大的特点。 JavaBean本质是一个普通的类只是它必须符合一定的规范。 + 它是一个公开类 public class + 它是一个公共的无参数的构造方法 + 提供了公共的setXXX和getXXX方法来决定Javabean属性。 【答案】 JSP使用Javabean有两种方式:JSP的脚本中使用纯粹的java代码和一些Javabean的动作标签。其中使用等动作标签会更加简洁一些,使用的也更多。 用动态标签来使用JavaBean的时候,用标签在特定范围内声明或参加一个JavaBean,用标签来设置一个JavaBean的属性值,用标签来获取一个JavaBean的属性的值。 ##表达式语言和JSTL ###如何使用迭代标签循环显示数据
名称类型说明
varString迭代过程中的当次变量引用名称
itemsObject集合对象如List、Set等
beginint迭代的初始数字
endint迭代的结束数字
stepint增量
varStatusString通过它可以获取迭代中的一些数据,如迭代总数等

语法1:

<c:forEach begin=0 end=5 [var = i] step =1>
System.out.println(i);
</c:forEach>

语法2:

<c:forEach items="${nameList}" var = i [varStatus="status"]>
System.out.println(${nameList.name});
</c:forEach>

JSTL提供哪些逻辑判断标签

【答案】
主要提供了两种或
(1)标签的条件表达式一般放在它的test属性中,如果返回为true则打印标签体的内容
(2)一般需要结合和来使用,条件表达式写在标签的test属性中,类似于java中的switch语句。

Struts 、Spring和Hibernate组合

MVC和Struts

什么是MVC设计模式

MVC模式的主要思想就是把控制器、数据模型和视图分离,达到高内聚和低耦合的作用。
模型:model:代表了应用程序的数据和处理这些数据的规则。当模型发生改变时,它将通知视图,为视图提供查询模型相关状态的能力。
视图(view):用来组织模型的内容,从模型中获取数据,然后将数据展现给用户
控制器(controller):负责从客户端接收请求,然后把请求转换为某种行为。这些行为往往由模型来实现。
用原生库实现MVC模型,则模型–JavaBean;视图—JSP;控制器—servlet

Struts框架是如何体现MVC模式的

1 客户端发出请求:http://cetc38.zhaopin.com
2 ActionServlet接收请求,然后根据struts-config.xml的配置来旋转一个Action,并实例化Action个,调用execute方法
3 Action处理完成后,根据返回的ActionForward找到相应的JSP文件,并将请求转发给JSP
4 JSP接收相应的数据或,构建页面
5 客户端浏览器接收到返回的结果并展示页面
【答案】
Struts框架为开发者提供了MVC的3个逻辑组成部分,主要由ActionServlet、Action和struts-config.xml配置文件组成控制层,由ActionForm来承兑模型层的功能,而Struts下的视图依然由JSP完成。

Hibernate的基本使用思想是什么

【答案】
Hibernate对JDBC进行了一种包装,提供了另外一套的API来操作数据。其中与数据直接打交道的组件是Session,它是以Hibernate的一级缓存,保持着应用程序与数据库之间的连接,通过它来保存内存与数据库之间的数据同步。Session是由SessionFactory来创建的,它代表的含义是数据源,通常指向某个数据库。而SessionFactory是由Configuration来创建,它代表的hibernate程序的数据源及其相关属性的配置信息。如果需要使用事务,则可通过Session来打开、提交和回滚事务。另外,如果需要使用比较复杂的查询功能,还会使用Query接口,它也是通过Session来获得。
Hibernate的API中,session、sessionFactory、Configuration、Transaction和Query是它的5个最重要的接口,它们一起工作,构成了hibernate基本的基本思想。

Hibernate的实体存在哪几种状态

  • 瞬时状态:用new语句创建的实体对象就属于瞬时态,它此时一般没有iD值
  • 持久状态:存放在Session中的实体对象就属于持久状态,一般通过save、saveOrUpdate等方法转换而来
  • 托管状态:当实体从Session中脱离出来的时候,它的状态就是托管状态了,尽管它具有ID值,但是它并不在Session中,即使实体的数据发送变化,也不能同步到数据库中。通过调用Close、evict等方法转换而来。

Spring

从实际出发,着眼于轻便、灵活、易于开发、易于测试和易于部署的轻量级开发框架。Spring在一定程度上影响了JavaEE的开发模式。

依赖注入的方式有哪些

【分析】
依赖注入是Spring的ICO容器中的一个核心概念,它的本质上是通过容器来管理对象数据的填充和对象之间的关联关系。
【答案】
setter方法和构造函数方法
(1) setter方法注入:使用标签进行配置,为符合JavaBean规范的可写属性赋值,值的类型可以是String int等数据类型,也可以是引用类型。
(2) 构造方法住注入:使用标签进行配置,根据下标位置来为变量赋值,类型也可以是任意的。
区别:Constructor可以在构建对象的同时把依赖关系也构建好。对象创建好以后就已经准备好了所有的资源,安全性高。setter创建完对象之后再通过set方法进行属性的设定,更加灵活些。

如何使用Spring的声明式事务

开发者通过配置的形式来使用事务

EJB与JPA相关问题

EJB3.0

EJB的类型有哪几种

EJB的全称为企业集Java Bean,根据用途的不同,可以分为3中Bean:
会话Bean:用于实现业务逻辑,负责接收客户端请求
实体Bean:代表实体模型,用于实现对象关系映射
消息驱动Bean:用于异步编程,基于消息服务,相当于异步的无状态会话Bean

开发EJB的步骤

1 完成业务接口和业务Bean类。使用Local、Remote、Stateless等标注
2 编译。引入javaee.jar进行编译
3 提供部署描述文件ejb-jar.xml
4 部署、打包和发布
5 检查部署成功与否。核对JNDI列表
6 写一个客户端程序进行检验

java算法与设计模式

基本算法

排序、查找、回文串、素数等

java高级编程

怎么实现Singleton模式

【分析】
单例模式需要满足三个条件
1 某个类只有一个实例
2 实例类自行创建这个实例对象
3 实例类自行想整个系统提供这个实例对象
java中实现单例模式一般需要注意几点:
1 私有的构造方法,保证外部类无法创建类实例
2 私有的静态的类型引用,因为静态可以保证只有一个变量引用
3 提供获取实例的方法,一般名为getInstance
创建单例模式有两种方式
1 懒汉式

private static XXXObject obj = null;
public static XXXObject getInstance(){
    if(obj==null)
        obj = new XXXObject();
    return obj;
}

懒汉式无法保证线程安全,不能100%的保证单例,需要加上synchronized关键字保证线程同步,synchronized可以加到方法上,也可加到代码段中

private static XXXObject obj = null;
private XXXObject(){}
public static synchronized XXXObject getInstance(){
    if(obj==null)
        obj = new XXXObject();
    return obj;
}

2 恶汉式
将new语句写在类型引用变量定义的地方,不判断null

private static XXXObject obj = new XXXObject();
private XXXObject(){}
public static XXXObject getInstance(){
    return obj;
}

恶汉式不存在线程安全的问题,但是可能造成资源浪费的情况,因为实例会在类加载的时候,随着静态成员变量的初始化而创建,但是有的时候并不会使用该实例,所有就会造成资源的浪费。

怎么实现简单的工厂模式

【分析】
专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类,这称为静态工厂模式,属于类的创建模式。
简单工厂模式的实质就是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例,并且这些产品类继承自一个父类或接口,该模式中包含的角色有以下几方面
1 工厂角色:负责实现创建所有实例的内部逻辑。
2 抽象角色:简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口。
3 具体产品角色,即简单工厂模式的创建目标。

abstract class Auto{

}
class Car extends Auto{
    ...
}
class Truck extends Auto{
    ...
}
//简单工厂模式
class AutoFactory{
    public static Auto createAuto(int autoType){
        if(autoType == 0){
            return new Car();
        }else if(autoType ==1){
            return new Truck();
        }
        return null;
    }
}
public class Main{
    public static void main(String[] args){
        Auto car = AutoFactory.createAuto(0);
        Auto truck = AutoFactory.createAuto(1);
    }
}

用户在使用时可以直接根据工厂类去创建所需的实例,而无须了解这些对象是如何创建以及如何组织的。有利于整个软件系统结构的优化。但是,简单工厂模式的缺点也正体现在其工厂类上,如果当系统中的具体产品类不断增加时,可能会出现要求工厂类也要做相应的比较大的改动,扩展性不好。

怎么实现工厂方法模式编程

abstract class Auto{

}
class Car extends Auto{
    ...
}
class Truck extends Auto{
    ...
}
abstract class AbstractAutoFactory{
    public abstract Auto createAuto();
}
class CarFactory extends AbstractAutoFactory{
    public Auto createAuto(){
        return new Car();
    }
}
class TruckFactory extends AbstractAutoFactory{
    public Auto createAuto(){
        return new Truck();
    }
}
public class Main{
    public static void main(String[] args){
        AbstractAutoFactory factory1 = new CarFactory();
        AbstractAutoFactory factory2 = new TruckFactory();
        factory1.createAuto();
        factory2.createAuto();
    }
}

怎么实现抽象工厂方法模式编程

abstract class Auto{

}
class Car extends Auto{

}
class Truck extends Auto{

}
abstract class Wheel{

}
class CarWheel extends Wheel{
    }
class TruckWheel extends Wheel{

}
/*抽象工厂方法模式(可以生成多种不同的产品)*/
/*且这些产品之间有一定的联系*/
/*关系在于:成产轿车的工厂只能生成轿车的轮胎,不能生成卡车的轮胎;可以创建一个轮胎接口*/
interface CreateWheelAble{
    public abstract Wheel createWheel();
}
abstract class AbstractAutoFactory implements CreateWheelAble{
    public abstract Auto createAuto();
    public abstract Wheel createWheel();
}
class CarFactory extends AbstractAutoFactory{
    public Auto createAuto(){
        return new Car();
    }
    public Wheel createWheel(){
        return new CarWheel();
    }
}
class TruckFactory extends AbstractAutoFactory{
    public Auto createAuto(){
        return new Truck();
    }
    public Wheel createWheel(){
        return new TruckWheel();
    }
}
public class Main{
    public static void main(String[] args){
        AbstractAutoFactory factory1 = new CarFactory();
        a[6] = factory1.createAuto();
        Wheel w = factory1.createWheel();
    }
}

怎么实现观察者模式编程

观察者模式又称为监听模式,广泛应用在图形化编程中。
【分析】
观察者模式将观察者和被观察者分开
观察者模式有很多实现方法,从根本上说,该模式必须包含有两个关键角色:观察者和被观察对象。通过一种注册和回调的形式来实现观察者模式。观察者往往是需要实现某个接口的,被观察者保持着这些被注册的观察者的信息,一旦发生变化则通过多态回调观察者的接口反复,从而达到低耦合的目的。
【答案】
实例:当商品价格发生变化时,通知网页观察者修改网页数据和并通知E-mail观察者发送E-mail。

public class ObserverPattern{
    //主方法
    public static void main(String[] args){
        Product p = new Product("人生若只如初见",100.00);
        Observer o1 = new WebObserver();
        Observer o2 = new MailObserver();
        p.addObserver(o1);
        p.addObserver(o2);
        System.out.println("---第一次价格变动---");
        p.setPrice(80);
        o1.unreg(p);//观察者1取消观察
        System.out.println("---第二次价格变动---");
        p.setPrice(70);
    }
}
interface Observer{
    public void update(Product p);
    public void unreg(Product p);
}
class WebObserver implements Observer{//web观察者
    public void update(Product p){
        System.out.println("更新价格: "+p.getName()+": "+p.getPrice());
    }
    public void unreg(Product p){
        p.getObservers().remove(this);
    }
}
class MailObserver implements Observer{//邮件观察者
    public void update(Product p){
        System.out.println("为所有会员发送价格变化的消息: "+p.getName()+": "+p.getPrice());
    }
    public void unreg(Product p){
        p.getObservers().remove(this);
    }
}
//产品类
class Product{
    private double price;
    private String name;
    private HashSet<Observer> observers;
    //构造方法
    public Product(String name,double price){
        this.name = name;
        this.price = price;
        observers = new HashSet<Observer>();
    }
    public void addObserver(Observer ob){//添加观察者
        observers.add(ob);
    }
    //通知监听者执行update方法
    public void notifyObserver(){
        for(Observer ob:observers){
            ob.update(this);
        }
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
    public void setPrice(double price){
        this.price = price;
    }
    public HashSet<Observer> getObservers(){
        return observers;
    }
    public void setObservers(HashSet<Observer> observers){
        this.observers = observers;
    }
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值