2017 java程序员面试宝典

1:JDK与JRE
JDK:JAVA Development Kit, java开发工具包; 包括各种类库和工具,当然也包括JRE
JRE:JAVA Runtime Environment,java程序运行环境,包括JAVA类库的class文件和JVM
2:JAVA_HOME PATH CLASSPATH
JAVA_HOME :JDK的安装目录,很多web服务器如tomcat没有内置JDK,它们通过JAVA_HOME找到JDK
PATH:在原有值后加“;%JAVA_HOME%\bin”;通过配置PATH,可以再任何命令提示符窗口中使用JAVAC、JAVA等命令了
CLASSPATH:用来指定JAVA程序搜索类的路径的,JAVA程序在编译和运行时,先搜索jre/lib/rt.jar中的类,然后搜索CLASSPATH中指定的类;一般CLASSPATH会包括当前目录“.”
3:JAVA程序动态的指定类搜索路径方法
利用-cp或-classpath选项,如
javac –cp D:\wrok\log4j.jar Hello.java (编译时指定D:\wrok\log4j.jar为搜索路径)
java –cp D:\wrok\log4j.jar Hello
4:JAVA和C++程序在编译及运行上的区别
C,C++这类语言的编译器(例如 UNIX下的CC命令,WINDOWS下的CL命令)都是把源代码直接编译成计算机可以认识的机器码,如EXE、DLL之类的文件,然后直接运行。
JAVA为了实现跨平台,多了一个中间步骤,就是先生成字节码文件,javac命令先把源文件编译成计算机无法直接识别的class文件,但是它可以被JVM所认识,JVM有多个平台版本,因此可以在多个平台执行。
5:什么是JVM及其工作原理
JVM是一个想象中的机器,在实际的计算机上通过软件模拟来实现。Java虚拟机有自己想象中的硬件,如处理器、堆栈、寄存器,还有相应的指令系统。JVM在执行字节码时,把字节码解释成具体平台上的机器指令执行。
6:JAVA垃圾回收机制
JVM中栈存放的是非static的自动变量、函数参数、表达式的临时结果和函数返回值。栈中这些实体数据的分配和释放均是由系统自动完成的。
堆中存放的实体数据是程序员显示分配的(new),没有自动垃圾回收机制的系统中(有些JVM没有垃圾回收机制)必须显示的释放这些实体
C、C++中也有栈和堆,对堆的管理,C是通过malloc()和free();而C++是通过new和delete
Object对象中有个finalize(),它会在对象被回收之前被调用;
System.gc();和Runtime.getRunime().gc()两个方法都可以显示请求开始垃圾回收线程
7:jar和war
两者都是java可执行文件,jar是对于桌面应用程序,war是对于web应用程序;
Jar和war打包都通过JDK的jar命令
8:JAVA变量及作用范围
分为:静态变量、成员变量、局部变量
静态变量在类中用static修饰,生存周期由类决定;成员变量是类中没有用static修饰的变量,生存周期有对象来决定;局部变量是定义在方法里的变量、方法的参数、代码块里的变量,它们的作用范围用大括号{}来界定
9:JAVA变量分为哪两种大的数据类型
基本数据类型和引用数据类型 ,它们最大的区别在于引用数据类型存放的是数据所在的地址,而基本数据类型直接存放数据的值;二者都保存在栈中
10:装箱、拆箱指的是基本基本数据类型和包装类型的自动相互转化
11:C++指针和JAVA引用的区别
相同:都是指向一块内存地址
不同:
一 类型转换:引用的类型转换,可能抛出java.lang.ClassCastException,引用对应的类型不同的话,转换不成功;C++指针则一定能转换成功,指向哪儿,还是一个地址
二 初始值:引用类型的初始值为null;C++指针是int,如不初始化,值是随机的
三 计算:引用不可计算;指针可计算,如++或—
四 内存泄露:JAVA引用基本不会产生内存泄露;指针容易,程序员须及时回收
五 作为参数:JAVA方法本质上只有传值,引用作为参数使用时,回给函数内引用的COPY,所以在函数内交换两个引用参数是没意义的,但改变一个引用参数的属性是有意义的,因为引用参数的COPY所引用的对象和引用参数是同一个对象;
C++指针作为参数,实际上就是它所指的地址在函数中被操作。
12:equals()和==
==运用在基本数据类型是比较的是实际的值;用于比较引用类型时候,比较两个引用的地址是否相同;(都是比较栈中数据)
Object有equals()方法,默认的比较方式与==相同,String类重写了该方法,使其能比较字符串的内容;
13:JAVA三元运算符
表达式1?表达式2:表达式3 表达式1为true则执行表达式2 ;否则执行表达式3
14:Java注释类型
①行注释 //
②块注释 /* ….. */
③文档注释 /** …. */
④Annotatio
15:类与对象
类是一种抽象,JVM对类只加载一次
对象是类的实现,通过new创建,可以创建多个对象;
面向对象特性:封装、继承、多态
16:什么是多态
本质是可发送消息给某个对象,让该对象自行决定响应何种行为。通过将子类对象引用赋值给超类对象引用变量(向上转型)来实现动态方法调用
17:java中静态成员的特点
类的静态成员是通过static修饰的成员,主要有:静态成员变量、静态方法、静态代码块;它们具有如下特点:
① 在类加载的时候,就进行创建、初始化或执行代码
② 对于一个类来说,都只有一份
③ 类的所有实例都能访问到它们
18:子类调用父类的构造函数
uper([args])必须放在子类构造函数的第一行
19:抽象类和接口的区别
① 接口中的方法都是抽象方法,不必写abstract
② 接口中的属性为static final 静态不可修改的常量
③ 最大区别是一个类可以实现多个接口,但只能继承一个抽象类
④ 抽象类中可以有非抽象方法
面向功能用接口,面向继承用抽象类;如果属性得继承用抽象类;
20:内部类
成员式:静态内部类和成员内部类
局部式:普通局部内部类和匿名内部类
① 静态内部类:相当于外部类的静态成员一样,用static修饰 ,外部类加载时内部类也随之加载,完整类名是abc.Outter.Inner;无法访问外部类的非静态成员
② 成员内部类:相当于外部类的普通成员一样,没有用static修饰,需等外部类创建了对象以后才会被加载到JVM中;创建成员内部类方法:
Outter o = new Outter()
Outter.Inner I = o.new Inner()
③ 局部内部类:定义在一个方法体中,它往往仅作为方法短暂的使用,只能访问用final
修饰的局部变量
④ 匿名内部类:也定义在方法体中,但没有一个具体的名字
如:
Public void adc(){
ew OneInterface(){//OneInterface为一个接口名
… //直接提供具体的实现
21:int和Integer有什么区别
int 属于8中基本数据类型之一,4字节长度,取值范围:-231~231-1;它保存在栈中;可以用算术运算符进行加、减…;在参数传递时传递的是它的值。
Integer是int的包装类;保存在堆中;不可以用算术运算符进行加、减…(因此得转为int);在参数传递时传递的是它所代表对象的引用。
int a = 10
Integer b = new Integer(a);//int–Integer
Integer c = Integer.valueOf(a);//int-Integer
a = b.intValue()+1;//Integer–int
22:float f = 2.3(错) 2.3默认为double型 float f = 2.3f或float f = (float)2.3
23:类型转换
隐式转换:由类型字节长度小的向类型字节长度大的转换 如int隐式转换为double
或者是子类对象赋值给父类的引用
显示转换:与上相反
当实型向整型转换时,会出现精度的损失,而且在进行float或double进行计算时会出现奇怪的问题,这时可以用BigDecimal类进行精确计算
24:用BigDecimal类进行精确计算
BigDecimal提供add() substract() multiply() divide()方法
如:
BigDecimal b1 = new BigDecimal(Double.toString(0.2))
BigDecimal b2 = new BigDecimal(Double.toString(0.3))
System.out.println(b1.add(b2).doubleValue())
25:JAVA不能用0代表false;也不能用非0代表true; 只能用boolean类型的true和false
因此C++中 while(1){…}在JAVA是错的
26:JAVA中 char类型采用unicode编码格式,用2个字节表示一个字符,范围从0到216-1
char能存储中文,且兼容英文字母(ASCII 0~127)
27:JAVA对象池
从JDK5.0开始,JVM启动时会实例化9个对象池。这个对象池分别用来存储8中基本类型的包装类对象和String对象。主要是为了效率问题。例子:
①String str1 = “hello”
String str2 = “hello”
②String str3 = new String(“hello”)
System.out.println(str1==str2);//输出true
System.out.println(str1==str3);//输出false
①处用字符串字面量(双引号),JVM到String对象池中去检查是否有一个值相同的对象,如果有就取现成的对象,如果没有,则创建一个新的对象,并加入到对象池中;
②处直接创建新的字符串,且未加入到对象池
对象池的简单实现:
class Dog{
rivate String name
rivate int age
rivate static HashSetpool = new HashSet()
ublic static Dog newInstance(String name,int age){
for(Dog dog:pool){
if(dog.name.equals(name)&&dog.age==age)
return dog
//如果对象池中没有,创建并加入对象池
Dog dog = new Dog(String,name)
ool.add(dog)
return dog
28:StringBuffer和StringBuilder
Java字符串String对象有个特性—不变性,它只能被创建,而不能被修改(只要一改变就新创建一个对象);因此,一些大量使用字符串的程序(如字符串拼接)可能会出现性能瓶颈,甚至内存溢出;这时需要用到StringBuffer或StringBuilder,两者API相似,但StringBuilder能保证线程安全。
简单示例:
StringBuffer sb = new StringBuffer()
.append(“a”)
String str = sb.toString()
29:如何输出反转过后的字符串
方法1:利用字符串存储字符的原理,取出它的char数组,进行重新排列;
方法2:利用StringBuffer的reverse()方法
30:JAVA数组本质上是一个类,该类保存了数据类型的信息。通过成员变量的形式来保存数据,并且通过[],使用下标来访问这些数据。将基本数据类型初始为各自默认的初始值,如将int初始为0(若程序员未提供初始值),将引用数据类型初始为null
31:集合
List: 有序,允许重复
Set: 无序,不允许重复
SortedSet: 排好序的Set
Map: 键值对 键不可重复
SortedMap: 排好序的Map(根据key排序)
List和Set是Collection的子类
32:迭代器
提供一种访问一个集合对象中各个元素的途径,同时又不需要暴露该对象的内部细节。JAVA通过提供Iterable和Iterator两个接口来实现集合类的可迭代性。从JAVA5.0开始,迭代器可以被foreach循环所替代,但是foreach循环的本质就是使用Iterator进行遍历的。
33:比较器
方法1:要比较的自定义类实现Comparable接口,实现其compareTo(Object o)方法
方法2:定义比较器,实现Comparator接口,实现compare(Object o1,Object o2)方法
String类实现了Comparable,用方法1实现了比较
Collections.sort(Collections c,Comparator com)//这时用方法2定义比较器传入sort方法
Collections.sort(Collections c)//这时用方法1
示例1:
ublic class Person {
rivate String name
rivate int age
ublic Person(String name,int age){
this.name = name
this.age = age
………setters and getters…
ublic class CompareByName implements Comparator{
ublic int compare(Object o1, Object o2) {
Person p1=null
Person p2=null
if(o1 instanceof Person&&o2 instanceof Person){
1 = (Person)o1
2 = (Person)o2
/*
if(p1.getName().compareToIgnoreCase(p2.getName())>0){
return 1
if(p1.getName().compareToIgnoreCase(p2.getName())<0){
return -1
return 0;*/
return (p1.getName()).compareTo(p2.getName())
ublic class DemoPerson {
ublic static void main(String[] args) {
Person p1 = new Person("c",24)
Person p2 = new Person("b",8)
Person p3 = new Person("a",34)
List list = new ArrayList()
list.add(p1)
list.add(p2)
list.add(p3)
//未排序之前
for(Person p:list){
System.out.println(p.getName()+":"+p.getAge())
//按年龄排序之后
System.out.println("按年龄排序之后")
Collections.sort(list,new CompareByAge())
for(Person p:list){
System.out.println(p.getName()+":"+p.getAge())
示例2:
ublic class Dog implements Comparable{
rivate String name
rivate int age
ublic Dog(String name,int age){
this.name = name
this.age = age
//实现Comparable接口的方法
ublic int compareTo(Object o) {//参数必须是Object
Dog d = null
if(o instanceof Dog){
d = (Dog)o
if(this.getAge()>d.getAge()){
return 1
if(this.getAge()
return -1
return 0
ublic class DemoDog {
ublic static void main(String[] args) {
Dog d1 = new Dog("c",24)
Dog d2 = new Dog("b",8)
Dog d3 = new Dog("a",34)
List list = new ArrayList()
list.add(d1)
list.add(d2)
list.add(d3)
//未排序之前
for(Dog d:list){
System.out.println(d.getName()+":"+d.getAge())
//按年龄排序之后
System.out.println("按年龄排序之后")
Collections.sort(list)
for(Dog d:list){
System.out.println(d.getName()+":"+d.getAge())
34:Vector和ArrayList
Verctor的大多数成员方法都会加上synchronized关键字,也就是说Vector是线程安全的;也正因如此,它的执行效率没ArrayList高;通常建议使用ArrayList
35:HashTable和HashMap的区别
① HashTable是线程安全的,HashMap不是
② HashTable不允许null值(key和value都不可以),HashMap可以
③ HashTable有个contains()方法,功能和HashMap的containsValue()一样
④ HashTable使用Enumeration遍历,HashMap使用Iterator
36:符合什么条件的数据集合可以使用foreach循环
从JDK5开始可以使用foreach代替迭代器,从语法上讲,数组或者实现了Iterable接口的类实例,都可以用foreach循环。
实例1:(迭代器模式方法)
ublic class Person {
rivate String name
rivate int age
ublic Person(String name,int age){
this.name = name
this.age = age
………setters and getters…
ublic class Persons implements Iterable{
Listpersonlist = new ArrayList()
//实现Iterable的方法
ublic Iterator iterator() {
PersonIterate pt = new PersonIterate()
t.setPersonList(personlist)
return pt
ublic void add(Person p){
ersonlist.add(p)
ublic class PersonIterate implements Iterator{
Listpersonlist = new ArrayList()
rivate int index = 0
ublic void setPersonList(Listpersonlist){
this.personlist = personlist
ublic boolean hasNext() {
// TODO Auto-generated method stu
return personlist.size()>index
ublic Person next() {
// TODO Auto-generated method stu
return personlist.get(index++)
ublic void remove() {
// TODO Auto-generated method stu
ersonlist.remove(index)
这样下面的foreach就能成功;
Persons persons = new Persons()
ersons.add(new Person("a",1))
ersons.add(new Person("b",2))
ersons.add(new Person("c",3))
for(Person p:persons){
System.out.println(p.getName()+":"+p.getAge())
实例2:(内部类方法)
ublic class Persons2 implements Iterable{
Listpersonlist = new ArrayList()
ublic void add(Person p){
ersonlist.add(p)
ublic Iterator iterator() {
// TODO Auto-generated method stu
return new Iterator(){ //用局部内部类实现
rivate int index=0
ublic boolean hasNext() {
return personlist.size()>index;//可以访问外部类成员
ublic Person next() {
return personlist.get(index++)
ublic void remove() {
ersonlist.remove(index)
这样也能进行foreach循环了
说明:Persons也可直接实现Iterator接口,并实现其hasNext(),next()等方法,但是这样的话Persons必须维护一个索引index,其index值是不确定的,如进行循环一次,index变为a,紧接着进行第二次循环遍历会得到空结果;
方法1和方法2每次进行循环迭代都将产生一个新的索引为0;
37:目录和文件操作
Java提供了java.io.File类对目录和文件进行操作,主要操作方法包括:路径字符串的构造方法、isDirectory、isFile、createNewFile、list(返回文件数组)、getName、delete、getLastModify(返回最近修改时间)、listFile(返回文件名数组)等
38:随机存取文件RandomAccessFile类
主要方法包括new RandomAccessFile(“路径”,”rw|r|w…”)
length()方法获得文件内容长度
eek()定位
read()获取当前位置数据
write()写数据
close()关闭打开的文件
示例:(将文件中所有字母a替换成c)
RandomAccessFile raf =new RandomAccessFile("d:/1.txt", "rw")
int len = (int) raf.length();//length()返回long类型
for(int i=0;i
yte b = (byte) raf.read();//raf.read()返回int类型
char c = (char)b;//字母能转为byte
if(c==’a’){
raf.seek(i)
raf.write(‘c’)
raf.close()
38:字节流和字符流
字节流处理的是计算机最基本的单位byte,它可以处理任何数据格式的数据。主要的操作对象是byte数组,通过read()和write()方法把byte数组的数据写入或读出
字符流有字节流包装而来,字符流创建时,一般要包装一个字节流;inputStreamReader提供字节流向字符流的转换,其构造函数中可以指定字符编码格式;
读取或输出文本一般用BufferedReader.readLine()和PrintWriter.println()方法;
PrintWriter和BufferedWriter同样提供可缓冲输出,但是PrintWriter可设置自动清除缓冲,不需要pw.flush()
PrintWriter pw = new PrintWriter(OutputStreamWirter(“d.txt”,”UTF-8”),true);//true表示自动清除缓冲
注意:①写时需要flush() ,PrintWriter可设定自动清除
②别忘了关闭流
39:序列化
Java可以通过序列化保存或传输一个对象。序列化本质上是把数据,变成一系列的字节数据。然后把这些字节数据写入到流中。
java.io.Serializable接口是可以进行序列化的类的标志性接口,该接口本身没有任何需要实现的方法,仅提供一个能唯一辨别一个类的serialVersionUID.作用是在序列化和反序列化过程中,起到辨别作用。在反序列过程中,若有两个相同类名的类,就通过serialVersionUID来判断到底反序列化成哪个类。
序列化:ObjectInputStream.readObject()
反序列化:ObjectOutputStream.writeObject()
40:进程与线程区别
① 线程隶属于某个进程
② 进程能独占资源,而线程不能
③ 线程是调度和分配的基本单位,进程是拥有资源的基本单位
④ 进程间通信困难,而线程间共享一块内存区域,通信方便
⑤ 创建销毁进程及进程切换系统开销大,而对于线程开销小
41:Runnable接口和Thread类的区别
两者都可以实现多线程编程,区别如下:
① 通过继承Thread方法定义线程就不能继承其他类,而实现Runnable接口方法可以
② Thread方法为“多线程多实例”;Runnable:当多个线程公用一个Runnable时为“多线程单实例”,这时可以共享一个变量,但可能有线程安全问题;当每个线程都有各自的Runnable,则为“多线程多实例”
③ Runnable可以方便的访问同一变量,而Thread需要用内部类实现。
ThreadLocal: 线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。一个ThreadLocal只能存放一个专有对象,若线程需要多个专有对象的话,必须设计多个ThreadLocal。ThreadLocal主要有两个方法set(Object) 和 get()
42:线程安全问题是指两方面的问题:变量安全和线程同步(见深入JDK206页)
解决变量安全的方法:1:多线程多实例 2:变量定义在方法中 3:使用ThreadLocal
解决线程同步问题用synchronized(监视器) 监视器默认为thi
(单实例,多线程中多个Thread基于同一个Runnable创建,Runnable中的变量为多个
Thread共享,所以存在变量安全问题)
ThreadLocal示例:(每个线程都实现从1~10累加)
ublic class Accumulator implements Runnable{
ThreadLocal threadLocal = new ThreadLocal();//创建threadlocal
ublic void run() {
for(int i=1;i<=10;i++){
if(threadLocal.get()==null){
threadLocal.set(new Integer(0))
int x = (Integer) threadLocal.get()
x = x+i
threadLocal.set(x)
try {
Thread.sleep(1000)
} catch (InterruptedException e) {
e.printStackTrace()
System.out.println(Thread.currentThread().getName()+
"\t累加和="+threadLocal.get())
ublic class Main {
ublic static void main(String[] args) {
Accumulator a = new Accumulator();//单实例多线程
Thread t1 = new Thread(a)
Thread t2 = new Thread(a)
t1.start()
t2.start()
说明:单实例多线程,假如不用ThreadLocal方法,在Accumulator中定义一个成员变量SUM保存每次累加和,则线程共享Runnable的变量SUM,会有变量安全问题;若改为多实例多线程则没有这问题;若将SUM定义在run()方法中也没有这样的问题;
43:同步锁Synchronized(括号内为可能发生同步冲突的监视器,默认为this)
当线程执行到Sychronized时候,检查传入的监视器对象,并得到该对象的同步锁,如果得不到(被占用),就会被加入到一个与该监视器对象相关联的等待线程池中,一直等待同步锁被释放,池中的等待线程就会得到该同步锁,然后继续执行下去,当线程执行完同步代码块,就会自动释放它占的同步锁。
44:协调运行—线程通信
wait()方法:使当前调用同步方法的线程等待,直到其他线程调用notify()或notifyAll()
otify():唤醒当前同步监视器(sychronized的参数)上正在等待的单个线程,如果有多个,随机唤醒一个。
otifyAll():唤醒当前同步监视器(sychronized的参数)上正在等待的所有线程
示例:(实现生产者消费者模式)
ublic class Store {//仓库类
rivate final int MAX_SIZE
rivate int count
ublic Store(int size,int c){
MAX_SIZE = size
count = c
//往仓库放货物
ynchronized public void add(){//synchronized默认的同步监视器为this即Store
if(count>=MAX_SIZE){
System.out.println("仓库满了")
try {
wait();//进入与Store实例相关联的等待线程池中
} catch (InterruptedException e) {
e.printStackTrace()
count++
System.out.println("put "+count)
otifyAll();//从线程池中唤醒所有等待线程,(若是producer被唤醒,则从等待处继续执行,(count++处)
//从仓库取货物
ynchronized public void get(){
if(count<=0){
System.out.println("仓库空了")
try {
wait()
} catch (InterruptedException e) {
e.printStackTrace()
System.out.println("get "+count)
count–
otifyAll()
ublic class Producer extends Thread{//生产者线程
rivate Store
ublic Producer(Store s){
this.s =
ublic void run(){
while(true){
.add()
try {
Thread.sleep(500)
} catch (InterruptedException e) {
e.printStackTrace()
ublic class Consumer extends Thread{//消费者线程
rivate Store
ublic Consumer(Store s){
this.s =
ublic void run(){
while(true){
.get()
try {
Thread.sleep(500)
} catch (InterruptedException e) {
e.printStackTrace()
ublic class Main {
ublic static void main(String[] args) {
Store s = new Store(5,0);//单实例多线程 共享仓库
Producer producer1 = new Producer(s)
Producer producer2 = new Producer(s)
Consumer consumer1 = new Consumer(s)
Consumer consumer2 = new Consumer(s)
roducer1.start()
roducer2.start()
consumer1.start()
consumer2.start()
45:JAVA实现线程池
思想:启动一个线程的开销是相当高的,利用线程池,程序向线程池传递一个实现Runnable接口的类的实例时,程序就会从线程池中启动一个空闲线程,并执行run()方法,run方法执行结束后,该线程又成为空闲线程,回到线程池,等待下一个Runnable对象,并执行对象的run()方法,从而大大提高了系统的性能。
通过java.util.concurrent包中的Executors类可以创建线程池对象,即创建线程
池类ExecutorService的实例。
示例:
ublic class Thread1 implements Runnable{
ublic void run() {
System.out.println("this is thread1")
ublic class Thread2 implements Runnable{
ublic void run(){
System.out.println("this is thread2")
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executor
ublic class Main {
ublic static void main(String[] args) {
//创建线程池对象
ExecutorService es = Executors.newFixedThreadPool(5)
es.submit(new Thread1());//传递Runnable接口实现类 这是利用回调吗?
es.submit(new Thread2())
es.shutdown();//关闭线程池对象
46:反射的原理:反射是为了能够动态的加载一个类,动态地调用一个方法,动态地访问
一个属等动态要求而设计的。它的出发点在于JVM会为每个类创建一个java.lang.Class类的实例,通过该对象可以获取这个类的信息,然后通过使用java.lang.reflect包下的API以达到各种动态要求。
类在以下情况下会被加载:
① 需要使用该类创建对象。如Student s = new Student() Student会被加载
② 访问该类的静态成员。 如system.out.println(Calendar.MONDAY)
③ 使用Class类的forName()方法
类一旦被加载,JVM就会为其创建一个Class对象,如何得到一个类的Class对象?
① Class.forName()返回就是一个Class对象
② 类名.cla
③ 对象名.getClass()
47:Field、Method、Construtor
Field通过Class类对象的getDeclaredField()和getDeclaredFields()方法得到;Field方法主要分为两大类:setXXX(object,value)和getXXX(object)其中object为实例对象。
Method通过Class类对象的getMethod()或getMethods()获得,Method最常用的方法是invoke(object,参数…)。
Constructor类通过Class类对象的getConstructor(参数类型.class…)获得。Constructor类最常用的方法是newInstance(),通过构造函数创建实例(Class对象也能通过newInstance()创建实例,但该类中提供无参构造函数)
获得一个类中私有变量:调用Field的setAccessible(true)
示例:
ublic class Person {
ublic String name
rivate int age
ublic Person(){}
ublic Person(String name,int age){
this.name = name
this.age = age
ublic void getInfo(){
System.out.println(name+":"+age)
ublic class Main {
ublic static void main(String[] args) {
Class personclass = Person.cla
try {
Constructor con = personclass.getConstructor(String.class,int.class)
Person person = (Person) con.newInstance("li",20)
Field f = personclass.getDeclaredField("name")
String name = (String) f.get(person)
Field f2 = personclass.getDeclaredField("age")
f2.setAccessible(true);//设置可以访问私有变量age
int age = (Integer) f2.get(person)
System.out.println(name+":"+age)
Method m = personclass.getDeclaredMethod("getInfo",null);//参数为null,可不写
m.invoke(person, null);//调用方法
} catch (Exception e) {
e.printStackTrace()
48:TCP通信特点
① 面向连接的传输
② 端到端的通信
③ 可靠性,确保传输数据的正确性,不出现丢失或乱序
④ 采用字节流方式,即以字节为单位传输字节序列
编程模型:
服务器端:①创建ServerSocket
②accept()等待客户请求
③获得输入流和输出流,并进行传输
④释放资源,关闭输入流输出流、Socket、ServerSocket
49:UDP通信特点
① UDP是一个无连接协议,当它想传送数据时就简单地抓取来自应用程序的数据,并尽可能快地把它扔到网络上
② 不需要维护连接状态,包括收发状态等
③ 字节开销很小,传输速度快,效率高
编程模型:(点对点,没有服务器与客户端之分;分为接收端和发送端)
接收端和客户端都需要有一下步骤:
① 创建DatagramSocket,指定一个端口号.
② 提供一个byte数组进行数据的存储;对于发送端,还需要提供对端的IP地址和端口号。
③ 调用DatagramPacket的receive()或send()方法进行数据的接收或发送
④ 调用DatagramPacket的getData()方法得到byte数组的数据。
⑤ 释放资源
说明: DatagramSocket ds = new DatagramSocket(port);//port为接收端口
接收:DatagramPacket dp = new DatagramPacket(buff,len)
ds.receive(dp)
发送: Datagrampacket dp = new DatagramPacket (str.getBytes() ,0,str.length(),InetAddress.getByName(“localhost”),sendPort);//参数:字节数组,offset,len,主机号或IP,对方接收端口号
ds.send(dp)
50:TCP实现web服务器
ublic class WebServer {
ublic static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(80)
Socket s = null
System.out.println("服务器已启动!")
while(true){
= ss.accept()
ew HTTPThread(s).start()
ublic class HTTPThread extends Thread{
rivate Socket socket
ublic HTTPThread(Socket s){
this.socket =
ublic void run(){
try{
OutputStream os = socket.getOutputStream()
PrintWriter pw = new PrintWriter(os)
w.println("")
w.println("")
w.println("hello world")
w.println("")
w.println("")
w.flush()
w.close()
ocket.close()
}catch(IOException e){
e.printStackTrace()
在浏览器输入http://localhost 会显示hello world
50:UDP实现一个即时聊天软件
QQ、MSN对安全的要求不是太高,一般会采用UDP的通信模式。UDP为点对点模式,没有服务器和客户端之分,两端都创建两个线程,SendThread(发送消息)还有ReceiveThread (接收消息)。代码如下:
ublic class ReceiveThread extends Thread{
rivate DatagramSocket d
ublic ReceiveThread(int recport){
try {
this.ds = new DatagramSocket(recport);//接收端口
} catch (SocketException e) {
e.printStackTrace()
ublic void run(){
try {
yte []buff = new byte[1024]
DatagramPacket dp = new DatagramPacket(buff,1024)
while(true){
ds.receive(dp);//接收数据
String str = new String (dp.getData(),0,dp.getLength())
System.out.println("receive:"+str)
} catch (IOException e) {
e.printStackTrace()
}finally{
ds.close()
ublic class SendThread extends Thread{
rivate DatagramSocket d
rivate int sendPort
ublic SendThread(int sendport,int otherPort){//发送、对方端口
this.sendPort = sendPort
try {
this.ds = new DatagramSocket(sendport);//发送端口
} catch (SocketException e) {
e.printStackTrace()
ublic void run(){
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in))
String str = null
while((str = br.readLine())!=null){
DatagramPacket dp = new DatagramPacket (str.getBytes(),0,str.length(),
InetAddress.getByName("localhost"),otherPort)
ds.send(dp)
System.out.println("send:"+str)
}catch(Exception ex){
ex.printStackTrace()
}finally{
ds.close()
ublic class Chat {
ublic static void main(String[] args) {
ew ReceiveThread(7000).start()
ew SendThread(7500,9000).start();//发送端口和对方接受端口
说明:在本机模拟执行时要两次运行Chat,并且设置好端口。
如第一次为:7000 7500 9000 第二次则为:9000 7600 7000
TCP实现聊天室思路:多线程实现,服务器维护一个socket的List,每次接收消息时遍历list将消息发送给每个客户端。
UDP实现聊天室思路:可以用UDP组播 MultiCastSocekt实现
51:使用JAVA访问WEB站点
网络爬虫的原理就是模拟浏览器挨个访问web站点,得到站点网页的映射
JAVA也可以用编程的方式去访问网站,步骤:
① 用URL创建一个资源定位对象
② 调用URL的openConnection()得到HttpURLConnection对象
③ 调用HttpURLConnection的connect()方法打开连接
④ 用getHeaderFields()方法得到响应结果的头信息
⑤ 用getInputStream()方法得到输入流对象,得到响应内容
ublic class HttpConnTest {
ublic static void main(String[] args) throws Exception{
//创建URL对象
URL url = new URL("http://www.baidu.com")
HttpURLConnection conn = (HttpURLConnection) url.openConnection()
conn.connect();//打开连接
//获取请求响应的头部信息
Map> header = conn.getHeaderFields()
for(String key:header.keySet()){
System.out.println(key+":"+header.get(key))
//获取响应内容
BufferedReader br = new BufferedReader(
ew InputStreamReader(conn.getInputStream(),"UTF-8"))
String str = null
while((str=br.readLine())!=null){
System.out.println(str)
conn.disconnect()
52:JDBC(java data base connectivity)工作原理
JDBC采用了一种驱动模式的设计,提供了两套的接口:开发者使用的API和数据库厂商使用的SPI(service provider interface 数据库厂商需要实现的接口),充分体现了面向接口编程的好处。程序员无需关心具体数据库的连接和调用,只需要使用JDK中提供的标准API编程即可,而具体的实现由特定的数据库生产商提供,也就是JDBC驱动。
53:JDBC编程步骤:
① 注册驱动程序。就是把驱动程序类加载到JVM,一般用Class.forName(“完整类名”)
② 获取数据库连接Connection conn = DriverManager.getConnection(“URL”,”用户名”,”密码”)
③ 创建会话Statement(用于向数据库发送SQL命令,并返回结果) 实际开发中用的更多的是PreparedStatement,它是一种预编译的会话,用占位符的方法效率高,且可以避免SQL注入
④ 执行SQL语句。 executeQuery()或executeUpdate()
⑤ 处理结果集。若是查询操作的话,会返回ResultSet 用其next()方法操作结果集
⑥ 关闭连接。关闭顺序ResultSet、Statement、Conectio
53:如何使用JDBC事务
事务特性:ACID(原子性、一致性、隔离性、持久性)
1. Atomicity(原子性)
原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。
2. Consistency(一致性)
一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务开始前是一个一致状态,事务结束后是另一个一致状态,事务将数据库从一个一致状态转移到另一个一致状态。
3. Isolation(独立性)
从字面上来说,独立性是其中最难理解的一点,但如果结合Oracle中的undo,也就不难理解了。所谓的独立性就是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务还未提交,它所访问的数据就不受未提交事务的影响。换句话说,一个事务的影响在该事务提交前对其它事务是不可见的。
注意:这里的Isolation跟隔离级别(Isolation Level)是无关的。
4. Durability(持久性)
持久性也不难理解,是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。
JDBC使用事务步骤:
① 关闭自动提及事务:conn.setAutoCommit(false)
② 捕获(try catch)执行代码,如果发生异常,在catch中conn.rollback()
③ 关闭连接。一般在finally{}中
54:如何使用可滚动的结果集
Statement stmt = conn.createStatement(sql,type,concurrency)
其中concurrency变量用于指定是否可更新的结果集,可取以下值:
① TYPE_FORWARD_ONLY:不允许滚动,只能向前(next())
② TYPE_SCROLL_INSENSITIVE:可滚动,对数据库变化不敏感,数据库查询生产结果集后若发生变化,结果集不发生变化
③ TYPE_SCROLL_SENSITIVE:可滚动,且对数据库变化敏感
可滚动的结果集方法:
rs.next()、rs.last();//到最后一行、rs.previous();//回一行
rs.absolute(6);//直接定位到第六行
55:如何使用可更新的结果集
当concurrency变量为以下值时:
① CONCUR_READ_ONLY:不能用于更新数据库
② CONCUR_UPDATABLE:结果集可用于更新数据库
如:
PreparedSatement pstmt = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)
rs = pstmt.executeQuery()
rs.last()
//更新最后一行数据
rs.updateString(2,”aaaa”);//修改值
rs.updateRow();//更新
56:什么是Servlet
Servlet在JAVA Web服务器中充当了信息资源的最小表示单位,代表了一个用户可以通过浏览器获取的资源,Servlet可以进行无限的扩展,它可以使用java的所有类库资源,为用户返回文本、图片、视频等各类信息资源。
从编程角度看,Servlet是一个java类,这个类需要实现Servlet接口,提供一个公开的无参构造方法。有WEB容器来控制它的创建、初始化、提供服务、销毁等。它的各种行为方式通过在web.xml中配置决定。
说明:在实际开发中,servelt一般通过继承自javax.servlet.http.HttpServlet
来创建(HttpServlet也是Servlet的实现),它可以为开发者提供一些方法的默认实现,而且可以区别不同的请求方法(doGet() doPost())
57:Servlet生命周期
① 加载。Servlet类加载到JVM中,并且实例化。这个过程中,web容器会调用Servlet类的无参构造方法。默认下,Servlet是在第一次请求时被加载,但可通过在web.xml中配置标签设置在web容器启动时加载。
② 初始化。调用init()方法,如为Servelt配置的初始化参数是在init()中取得的。
③ 提供服务。当有HTTP请求时,调用service()方法。如果是继承自HttpServlet的话,service()会根据请求类型不同调用doGet()或doPost()方法
④ 销毁。当重新部署web应用,关闭web容器时被销毁并调用destroy()方法
Servlet运行时的基本原理
1)、当WEB客户请求Servlet服务或当WEB服务启动时,容器环境加载一个Java Servlet类。
2)、容器环境也将根据客房请求创建一个Servlet对象实例,或者创建多个Servlet对象实例,并把这些实例加入到Servlet实例池中。
3)、容器环境调用Servlet的初始化方法HttpServlet.init()进行Servlet实例化。在调用初始化时,要给init()方法传入一个ServletConfig对象,ServletConfig对象包含了初始化参数和容环境的信息,并负责向servlet传递信息,如果传递失败,则会发生ServletException。Servlet将不能正常工作。
4)、容器环境利用一个HttpServletRequest和HttpServletResponse对象,封装从Web客户接收到的HTTP请求和由Servlet生成的响应。
5)、容器环境把HttpServletRequest和HttpServletResponse对象传递给HttpServlet.Service()方法。这样,一个定制的Java Servlet就可以访问这种HTTP请求和响应接口。Servlet()方法可被多次调用,各调用过程运行在不同的线程中,互不干扰。
6)、定制的Java Servlet从HttpServletRequest对象读取HTTP请求数据,访问来自HttpSession或Cookie对象的状态信息,进行特定应用的处理,并且用HttpServletResponse对象生成HTTP响应数据。
7)、当WEB服务器和容器关闭时,会自动调用HttpServlet.destroy()方法关闭任何打开的资源,并进行一些关闭前的处理。
ervlet 的生命周期。
Servlet 运行在 Servlet 容器中,其生命周期由容器来管理。 Servlet 的生命周期通过 Servlet 接口中 init ()、 service ()、 destroy ()方法来表示。
Servlet 的生命周期包含了下面 4 个阶段。
(1) 加载和实例化
Servlet 容器负责加载和实例化 Servlet 。当 Servlet 容器启动时,或者在容器检查到需要这个 Servlet 来响应一个请求时,创建 Servlet 实例。当 Servlet 容器启动后,它必须要知道所需的 Servlet 类在什么位置, Servlet 容器可以从本地文件系统、远程文件系统或者其他网络服务器中通过类加载器加载 Servlet 类,成功加载后,容器创建 Servlet 实例。因为容器是通过 Java 的反射 API 来创建 Servlet 实例,调用的是 Servlet 的默认构造函数,也就是那个不带参数的构造函数,所以我们在编写 Servlet 类的时候,不应该提供带参数的构造函数。——这也就是为什么 Servlet 类可以不写构造函数的原因。
(2) 初始化
在 Servlet 实例化之后,容器必须调用 Servlet 的 init ()方法初始化这个对象。初始化的目的是为了让 Servlet 对象在处理客户请求前完成一些初始化工作,如建立数据库连接,获取配置信息等。对于每一个 Servlet 实例, init ()方法只能被调用一次。在初始化期间, Servlet 实例可以使用容器为它准备的 ServletConfit 对象从 web 应用程序的配置信息(在 web.xml 中配置)中获取初始化的参数信息。在初始化期间,如果发生错误, Servlet 实例可以抛出异常来通知容器。
(3) 请求处理
Servlet 容器调用 Servlet 的 service ()方法对请求进行处理。要注意的是,在 service ()方法调用之前, init ()方法必须成功执行。在 service ()方法中, servlet 实例通过 ServletRequest 对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用 servletResponse 对象的方法设置响应信息。
(4) 服务终止
当容器检测在一个 Servlet 实例应该从服务中被移除的时候,容器就会调用实例的 destroy ()方法,以便让该实例可以释放它所使用的资源,保存数据到持久存储设备中。当需要释放内存或者容器关闭时,容器就会调用 Servlet 实例的 destroy ()方法。在调用 destroy ()方法后,容器会释放这个 Servlet 实例,该实例随后会被 java 的垃圾收集器回收。
在整个 Servlet 的生命周期过程中,创建 Servlet 实例、调用实例的 init ()和 destroy ()方法都只进行一次,当初始化完成后, Servlet 容器会将该实例保存在内存中,通过调用它的 service ()方法,为接收到的请求服务。
58:在web.xml中Servlet的标准配置
LoginServlet
com.abc.LoginServelt
myparam
100
0
LoginServlet
/*Servlet
59:Forward(直接转发或请求转发)和Redirect(间接转发或重定向)的区别
① 直接转发或请求转发:
RequestDspatcher rs = request.getRequestDispatcher(“url”)
Rs.forward(request,response)
本质上是一次请求,共享同一个request对象,地址栏地址不会改变
② 间接转发或重定向response.sendRedirect(“url”)
本质上是两次请求,对应两个不同request对象,请求信息不一样。
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。还有,转发是在web应用程序之内进行的,可以访问web应用程序所设定的内部目录,像是WEB-INF目录,只能在Web应用程序中进行,不能指定至其它的Web应用程序的地址。
redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。web应用程序会要求客户端浏览器重新发出请求地址,客户端会重新连接至所指定的地址,因此浏览器的地址会出现重新导向的信息,重新导向后的请求由浏览器发出,所以不能访问Web应用程序中的隐藏目录,像是WEB-INF,重新是由浏览器重新要求一个网页,可以指定至其他的Web应用程序地址。
RequestDispatcher.forward()方法和HttpServletResponse.sendRedirect()方法的区别是:前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址,他是不会改变Request的值,如果你需要在下一个页面中能从中获取新的信息的话,你可以Request.setAttribute()来放置一些标志,这样从下一个页面中获取;后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量使用RequestDispatcher.forward()方法,并且,这样也有助于隐藏实际的链接。在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用 HttpServletResponse.sendRequest()方法。
1、forward与include共亨Request范围内的对象,而redirect则不行,即:如果一个javabean被声明为request范围的话,则被forward到的资源也可以访
问这个javabean,而redriect则不行。
2、forward与include基本上都是转发到context内部的资源,而redirect可以重定向到外部的资源,如: req.sendRedriect
1、从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送
的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
2、从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
3、从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
4、从效率来说
forward:高.
redirect:低.
不要仅仅为了把变量传到下一个页面而使用session作用域,那会无故增大变量的作用域,转发也许可以帮助你解决这个问题。
redirect:以前的request中存放的变量全部失效,并进入一个新的request作用域。
forward:以前的request中存放的变量不会失效,就像把两个页面拼到了一起。
他们的调用分别如下:
request.getRequestDispatcher("apage.jsp").forward(request, response); //转发到apage.j
response.sendRedirect("apage.jsp"); //重定向到apage.j
在jsp页面中你也会看到通过下面的方式实现转发:
60:过滤器的作用和原理
过滤器是处于web容器内的一个组件,它会过滤特定请求和响应.当一个请求到来时,web容器判断是否有过滤器与该信息资源关联,若有,则交给过滤器—处理,然后交给目标资源。响应的时候则以相反的顺序交给过滤器,最后返回给用户。过滤器是一种很重要的设计模式(基于AOP思想)可以再不侵入原有代码的基础上为它们提供一些功能。Struts就是利用过滤器工作的。
过滤器要实现javax.servlet.Filter接口,并实现doFilter()方法。
ublic class MyFilter implements Filter{
//过滤器的业务逻辑方法
ublic void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//业务代码
chain.doFilter(request, response);//将请求转发给下一个过滤器或目标资源
ublic void init(FilterConfig arg0) throws ServletException {
//初始化代码
ublic void destroy() {
//释放资源代码
Web.xml中配置:
MyFilter
com.abc.MyFilter
MyFilter
/*Servlet
61:监听器的作用和工作原理
对于web应用程序来说,监听器是处于web容器内的一个组件,它会对web容器中的request,session和application 3种对象进行监听。当这些对象在创建或销毁时,web容器主动调用它们的初始化和销毁方法。
Request事件监听接口ServletRequestListener
Session事件监听接口HttpSessionListener
Application事件监听接口ServletContextListener
应用:当用户第一次访问web应用程序是,程序将在线人数加1
62:JSP的运行机制
JSP本质上是Servlet,但JSP的存在是必要的,因为Servlet在处理静态内容(如HTML标签)时非常笨拙,不得不以字符串形式进行拼接,而JSP可以很好的实现动态和静态内容的分离。
当客户端发出一次对某个JSP的请求,web容器处理该请求过程如下:
① web容器会检验JSP的语法是否正确
② 将JSP文件转换成Servlet的源代码文件
③ 编译该源代码文件称为class文件
④ 创建一个该Servlet类的对象实例,为请求提供服务
说明:JSP只会在第一次访问时才转换盒编译。以后的访问web容器就直接调用编译好的servlet对象实例了,如果JSP被修改过,整个过程重新执行一次。
63:JSP内置对象及用途(见文档)
request   类型 javax.servlet.ServletRequest 作用域 Request
response 类型 javax.servlet.SrvletResponse 作用域 Page
ageContext 类型 javax.servlet.jsp.PageContext 作用域 Page
ession 类型 javax.servlet.http.HttpSession 作用域 Sessio
application 类型 javax.servlet.ServletContext 作用域 Applicatio
out 类型 javax.servlet.jsp.JspWriter 作用域 Page
config 类型 javax.servlet.ServletConfig 作用域 Page
age 类型 javax.lang.Object 作用域 Page
exception 类型 javax.lang.Throwable 作用域 page
64:JSP作用域
JSP比Servlet多了一种页面范围(page),一共四种作用域:page,request,session和application。
Request范围指的是一次请求,如果请求指向一个单一的JSP文件,则此时的page和request的生命周期是一样的,但是如果一次请求经过多次请求转发(forward),则这个request周期可以为多个page周期之和
65:jsp中使用javabea
JavaBean规范:
① 是一个公开类
② 提供一个无参数的构造方法
③ 提供了公开的setXXX和getXXX
JSP使用javabean两种方法
① 纯JAVA代码,如Dog dog = new Dog()
② Jsp动作标签
Scope属性默认为page
66:表达式语言EL和JSTL(详见文档EL OGNL JSTL)
EL是一种数据表现语言 JSTL是一个标签库,而EL是从JSTL诞生出来的
EL用${people.name}方法 区别于OGNL{#person.name}或{person.name}(根对象)
67:Struts框架是如何体现MVC模式的?
Controller由ActionServlet、Action和Struts-config.xml组成。
Model由ActionForm来实现
View主要由JSP实现
一次典型的Struts请求是这样的:客户端(浏览器)发送请求,然后ActionServlet接收到请求后,会根据请求的路径和参数来判断由哪个Action来处理该次请求。等到Action处理完成以后,通常是Execute方法调用完成以后,Struts会根据该方法返回的ActionForward来判断由哪个JSP来作为最终响应。
68:Hibernate实体存在哪几种状态
瞬时态、持久态、脱管态
69:Hibernate继承关系的映射策略
有三个类 Animal Dog Cat
单表策略:当所有子类都在一张表中,只需建一个Animal.hbm.xml 用添加子类
//区别子类的字段
//子类
多表策略:当每个子类一张表,只需建一个Animal.hbm.xml 用添加子类
< joined-subclass name=”Dog” table=”dog”>//子类 需指明表名
//指明dog表的主键 同时为指向animal的外键
< joined-subclass …>…
这样数据库有三个表animal dog cat 其中dog,cat共同属性放在animal表中
单表策略:无需表连接,查询速度快,适合多态查询(查询有继承关系的类时,同时查询到多个子类),缺点是可能造成表太大的结果(因为每个子类属性不一样,造成很多NULL),不利于维护。
多表策略:数据存储比较紧凑,当查询某个子类的数据时速度比较快,缺点是可能会有很多的表连接,不太适合多态查询
69:AOP原理
AOP是一种对OOP有益补充的编程技术,它可以解决OOP和过程化方法不能够很好解决的横切问题,如事务,安全,日志等。随着软件系统变得越来越复杂,横切关注点成为一个大问题,AOP可以很轻松的解决横切关注点这个问题,Spring框架对AOP提供了很好的支持。简单来说,AOP就是一种功能比较复杂的拦截器。在代码真正达到目标以前,AOP可以对其进行拦截,提供一些通用的中间件的服务,例如,加上事务服务,记录日志等。Spring的声明式事务也就是基于AOP实现的。
70:打印1000以内的回文数字
for(int i=10;i<10000;i++){
int temp = i
int reverse = 0
while(temp>0){//反序
reverse = reverse*10+temp%10
temp=temp/10
if(i==reverse){
System.out.println(i)
//判断一个字符串是否回文
String str = "abababa"
StringBuffer str2 = new StringBuffer(str)
tr2 = str2.reverse()
if(str.equals(str2.toString())){
System.out.println("回文")
71:50个人围城一圈数到3和3的倍数时出圈,问剩下的人是谁,在原来的位置是多少?
ublic static void main(String []args) {
Listlist = new LinkedList()
for(int i=1;i<=50;i++){//模拟50人
list.add(i)
int index=-1;//模拟当前数的数字
while(list.size()>1){//多于一个人
//取余 如果数到最后一个人,循环
index = (index+3)%list.size();//
//因为删除一个元素后,后边元素自动前移,所以索引减一
list.remove(index–)
System.out.println(list.get(0))


你可能感兴趣的:(Java,java,面试,基础,daima)