超详细的Java面试题汇总(基础篇+框架篇)

版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接 ! https://blog.csdn.net/jex00000/article/details/86671260

Java面试题汇总-基础篇

1.面向对象是什么?

答:面向对象是一种思想,世间万物都可以看做一个对象,这里只讨论面向对象编程(OOP),Java是一个支持并发、基于类和面向对象的计算机编程语言,面向对象软件开发的优点:代码开发模块化,更易维护和修改;代码复用性强;增强代码的可靠性和灵活性;增加代码的可读性。

2、String 是最基本的数据类型吗?

答:不是。Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type)和枚举类型(enumeration type),剩下的都是引用类型(reference type)。

3、float f=3.4;是否正确?

答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。

4、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?

答:对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换。

5、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?

答:可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。

6、Java有没有goto?

答:java中的保留字,现在没有在java中使用。

7、int和Integer有什么区别?

答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类就是Integer,从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。

public static void main(String[] args) {
    Integer a = new Integer(3);
    Integer b = 3;                  // 将3自动装箱成Integer类型
    int c = 3;
    System.out.println(a == b);     // false 两个引用没有引用同一对象
    System.out.println(a == c);     // true a自动拆箱成int类型再和c比较
  }

还有一个面试题,也是和自动装箱和拆箱有点关系的,代码如下所示:

public static void main(String[] args) {
    Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
    System.out.println(f1 == f2);
    System.out.println(f3 == f4);
  }

如果不明就里很容易认为两个输出要么都是true要么都是false。首先需要注意的是f1、f2、f3、f4四个变量都是Integer对象引用,所以下面的==运算比较的不是值而是引用。装箱的本质是什么呢?当我们给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,代码如下:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high) {
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
  }
}

简单的说,如果整型字面量的值在-128到127之间,那么不会new新的Integer对象,而是直接引用常量池中的Integer对象,所以上面的面试题中f1= =f2的结果是true,而f3==f4的结果是false。

8、解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法。

栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间

String str = new String("hello");

上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而”hello”这个字面量放在静态区。

9、构造器(constructor)是否可被重写(override)?

答:构造器不能被继承,因此不能被重写,但可以被重载。

10、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

答:不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同

11、是否可以继承String类?

答:String 类是final类,不可以被继承。

12、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

答:是值传递。Java语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的。

13、Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?

答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。

14、switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?

答:expr可以是byte、short、char、int、enum、String类型,但是long类型不能。

15、用最有效率的方法计算2乘以8?

答: 2 << 3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)。

16、数组有没有length()方法?String有没有length()方法?

答:数组没有length()方法,有length 的属性。String 有length()方法。JavaScript中,获得字符串的长度是通过length属性得到的,这一点容易和Java混淆。

17、char型变量中能不能存贮一个中文汉字?为什么?

可以存储,因为java中使用的编码是Unicode编码,一个char类型占2个字节(16bit),放一个中文汉字是没有问题的。
Unicode编码:不选择任何特定的编码,直接使用字符在字符集中的编码,这是统一的唯一方法。

18、用最有效率的方法算出2乘以8等於几?

2 << 3,因为将一个数左移n位,就相当于乘以了2的n次方,那么,一个数乘以8只要将其左移3位即可,而位运算cpu直接支持的,效率最高,所以,2乘以8等於几的最效率的方法是2 << 3。

19、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。

20、重载(Overloading)和重写(Override)的区别

重载(Overloading):多个同名函数同时存在,参数类型和参数个数不通,返回值类型可同可不同,统一方式处理不同类型的数据。这也是java特性中多态性的一种体现,一个类中的多态性。
重写(Override):子类中重新父类的方法,也叫做方法覆盖,方法名与父类相同,参数返回类型相同,子类的修饰权限不能够低于父类不同类之间多态的体现。

21、"=="和equals的区别

“==”: 比较变量值是否相等(数值) 相当于比较的是地址
“equals”: 两个独立对象的内容是否相同 比较的是内容

22、静态变量和实例变量的区别

静态变量:静态变量也叫做类变量,static修饰,在类中,为类所有,只要程序加载啦字节码文件,不用创建实例对象就会自动的为静态变量分配内存空间。所有对象共有,其中一个对象将其值改变,其他对象得到的就是改变后的结果。
实例变量:new了对象之后,才会分配内存空间。当前对象私有,改变其值,不会影响其他对象。

23、是否可以从一个static方法内部发出对非static方法的调用?

答:不可以。因为static方法的调用可以直接通过类名.方法名()调用,不用创建对象。而非static方法要与对象关联在一起的,必须要创建对象之后才可以在该对象上进行方法的调用,所以是不可以的。

24、多线程有几种实现方法?同步有几种实现方法?

多线程有两种实现方法:继承Thread类与实现Runnable接口
同步的实现方面有两种:synchronized,wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

25、启动一个线程是用run()还是start()?

启动一个线程是调用start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码。

26、List 、Map、Set区别?

List:存储单列数据的集合,数据有序,并且允许重复。
Map:数据无序,键值集合,键不可以重复,值是可以重复的。
Set:数据无序,无重复对象。

27、Collection 和 Collections的区别?

Collection:集合类的上级接口,继承与他的接口主要有Set 和List.
Collections:针对集合类的一个帮助类,提供了一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

28、当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?

答:不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁。

29.如果两个键的hashcode相同,你如何获取值对象?

答:当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,然后会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。

30、GC是什么?为什么要有GC?

答:GC是垃圾收集的意思,垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。

31、Java 中 bytes 与其他类型的转换?

public class Test {          
    private static ByteBuffer buffer = ByteBuffer.allocate(8);        
    public static void main(String[] args) {    
             
        //测试 int 转 byte    
        int int0 = 234;    
        byte byte0 = intToByte(int0);    
        System.out.println("byte0=" + byte0);//byte0=-22    
        //测试 byte 转 int    
        int int1 = byteToInt(byte0);    
        System.out.println("int1=" + int1);//int1=234    
 
        //测试 int 转 byte 数组    
        int int2 = 1417;    
        byte[] bytesInt = intToByteArray(int2);    
        System.out.println("bytesInt=" + bytesInt);//bytesInt=[B@de6ced    
        //测试 byte 数组转 int    
        int int3 = byteArrayToInt(bytesInt);    
        System.out.println("int3=" + int3);//int3=1417    
             
             
        //测试 long 转 byte 数组    
        long long1 = 2223;    
        byte[] bytesLong = longToBytes(long1);    
        System.out.println("bytes=" + bytesLong);//bytes=[B@c17164    
        //测试 byte 数组 转 long    
        long long2 = bytesToLong(bytesLong);    
        System.out.println("long2=" + long2);//long2=2223    
    }    
         
         
    //byte 与 int 的相互转换    
    public static byte intToByte(int x) {    
        return (byte) x;    
    }    
         
    public static int byteToInt(byte b) {    
        //Java 总是把 byte 当做有符处理;我们可以通过将其和 0xFF 进行二进制与得到它的无符值    
        return b & 0xFF;    
    }    
         
    //byte 数组与 int 的相互转换    
    public static int byteArrayToInt(byte[] b) {    
        return   b[3] & 0xFF |    
                (b[2] & 0xFF) << 8 |    
                (b[1] & 0xFF) << 16 |    
                (b[0] & 0xFF) << 24;    
    }    
     
    public static byte[] intToByteArray(int a) {    
        return new byte[] {    
            (byte) ((a >> 24) & 0xFF),    
            (byte) ((a >> 16) & 0xFF),       
            (byte) ((a >> 8) & 0xFF),       
            (byte) (a & 0xFF)    
        };    
    }     
    //byte 数组与 long 的相互转换    
    public static byte[] longToBytes(long x) {    
        buffer.putLong(0, x);    
        return buffer.array();    
    }    
    public static long bytesToLong(byte[] bytes) {    
        buffer.put(bytes, 0, bytes.length);    
        buffer.flip();//need flip     
        return buffer.getLong();    
    }    
}

32、用 wait-notify 写一段代码来解决生产者-消费者问题?

在同步块中调用 wait() 和 notify()方法,如果阻塞,通过循环来测试等待条件。请参考答案中的示例代码。

【生产者】

package com.edu.chapter03.test;  
import java.util.Vector;  
import java.util.logging.Level;  
import java.util.logging.Logger;  
  
public class Producer implements Runnable {  
  
    private final Vector sharedQueue;  
    private final int SIZE;  
      
    public Producer(Vector sharedQueue, int size) {  
        this.sharedQueue = sharedQueue;  
        this.SIZE = size;  
    }  
      
   @Override  
    public void run() {  
        // TODO Auto-generated method stub  
        for (int i = 0; i < 7; i++) {  
            System.out.println("Produced:" + i);  
            try {  
                produce(i);  
            } catch (InterruptedException ex) {  
                Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);  
            }  
        }  
    }  
  
    private void produce(int i) throws InterruptedException {  
          
        //wait if queue is full  
        while (sharedQueue.size() == SIZE) {  
            synchronized (sharedQueue) {  
                System.out.println("Queue is full " + Thread.currentThread().getName()  
                        + " is waiting , size: " + sharedQueue.size());  
                sharedQueue.wait();  
            }  
        }  
          
        //producing element and notify consumers  
        synchronized (sharedQueue) {  
            sharedQueue.add(i);  
            sharedQueue.notifyAll();  
        }  
    }  
}  

【消费者】

package com.edu.chapter03.test;  
import java.util.Vector;  
import java.util.logging.Level;  
import java.util.logging.Logger;  
  
public class Consumer implements Runnable {  
  
    private final Vector sharedQueue;  
    private final int SIZE;  
      
    public Consumer(Vector sharedQueue, int size) {  
        this.sharedQueue = sharedQueue;  
        this.SIZE = size;  
    }  
  
    @Override  
    public void run() {  
        // TODO Auto-generated method stub  
        while (true) {  
            try {  
                System.out.println("Consumer: " + consume());  
                Thread.sleep(50);  
            } catch (InterruptedException ex) {  
                Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);  
            }  
        }  
    }  
      
    private int consume() throws InterruptedException {  
          
        //wait if queue is empty  
        while (sharedQueue.isEmpty()) {  
            synchronized (sharedQueue) {  
                System.out.println("Queue is empty " + Thread.currentThread().getName()  
                        + " is waiting , size: " + sharedQueue.size());  
                sharedQueue.wait();  
            }  
        }  
          
        //otherwise consume element and notify waiting producer  
        synchronized (sharedQueue) {  
            sharedQueue.notifyAll();  
            return (Integer) sharedQueue.remove(0);  
        }  
    }  
}  

【测试函数】

package com.edu.chapter03.test;  
import java.util.Vector;  
  
public class ProducerConsumerSolution {  
  
    public static void main(String[] args) {  
        Vector sharedQueue = new Vector();  
        int size = 4;  
        Thread prodThread = new Thread(new Producer(sharedQueue, size), "Producer");  
        Thread consThread = new Thread(new Consumer(sharedQueue, size), "Consumer");  
        prodThread.start();  
        consThread.start();  
    }  
} 

33、 用 Java 写一个线程安全的单例模式(Singleton)?

当我们说线程安全时,意思是即使初始化是在多线程环境中,仍然能保证单个实例。Java 中,使用枚举作为单例类是最简单的方式来创建线程安全单例模式的方式。请参考答案中的示例代码,这里面一步一步教你创建一个线程安全的 Java 单例类。

立即加载/饿汉式:

【在调用方法前,实例就已经被创建】

package com.weishiyao.learn.day8.singleton.ep1;
 
public class MyObject {
  // 立即加载方式==恶汉模式
  private static MyObject myObject = new MyObject();
 
  private MyObject() {
  }
  
  public static MyObject getInstance() {
    // 此代码版本为立即加载
    // 此版本代码的缺点是不能有其他实例变量
    // 因为getInstance()方法没有同步
    // 所以有可能出现非线程安全的问题
    return myObject;
  }
}

【创建线程类】

package com.weishiyao.learn.day8.singleton.ep1;
 
public class MyThread extends Thread {
  @Override
  public void run() {
    System.out.println(MyObject.getInstance().hashCode());
  }
}

【创建运行类】

package com.weishiyao.learn.day8.singleton.ep1;
 
public class Run {
  public static void main(String[] args) {
    MyThread t1 = new MyThread();
    MyThread t2 = new MyThread();
    MyThread t3 = new MyThread();
    t1.start();
    t2.start();
    t3.start();
  }
}

延迟加载/懒汉式:

【建对象的实例】

package com.weishiyao.learn.day8.singleton.ep2;
 
public class MyObject {
  private static MyObject myObject;
  
  private MyObject() {
    
  }
  
  public static MyObject getInstance() {
    // 延迟加载
    if (myObject != null) {
      
    } else {
      myObject = new MyObject();
    }
    return myObject;
  }
}

【创建线程类】

package com.weishiyao.learn.day8.singleton.ep2;
 
public class MyThread extends Thread {
  @Override
  public void run() {
    System.out.println(MyObject.getInstance().hashCode());
  }
}

【创建运行类】

package com.weishiyao.learn.day8.singleton.ep2;
 
public class Run {
  public static void main(String[] args) {
    MyThread t1 = new MyThread();
    t1.start();
  }
}

【运行测试类】

package com.weishiyao.learn.day8.singleton.ep2;
 
public class Run {
  public static void main(String[] args) {
    MyThread t1 = new MyThread();
    MyThread t2 = new MyThread();
    MyThread t3 = new MyThread();
    MyThread t4 = new MyThread();
    MyThread t5 = new MyThread();
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();
  }
}

java面试题汇总-框架篇

一、Spring面试题

1、Spring下的注解?

注册:@Controller @Service @Component
注入:@Autowired @Resource
请求地址:@RequestMapping
返回具体数据类型而非跳转:@ResponseBody

2、Spring DI 的三种方式?

构造器注入:通过构造方法初始化

<constructor-arg index="0" type="java.lang.String" value="宝马"></constructor-arg>

setter方法注入:通过setter方法初始化

<property name="id" value="1111"></property>

接口注入

3、Spring主要使用了什么模式?

工厂模式:每个Bean的创建通过方法
单例模式:默认的每个Bean的作用域都是单例
代理模式:关于Aop的实现通过代理模式

4、Spring 在ssm中起什么作用?

Spring:轻量级框架
作用:Bean工厂,用来管理Bean的生命周期和框架集成。
两大核心:
①. IOC/DI(控制反转/依赖注入) :把dao依赖注入到service层,service层反转给action层,Spring顶层容器为BeanFactory。
②. AOP:面向切面编程

5、Spring的事务?

编程式事务管理:编程方式管理事务,极大灵活性,难维护。
声明式事务管理:可以将业务代码和事务管理分离,用注解和xml配置来管理事务。

6、IOC,AOP的实现原理?

IOC:通过反射机制生成对象注入
AOP:动态代理

7、IOC 在项目中的作用?

作用:Ioc解决对象之间的依赖问题,把所有Bean的依赖关系通过配置文件或注解关联起来,降低了耦合度。

8、Spring的配置文件中的内容?

开启事务注解驱动
事务管理器
开启注解功能,并配置扫描包
配置数据库
配置SQL会话工厂,别名,映射文件
不用编写Dao层的实现类

二、SpringMvc面试题

1、SpringMvc中函数的返回值?

String,ModelAndView,List,Set 等
一般String,Ajax请求,返回一个List集合

2、SpringMvc中的转发和重定向?

转发: return:“hello”
重定向 :return:“redirect:hello.jsp”

3、SpringMvc和Ajax之间的相互调用?

通过JackSon框架把java里面对象直接转换成js可识别的json对象,具体步骤如下:
加入JackSon.jar
在配置文件中配置json的映射
在接受Ajax方法里面直接返回Object,list等,方法前面需要加上注解@ResponseBody

4、SpringMvc的工作流程图?

image

5、SpringMvc 的控制器是不是单例模式,如果是,有什么问题,怎么解决?

问题:单例模式,在多线程访问时有线程安全问题
解决方法:不要用同步,在控制器里面不能写字段

6、SpringMvc 中控制器的注解?

@Controller:该注解表明该类扮演控制器的角色

7、Struts2 和 SpringMvc的区别?

入口不同:
Struts2:filter过滤器
SpringMvc:一个Servlet即前端控制器

开发方式不同:
Struts2:基于类开发,传递参数通过类的属性,只能设置为多例
SpringMvc:基于方法开发(一个url对应一个方法),请求参数传递到方法形参,可以为单例也可以为多例(建议单例)

请求方式不同:
Struts2:值栈村塾请求和响应的数据,通过OGNL存取数据
SpringMvc:通过参数解析器将request请求内容解析,给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面,jsp视图解析器默认使用的是jstl。

8、@RequestMapping 注解用在类上的作用?

作用:用来映射一个URL到一个类或者一个特定的处理方法上

9、前台多个参数,这些参数都是一个对象,快速得到对象?

方法:直接在方法中声明这个对象,SpringMvc就自动把属性赋值到这个对象里面

Struts2面试题

1、在struts2中如何实现转发和重定向?

答:在struts.xml中配置type=“redirect”(重定向);type=“redirectAction”(转发)

2、Struts2中的type类型有哪些?至少写4种

答:chain,redirect,redirectAction,json,dispatcher

3、struts2默认能解决get和post提交方式的乱码问题吗?

答:不能。struts.i18n.encoding=UTF-8属性值只能解析POST提交下的乱码问题。

4、说下Struts的设计模式

答:MVC模式:
1.web应用程序启动时就会加载并初始化ActionServler。
2.用户提交表单时,一个配置好的ActionForm对象被创建,并被填入表单相应的数据,ActionServler根据Struts-config.xml文件配置好的设置决定是否需要表单验证,如果需要就调用ActionForm的Validate()验证后选择将请求发送到哪个Action,如果Action不存在,ActionServlet会先创建这个对象,然后调用Action的execute()方法.
3.Execute()从ActionForm对象中获取数据,完成业务逻辑,返回一个ActionForward对象,ActionServlet再把客户请求转发给ActionForward对象指定的jsp组件,ActionForward对象指定的jsp生成动态的网页,返回给客户。

5、拦截器和过滤器的区别

答:拦截器和过滤器的区别是:
1.拦截器是基于java反射机制的,而过滤器是基于函数回调的。
2.过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。
3.拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。
4.拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。
5.在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。

6、ActionContext、ServletContext、pageContext的区别?

答:ActionContext、ServletContext、pageContext的区别是:
1.ActionContext是当前的Action的上下文环境,通过ActionContext可以获取到request、session、ServletContext等与Action有关的对象的引用;
2.ServletContext是域对象,一个web应用中只有一个ServletContext,生命周期伴随整个web应用;
3.pageContext是JSP中的最重要的一个内置对象,可以通过pageContext获取其他域对象的应用,同时它是一个域对象,作用范围只针对当前页面,当前页面结束时,pageContext销毁, 生命周期是JSP四个域对象中最小的。

7、什么是国际化,struts2实现国际化的原理?

答:国际化是根据不同的国家和地区的语言文化的不同,所设计的适用于不同地区的编码格式。
实现方法:
1.首先在src目录下新建message_en.properties(英文);
2.页面获取国际化信息或者使用

原理:程序得到当前运行环境的国际/区域,语言环境并存放于Locale,ResourceBundle根据Locale中信息自动搜索对应的国际化资源文件并加载。

8、描述Struts2的工作原理

答:客户端发送请求–》请求经过一系列过滤器–》FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action --》FilterDispatcher把请求的处理交给ActionProxy–》通过ConfigurationManager询问Struts配置文件(Struts.xml),找到需要调用的Action类–》ActionProxy创建一个ActionInvocation的实例 --》调用Action–》执行完毕,返回结果。

9、Struts2有哪些优点?

答:Struts2的优点如下:
1.在软件设计上Struts2的应用可以不依赖于Servlet API和struts API。 Struts2的这种设计属于无侵入式设计;
2.拦截器,实现如参数拦截注入等功能;
3.类型转换器,可以把特殊的请求参数转换成需要的类型;
4.多种表现层技术,如:JSP、freeMarker、Velocity等;
5.Struts2的输入校验可以对指定某个方法进行校验;
6.提供了全局范围、包范围和Action范围的国际化资源文件管理实现
7.实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现。有丰富的tag可以用,大大提高了开发效率。(简要)

三、Hibernate面试题

1、Hibernate中的SessionFactory有什么作用? SessionFactory是线程安全的吗?

答:SessionFactory就是一个用于创建Hibernate的Session对象的工厂。SessionFactory通常是在应用启动时创建好的,应用程序中的代码用它来获得Session对象。作为一个单个的数据存储,它也是 线程安全的,所以多个线程可同时使用同一个SessionFactory。Java JEE应用一般只有一个SessionFactory,服务于客户请求的各线程都通过这个工厂来获得Hibernate的Session实例,这也是为什么SessionFactory接口的实现必须是线程安全的原因。还有,SessionFactory的内部状态包含着同对象关系影射有关的所有元数据,它是 不可变的,一旦创建好后就不能对其进行修改了。

2、 Hibernate的查询方式

答:HQL、Criteria、Sql

3、如何优化Hibernate?

答:优化Hibernate的方法如下:
1.使用双向一对多关联,不使用单向一对多
2.灵活使用单向一对多关联
3.不用一对一,用多对一取代
4.配置对象缓存,不使用集合缓存
5.一对多集合使用Bag,多对多集合使用Set
6.继承类使用显式多态
7.表字段要少,表关联不要怕多,有二级缓存撑腰

####4、在数据库中条件查询速度很慢的时候,如何优化?
答:优化数据库中条件查询速度的方法如下:
1.建索引
2.减少表之间的关联
3.优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据量大的表排在前面
4.简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据

####5、Hibernate中的Session指的是什么? 可否将单个的Session在多个线程间进行共享?
答:Session代表着Hibernate所做的一小部分工作,它负责维护者同数据库的链接而且 不是线程安全的,也就是说,Hibernage中的Session不能在多个线程间进行共享。虽然Session会以主动滞后的方式获得数据库连接,但是Session最好还是在用完之后立即将其关闭。

6、Hibernate中get和load有什么不同之处?

答:get和load的最大区别是,如果在缓存中没有找到相应的对象,get将会直接访问数据库并返回一个完全初始化好的对象,而这个过程有可能会涉及到多个数据库调用;而load方法在缓存中没有发现对象的情况下,只会返回一个代理对象,只有在对象getId()之外的其它方法被调用时才会真正去访问数据库,这样就能在某些情况下大幅度提高性能。你也可以参考 Hibernate中get和load的不同之处, 此链接给出了更多的不同之处并对该问题进行了更细致的讨论。

7、Hibernate中save、persist和saveOrUpdate这三个方法的不同之处?

答:也就是save()、saveOrUpdate()和persist()都是用于将对象保存到数据库中的方法,但其中有些细微的差别。例如,save()只能INSERT记录,但是saveOrUpdate()可以进行 记录的INSERT和UPDATE。还有,save()的返回值是一个Serializable对象,而persist()方法返回值为void。你还可以访问 save、persist以及saveOrUpdate,找到它们所有的不同之处。

8、Hibernate中的命名SQL查询指的是什么?

答:命名查询指的是用标签在影射文档中定义的SQL查询,可以通过使用Session.getNamedQuery()方法对它进行调用。命名查询使你可以使用你所指定的一个名字拿到某个特定的查询。 Hibernate中的命名查询可以使用注解来定义,也可以使用我前面提到的xml影射问句来定义。在Hibernate中,@NameQuery用来定义单个的命名查询,@NameQueries用来定义多个命名查询。

9、hibernate中sorted collection和ordered collection有什么不同?

答:sorted collection是通过使用 Java的Comparator在内存中进行排序的,ordered collection中的排序用的是数据库的order by子句。对于比较大的数据集,为了避免在内存中对它们进行排序而出现 Java中的OutOfMemoryError,最好使用ordered collection。

10、持久化对象的状态都有哪些?

答:瞬时对象(Transient Objects):使用new 操作符初始化的对象不是立刻就持久的。它们的状态是瞬时的,也就是说它们没有任何跟数据库表相关联的行为,只要应用不再引用这些对象(不再被任何其它对象所引用),它们的状态将会丢失,并由垃圾回收机制回收。
持久化对象(Persist Objects):持久实例是任何具有数据库标识的实例。它有持久化管理器Session统一管理,持久实例是在事务中进行操作的——它们的状态在事务结束时同数据库进行同步。当事务提交时,通过执行SQL的INSERT、UPDATE和DELETE语句把内存中的状态同步到数据库中。
离线对象(Detached Objects):Session关闭之后,持久化对象就变为离线对象。离线表示这个对象不能再与数据库保持同步,它们不再受Hibernate管理。

11、Hibernate工作原理及为什么要用?

答:Hibernate工作原理:
1.读取并解析配置文件
2.读取并解析映射信息,创建SessionFactory
3.得到session,并打开Sesssion
4.创建事务Transation
5.持久化操作
6.提交事务
7.关闭Session
8.关闭SesstionFactory

使用的原因:
1.对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2.Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
3.hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4.hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。

12、Hibernate是如何延迟加载?

1.Hibernate2延迟加载实现:a)实体对象 b)集合(Collection)
2.Hibernate3 提供了属性的延迟加载功能
当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,从而提高了服务器的性能。

13、说下Hibernate的缓存机制

答:Hibernate的缓存机制如下:
1.内部缓存存在Hibernate中又叫一级缓存,属于应用事物级缓存
2.二级缓存:
  a)应用及缓存
  b)分布式缓存条件:数据不会被第三方修改、数据大小在可接受范围、数据
更新频率低、同一数据被系统频繁使用、非关键数据
  c)第三方缓存的实现

四、Mybatis面试题

1、Mybatis工作原理?

image
原理:
通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件中构建出SqlSessionFactory。
SqlSessionFactory开启一个SqlSession,通过SqlSession实例获得Mapper对象并且运行Mapper映射的Sql语句。
完成数据库的CRUD操作和事务提交,关闭SqlSession。

2、查询表名和返回实体Bean对象不一致,如何处理?

映射键值对即可

<result column="title" property="title" javaType="java.lang.String"/>

column:数据库中表的列名
property:实体Bean中的属性名

3、Mybatis的好处?

把Sql语句从Java中独立出来。
封装了底层的JDBC,API的调用,并且能够将结果集自动转换成JavaBean对象,简化了Java数据库编程的重复工作。
自己编写Sql语句,更加的灵活。
入参无需用对象封装(或者map封装),使用@Param注解

4、Mybatis配置一对多?

<collection property="topicComment" column="id" ofType="com.tmf.bbs.pojo.Comment" select="selectComment" />

property:属性名
column:共同列
ofType:集合中元素的类型
select:要连接的查询

5、Mybatis配置一对一?

<association property="topicType" select="selectType" column="topics_type_id" javaType="com.tmf.bbs.pojo.Type"/>

property:属性名
select:要连接的查询
column:共同列
javaType:集合中元素的类型

6、Ibatis和Mybatis?

Ibatis:2010年,apache的Ibatis框架停止更新,并移交给了google团队,同时更名为MyBatis。从2010年后Ibatis在没更新过,彻底变成了一个孤儿框架。一个没人维护的框架注定被mybatis拍在沙滩上。
Mybatis:Ibatis的升级版本。

7、什么是Mybatis的接口绑定,有什么好处?

Mybatis实现了DAO接口与xml映射文件的绑定,自动为我们生成接口的具体实现,使用起来变得更加省事和方便。

8、获取上一次自动生成的主键值?

select last _insert_id()

9、Mybatis如何分页,分页原理?

RowBounds对象分页
在Sql内直接书写,带有物理分页

10、什么情况用注解,什么情况用xml绑定?

注解使用情况:Sql语句简单时
xml绑定使用情况:xml绑定 (@RequestMap用来绑定xml文件)

11、Mybatis在核心处理类叫什么?

SqlSession

猜你喜欢

转载自blog.csdn.net/jex00000/article/details/86671260