JAVA常见的面试题
JAVA常见的面试题
TonyStarkSir 发表于9个月前
JAVA常见的面试题
  • 发表于 9个月前
  • 阅读 13
  • 收藏 0
  • 点赞 0
  • 评论 0
摘要: 最近面试,没有什么准备,发现很多东西似乎都知道,但就是说不上来,所以趁闲着,总结下最近面试中经常遇到的一些问题

1.String是基本数据类型吗?

答:不是的,Java中基本数据类型有8种,byte、int、short、long、char、boolean、float、double,其中long、float占8个字节,int、float占4个字节,char和short是2个字节,boolean和byte是1个字节

2.float f=3.4是否正确?

答:不正确,3.4是双精度double类型的,双精度转换为浮点型会有精度损失,应该为:float f =(float)3.4或者float f=3.4F

3.数组有没有.length(),String 有没有length()?

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

4.String、StringBulider、StringBuffer的区别

答:Java平台提供了两种类型的字符串:String和StringBuffer/StringBuilder,它们可以储存和操作字符串。其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改。StringBuilder是Java 5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer要高。

5.阐述final、finally、finalize的区别。 
答: final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。将变量声明为final,可以保证它们在使用中不被改变,被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为final的方法也同样只能使用,不能在子类中被重写。

finally:通常放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。 

finalize:Object类中定义的方法,Java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize()方法可以整理系统资源或者执行其他清理工作。

6.static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。 
被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。
只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。 
用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象市,不生成static变量的副本,而是类的所有实例共享同一个static变量。

7、Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别? 
答:sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态,请参考第66题中的线程状态转换图)。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

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

9、请说出与线程同步以及线程调度相关的方法。 
答: 
- wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁; 
- sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常; 
- notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关; 
- notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

网上找了个例子:下面的例子演示了100个线程同时向一个银行账户中存入1元钱,在没有使用同步机制和使用同步机制情况下的执行情况。

银行账户类:

/**
 * 银行账户
 * @author 骆昊
 *
 */
public class Account {
    private double balance;     // 账户余额

    /**
     * 存款
     * @param money 存入金额
     */
    public void deposit(double money) {
        double newBalance = balance + money;
        try {
            Thread.sleep(10);   // 模拟此业务需要一段处理时间
        }
        catch(InterruptedException ex) {
            ex.printStackTrace();
        }
        balance = newBalance;
    }

    /**
     * 获得账户余额
     */
    public double getBalance() {
        return balance;
    }
}

线程存钱类:

/**
 * 存钱线程
 * @author 骆昊
 *
 */
public class AddMoneyThread implements Runnable {
    private Account account;    // 存入账户
    private double money;       // 存入金额

    public AddMoneyThread(Account account, double money) {
        this.account = account;
        this.money = money;
    }

    @Override
    public void run() {
        account.deposit(money);
    }

}

测试类:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test01 {

    public static void main(String[] args) {
        Account account = new Account();
        ExecutorService service = Executors.newFixedThreadPool(100);

        for(int i = 1; i <= 100; i++) {
            service.execute(new AddMoneyThread(account, 1));
        }

        service.shutdown();

        while(!service.isTerminated()) {}

        System.out.println("账户余额: " + account.getBalance());
    }
}

在没有同步的情况下,执行结果通常是显示账户余额在10元以下,出现这种状况的原因是,当一个线程A试图存入1元的时候,另外一个线程B也能够进入存款的方法中,线程B读取到的账户余额仍然是线程A存入1元钱之前的账户余额,因此也是在原来的余额0上面做了加1元的操作,同理线程C也会做类似的事情,所以最后100个线程执行结束时,本来期望账户余额为100元,但实际得到的通常在10元以下(很可能是1元哦)。解决这个问题的办法就是同步,当一个线程对银行账户存钱时,需要将此账户锁定,待其操作完成后才允许其他的线程进行操作,代码有如下几种调整方案

  • 在银行账户的存款(deposit)方法上同步(synchronized)关键字
  • /**
     * 银行账户
     * @author 骆昊
     *
     */
    public class Account {
        private double balance;     // 账户余额
    
        /**
         * 存款
         * @param money 存入金额
         */
        public synchronized void deposit(double money) {
            double newBalance = balance + money;
            try {
                Thread.sleep(10);   // 模拟此业务需要一段处理时间
            }
            catch(InterruptedException ex) {
                ex.printStackTrace();
            }
            balance = newBalance;
        }
    
        /**
         * 获得账户余额
         */
        public double getBalance() {
            return balance;
        }
    }

     

  • 在线程调用存款方法时对银行账户进行同步
  • /**
     * 存钱线程
     * @author 骆昊
     *
     */
    public class AddMoneyThread implements Runnable {
        private Account account;    // 存入账户
        private double money;       // 存入金额
    
        public AddMoneyThread(Account account, double money) {
            this.account = account;
            this.money = money;
        }
    
        @Override
        public void run() {
            synchronized (account) {
                account.deposit(money); 
            }
        }
    
    }

     

  • 通过Java 5显示的锁机制,为每个银行账户创建一个锁对象,在存款操作进行加锁和解锁的操作

10.编写多线程程序有几种实现方式? 
答:Java 5以前实现多线程有两种实现方法:一种是继承Thread类;另一种是实现Runnable接口。两种方式都要通过重写run()方法来定义线程的行为,推荐使用后者,因为Java中的继承是单继承,一个类有一个父类,如果继承了Thread类就无法再继承其他类了,显然使用Runnable接口更为灵活。Java 5以后创建线程还有第三种方式:实现Callable接口,该接口中的call方法可以在线程执行结束时产生一个返回值

11、synchronized关键字的用法? 
答:synchronized关键字可以将对象或者方法标记为同步,以实现对对象和方法的互斥访问,可以用synchronized(对象) { … }定义同步代码块,或者在声明方法时将synchronized作为方法的修饰符。在第60题的例子中已经展示了synchronized关键字的用法。

12、事务的ACID是指什么? 
答: 
- 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败; 
- 一致性(Consistent):事务结束后系统状态是一致的; 
- 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态; 
- 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。

13、web.xml文件中可以配置哪些内容? 
答:web.xml用于配置Web应用的相关信息,如:监听器(listener)、过滤器(filter)、 Servlet、相关参数、会话超时时间、安全验证方式、错误页面等,下面是一些开发中常见的配置:

①配置spring上下文加载监听器加载Spring配置文件并创建IoC容器:

<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
   <listener-class>
       org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener>

②配置Spring的OpenSessionInView过滤器来解决延迟加载和hibernate会话关闭的矛盾:

<filter>
      <filter-name>openSessionInView</filter-name>
      <filter-class>
         org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
      </filter-class>
</filter>

<filter-mapping>
      <filter-name>openSessionInView</filter-name>
      <url-pattern>/*</url-pattern>
</filter-mapping>

③配置会话超时时间为10分钟:

<session-config>
      <session-timeout>10</session-timeout>
</session-config>

④配置404和Exception的错误页面:

<error-page>
      <error-code>404</error-code>
      <location>/error.jsp</location>
</error-page>

<error-page>
      <exception-type>java.lang.Exception</exception-type>
      <location>/error.jsp</location>
</error-page>

⑤配置安全认证方式:

<security-constraint>
      <web-resource-collection>
          <web-resource-name>ProtectedArea</web-resource-name>
          <url-pattern>/admin/*</url-pattern>
          <http-method>GET</http-method>
          <http-method>POST</http-method>
      </web-resource-collection>
      <auth-constraint>
          <role-name>admin</role-name>
      </auth-constraint>
</security-constraint>

<login-config>
      <auth-method>BASIC</auth-method>
</login-config>

<security-role>
      <role-name>admin</role-name>
</security-role>

 

共有 人打赏支持
粉丝 0
博文 21
码字总数 9766
×
TonyStarkSir
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: