IBM面试

上周六去IBM面试了,面试官问了如下一些问题:

1.String 和 StringBuffer 有什么区别?StringBuffer的构造方法中带String的和带int型的有什么不同?
:字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。
StringBuffer是线程安全的可变字符序列,一个类似于 String的字符串缓冲区。

StringBuffer()
          构造一个其中不带字符的字符串缓冲区,初始容量为 16 个字符。
StringBuffer(CharSequence seq)
          public java.lang.StringBuilder(CharSequence seq) 构造一个字符串缓冲区,它包含与指定的 CharSequence 相同的字符。
StringBuffer(int capacity)
          构造一个不带字符,但具有指定初始容量的字符串缓冲区。
StringBuffer(String str)
          构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。
从 JDK 5 开始,为该类补充了一个单个线程使用的等价类,即 StringBuilder。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。(引用自JDK1.6说明)

2.ArrayList里的Bean怎么实现排序?(比如这个Bean里有name、age,按age大小排序)
:利用Collections的Sort(List,Comparator),实现Comparator接口里的 compare()比较方法,即可。

3.怎么理解java的多态?
:在《核心技术卷1》中说:一个对象变量可以指向多种实际类型这种现象称为“多态”。
在Java中,谈论多态就是在讨论方法调用的绑定,绑定就是将一个方法调用同一个方法主体关联起来。在C语言中,方法(在C中称为函数)的绑定是由编译器来实现的,在英文中称为early binding(前期绑定),因此,大家自然就会想到相对应的late binding(后期绑定),这在Java中通常叫做run-time binding(运行时绑定),我个人觉得这样称呼更贴切,运行时绑定的目的就是在代码运行的时候能够判断对象的类型。
通俗来说就是:如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法。

4.java当中的基本类型和包装类型有什么区别?什么时候用包装类型,什么时候用基本类型?
:java的类型分两部分,基本类型和引用类型。并且,每个基本类型都对应了一个引用的类型,称为装箱基本类型。
如Integer 对应int,Double对应的double.
 两者的主要区别有三:
基本类型只有值,而装箱类型则有与他们的值不同的同一性,也就是两个装箱类型可以具有相同的值,有不同的同一性(不同的引用)
基本类型只有功能完备的值,而每个装箱类型除了它对应基本类型的所有功能值外,还有个非功能的值--null
基本类型通常比装箱类型更节省时间和空间。
反复的拆箱和装箱影响性能。
详解参考 点击打开链接

5.Spring的注入有哪几种方式?比如接口注入?
spring的三种注入方式:
接口注入(不推荐)
getter,setter方式注入(比较常用)
构造器注入(死的应用)
------------------------------------------------------------------------------------------------------------
关于getter和setter方式的注入:
 autowire="defualt"
 autowire=“byName”
 autowire="bytype"
例如:有如下两个类需要注入

package org.jia;
 
public class Order {
     private String orderNum;
     @SuppressWarnings("unused")
     private OrderItem orderitem;
 
     public OrderItem getOrderitem() {
         return orderitem;
     }
 
     public void setOrderitem(OrderItem orderitem) {
         this.orderitem = orderitem;
     }
 
     public String getOrderNum() {
         return orderNum;
     }
 
     public void setOrderNum(String orderNum) {
         this.orderNum = orderNum;
     }
     
}
 package org.jia;
 
 public class OrderItem {
     private String orderdec;
 
     public String getOrderdec() {
         return orderdec;
     }
 
     public void setOrderdec(String orderdec) {
         this.orderdec = orderdec;
     }
 }
getter&&setter方式第一种注入:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean id="orderItem" class="org.jia.OrderItem">
        <property name="orderdec" value="item00001"></property>
    </bean>
    <bean id="order" class="org.jia.Order" >
        <!-----注入变量 名字必须与类中的名字一样------->
        <property name="orderNum" value="order000007"></property>
         <!--注入对象 名字为orderitem,所属的类的应用id为orderItem-->
        <property name="orderitem" ref="orderItem"></property>
    
    --></bean>


</beans>
getter&&setter方式第二种注入: byName
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!--此时的id就必须与Order.java中所定义的OrderItem的对象名称一样了,不然就会找不到-->
    <bean id="orderitem" class="org.jia.OrderItem">
        <property name="orderdec" value="item00001"></property>
    </bean>
    <bean id="order" class="org.jia.Order" autowire="byName">
        <property name="orderNum" value="order000007"></property>
    </bean>
</beans>
getter&&setter方式第三种注入:byType
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!--按照byType注入则就与id没有关系,可以随便定义id !!!但是不能出现多个此类的id-->
    <bean id="orderitdfadafaem" class="org.jia.OrderItem">
        <property name="orderdec" value="item00001"></property>
    </bean>
    <bean id="order" class="org.jia.Order" autowire="byType">
        <property name="orderNum" value="order000007"></property>
    </bean>
</beans>
--------------------------------------------------------------------------------------------------------
关于构造器的注入:
autowire="constructor"
需要在Order.java中加入一个构造器
public Order(OrderItem item ){ orderitem = item; }
 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="orderItem" class="org.jia.OrderItem">
        <property name="orderdec" value="item00001"></property>
    </bean>
    <bean id="order" class="org.jia.Order" autowire="constructor">
        <property name="orderNum" value="order000007"></property>
    </bean>
</beans>

6.怎么理解Spring的事务管理?
了解事务:

事务是一组原子(Atomic)操作的工作单元,以数据库存取的实例来说,就是一组SQL指令,这一组SQL指令必须全部执行成功,若因为某个原因未全部执行成功(例如其中一行SQL有错误),则先前所有执行过的SQL指令都会被撤消。

Spring是把JDBC事务管理进来了封装,Spring事务管理的抽象关键在于org.springframework.transaction.PlatformTransactionManager接口,里面有 commit  rollback

 public interface PlatformTransactionManager ...{

    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status)  throws TransactionException;

    void rollback(TransactionStatus status)  throws TransactionException;

}

TransactionDefinition接口的实例定义了

事务的隔离程度(Isolation level

传播行为(Propagation behavior

超时(Timeout

只读(Read-only)等

DataSourceTransactionManagerHibernateTransactionManagerJdoTransaction- ManagerJtaTransactionManager等是实现了该接口

Spring提供编程式的事务管理(Programmatic transaction management)与声明式的事务管理(Declarative transaction management):

 1、编程式的事务管理可以清楚地控制事务的边界,也就是让您自行实现事务开始时间、撤消操作的时机、结束时间等,可以实现细粒度的事务控制。

 2、然而多数的情况下,事务并不需要细粒度的控制,而是采用声明式的事务管理,好处是Spring事务管理的相关API可以不用介入程序之中,从对象的角度来看,它并不知道自己正被纳入事务管理之中,在不需要事务管理的时候,只要在设置文件上修改一下设置,即可移去事务管理服务。


7.Spring中BeanFactory与ApplicationContext的差别?
:使用BeanFactory从xml配置文件加载bean:

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class XmlConfigWithBeanFactory {

    public static void main(String[] args) {
        XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource(
                "build/beans.xml"));

    }
}
使用ApplicationConText从xml配置文件加载bean:

public class XmlConfigWithApplication{

    public static void main(String[] args){
        ApplicationContext application = new ClassPathXmlApplicationContext(beans.xml"));
         application.getBean("BeanName");
    }
}
ApplicationContext和BeanFacotry相比,提供了更多的扩展功能,但其主要区别在于后者是延迟加载,如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身是检验,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用ApplicationContext。

8.怎么理解Hibernate 的缓存?
:Hibernate缓存是一种提高系统性能的比较好的工具,如果使用合理,则能极大地提高系统性能,但如果使用不合理也会使用系统性能下降。Hibernate缓存比较复杂,要想灵活使用hibernate缓存,必须深入研究hiberante缓存原理,最好能分析hibernate的源代码。有很多人使用hibernate的时间比较长也不能正确理解hibernate缓存,下面我就谈谈hibernate缓存的使用,希望能对大家有点帮助。
Session缓存(一级缓存):当调用Session的保存、更新、查询操作时,在Session缓存中不存在相应对象,则把这些对象加入Session缓存。同一个Session操作,第一次通过ID调用load()或get()查询持久对象,先从Session缓存中查询发现该对象不命中,随即发送一条SQL语句生成一个持久对象并把该对象放入Session缓存。第二次再通过相同ID调用load()或get()查询时将直接从Session缓存将该对象返回,避免多余的数据库连接和查询的开销。
Session的load()和get()方法使用区别:
1、当数据库不存在对应ID数据时,调用load()方法将会抛出ObjectNotFoundException异常,get()方法将返回null,我比较喜欢使用get()方法。
2、当对象.hbm.xml配置文件<class>元素的lazy属性设置为true时,调用load()方法时则返回持久对象的代理类实例,此时的代理类实例是由运行时动态生成的类,该代理类实例包括原目标对象的所有属性和方法,该代理类实例的属性除了ID不为null外,所在属性为null值,查看日志并没有Hibernate SQL输出,说明没有执行查询操作,当代理类实例通过getXXX()方法获取属性值时,Hiberante才真正执行数据库查询操作。当对象.hbm.xml配置文件<class>元素的lazy属性设置为false时,调用load()方法则是立即执行数据库并直接返回实体类,并不返回代理类。而调用get()方法时不管lazy为何值,都直接返回实体类。
3、load()和get()都会先从Session缓存中查找,如果没有找到对应的对象,则查询Hibernate二级缓存,再找不到该对象,则发送一条SQL语句查询。关于这点,很多资料说明get ()不会查询二级缓存,比如夏昕编著的《深入浅出Hibernate》245页描述get()方法不查询二级缓存。但我测试发现load()和get()方法都会查询二级缓存,我上网看了很多缓存方面资料也证实了这点,大家可以看看这篇文章:http://blog.csdn.net/woshichenxu/archive/2006/01/22/586361.aspx
Session的evict()方法将持久对象从Session缓存中清除,clear()方法将清空整个缓存。
二级缓存(SesionFactory): 二级缓存由SessionFactory创建的所有Session对象共享使用, 二级缓存可使用第三方的缓存插件,如EHCache、OSChahe、SwarmCache、JBossCache,下面分别介绍二级缓存的类缓存、集合缓存和查询缓存。

1、类缓存:类缓存的key是持久对象的ID,value为持久化对象POJO,无论调用list(),load()还是iterate()查询,只要读出一个持久化对象POJO,都会根据POJO的ID作为key,value为POJO填充到类缓存中。当通过iterate()方法查询时,先会向数据库发送一条select id from POJO的SQL语句,将所有ID查询出来,再根据ID一个个地作为key到类缓存中查询相应POJO,如果类缓存中存在(命中),则从缓存中返回,否则向数据库发一条select * from POJO  where  id=?语句将查询该对象返回,并填充到类缓存中。当通过list()方法查询时,不会象iterate()先查询ID再查询类缓存,而是直接发送SQL查询数据库将结果返回,但会将查询结果填充到类缓存中,可供itetator()使用。

9.怎么理解Hibernate的懒加载?
:延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。在Hibernate中提供了对实体对象的延迟加载以及对集合的延迟加载,另外在Hibernate3中还提供了对属性的延迟加载。
xxxx.hbm.xml文件的<class>元素的lazy属性设为true,表示使用延迟检索策略。

10.Statement和PreparedStatement有什么区别?

1: 我们先从这两个单词进行初步的讲解,Prepared(准备好的, 精制的),从这里可以知道PreparedStatement是预先编译的语句,而Statement则不是预先编译的,在DBMS中处理管理中Statement是要进行语法、语义的,而PreparedStatement则不要。 

2: PrepareStatement中执行的SQL语句中是可以带参数的,而Statement则不可以。 
比如: 
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES 
SET SALARY = ? WHERE ID = ?"); 
pstmt.setBigDecimal(1, 153833.00); 
pstmt.setInt(2, 110592); 
pstmt. executeUpdate(); 

3: 当处理批量SQL语句时,这个时候就可以体现PrepareStatement的优势,由于采用Cache机制,则预先编译的语句,就会放在Cache中,下次执行相同SQL语句时,则可以直接从Cache中取出来。
关于PreparedStatement 预编译的语句具体是放在哪儿?为什么能提升性能?
先看看oracle的sql执行细节:
oracle 执行sql时,首先要分析sql生成查询计划,具体有:分析sql的合法性(到数据库schema中查询),决定使用某个的哪段索引(好像是这样说的)... ...,然后在第一次查询时,用物理读,其后相同的查询计划都是逻辑读,是到缓存里面读。 
PreparedStatement有利于oracle生成查询计划,或许还有别的帮助,所以提高了性能。 
但有一点是肯定的,PreparedStatement一定需要driver具体实现才行,Prepared是缓存在数据库端的。
所以说,PreparedStatement预编译的sql语句是放在数据库端的缓存里面,而放到缓存,有利于sql生成查询计划。

11.谈谈设计模式中Facade模式和工场模式
:略


12.高并发下怎么考虑你的设计
:略


总结:国际商业机器的面试官很客气,人非常低调,没有架子。提问的以上问题,基本上都是非常基础的,只要有一定工作经验的人,稍微准备一下,都是可以顺利回答的。
不过工作要求是:能适应一定的加班,能适应一定时间(半年或1年)的出差,这个貌似不是每个童鞋都愿意干的,尤其是拖家带口的那种。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值