• 明航凯亚面试题


     


    1. 下列代码的执行结果是什么:

    public class Test {
        public static void main(String[] args) {
            (new ThreadTest()).start();
        }
    }
    class ThreadTest extends  Thread{
        @Override
        public void run() {
            System.out.println("In run");
            yield();
            System.out.println("leaving run.");
        }
    }

    答案:In run 在leaving run之前被打印出来。

    分析:Thread类的yield()方法的作用为线程让步,尝试释放当前线程对CPU资源的占用,并重新进入就绪状态。当其再次获取到CPU资源后会继续执行。

     


     

    2. <jsp:forward>和HttpServletResponse的sendredirect()方法的主要区别描述正确的是:

    答案为:forward执行在服务器端,而sendredirect在客户端

    分析:<jsp:forward> 的原理是HttpServletRequest的getRequestDispatcher的forward方法,为请求的转发,而sendredirect为页面的重定向。二者的完整区别为:  

    a.     重定向

    response.sendRedirect(你要跳转的路径)

    服务器告知给客户端,让客户端去请求你要跳转的路径。

    1、          跳转前和跳转后的request对象不是同一个对象了;意味着跳转后不能从request中获取到跳转前的用户请求数据;

    2、          在客户端的浏览器地址栏上看到的地址是跳转的地址。

    3、          可以跳转到项目外的地址;

    4、          如果跳转的路径采用根路径的话,需要携带项目的上下文路径。

    根路径:   /应用上下文/资源目录/文件名

    问题:如何动态的获取到应用上下文路径?

                request.getContextPath()
    5、          跳转后,如果客户端刷新页面,它只会刷新跳转后的页面

     b.     请求的转发

    request.getRequestDispatcher(你要跳转的路径)

                    .forward(request,response);

           服务器自己去请求跳转后的资源并执行,执行后将执行结果响应给客户端。

    1、          跳转前和跳转后的request对象是同一个对象;意味着跳转后可以从request中获取到跳转前的用户请求数据;

    2、          在客户端的浏览器地址栏上看到的地址是跳转的地址。

    3、          不可以跳转到项目外的地址;

    4、          如果跳转的路径采用根路径的话,不需要携带项目的上下文路径。

    根路径:  /资源目录/文件名

    5、   跳转后,如果客户端刷新页面,它会将跳转前和跳转后的页面都再执行一次。
    6、   请求的转发,他可以跳转到WEB-INF下的页面。

    3. 以下语句创建了几个对象
    String a,b,c;
    a = "a";
    b = "b";
    a = a+b;
    StringBuffer d = new StringBuffer("abc");
    d = d.append("567");

     



    答案:这个题,说实话很诛心,非常的恶心,下面是分析

    首先, 明确一下 创建对象 的具体含义. 按我的理解, 如果字符串是 字符常量, 那么这个字符串对象是在编译时候确定好的, 它是存放在常量池中的, 因此就不算是创建了一个字符串对象, 而如果有 String b = new String("abc") 之类的操作, 那么可以认为是创建了字符串对象, 并与变量 b 关联.

    根据上面的定义, 那么有: "a", "b", "abc", "567" 都是常量, 放在常量池中的, 因此就不算是创建对象了。

    那么来看一下代码:
    源码:

    1: String a,b,c;
    2: a = "a";
    3: b = "b";
    4: a = a+b;
    5: StringBuffer d = new StringBuffer("abc");
    6: d = d.append("567");

    为了方便起见, 我手动给每一行编号了.
    再来看一下对应的字节码:

    Code:
      stack=3, locals=5, args_size=1
         0: ldc           #2                  // String a
         2: astore_1
         3: ldc           #3                  // String b
         5: astore_2
         6: new           #4                  // class java/lang/StringBuilder
         9: dup
        10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
        13: aload_1
        14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        17: aload_2
        18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        24: astore_1
        25: new           #8                  // class java/lang/StringBuffer
        28: dup
        29: ldc           #9                  // String abc
        31: invokespecial #10                 // Method java/lang/StringBuffer."<init>":(Ljava/lang/String;)V
        34: astore        4
        36: aload         4
        38: ldc           #11                 // String 567
        40: invokevirtual #12                 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
        43: astore        4
        45: return

    由字节码可以看出, 源码的第四行 a = a+b 翻译为如下代码:

    StringBuilder builder = new StringBuilder();
    builder.append(a);
    builder.append(b);
    a = builder.toString();

    那么这里就新建了一个对象 new StringBuilder(), 接着调用 builder.toString() 方法, 它源码如下:

    @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

    于是 builder.toString() 方法创建了一个 String 对象, 因此目前我们已经创建了 两个对象 了.

    接着第五行 StringBuffer d = new StringBuffer("abc") 毫无疑问是 创建了对象 StringBuffer, 于是我们就有 三个对象 了. 有一点需要注意的是 StringBuffer d 从始至终都没有调用 toString 方法, 因此就不会有多余的 String 创建出来.

    总结:

    • "a": 字符串常量, 不算创建对象

    • "b": 字符串常量, 不算创建对象

    • builder 对象: 在执行 a = a+b 时创建.

    • "ab": 由 StringBuilder.toString() 创建.

    • "abc": 字符串常量, 不算创建对象

    • "567": 字符串常量, 不算创建对象

    • d: 通过 new StringBuffer("abc") 创建.

    因此最终有三个对象创建了.

    当然有的学者也将字符串常量理解为对象,这样的话总共就是七个对象被创建了

     


    4. 在实现DAO设计模式时,下面哪种模式经常被采用?
    答案:Factory模式

    5. 有如下的Servlet类
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class MyServlet extends HttpServlet {
    
        @Override
        public void init() throws ServletException {
        }
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            PrintWriter out = resp.getWriter();
            out.print("hello");
        }
    }

     

    加入编译SErvlet要具备的环境都已经齐全,用完全正确的命令编译此文件,描述正确的是:
    答案:编译后,将MyServlet.class放在正确的位置,在浏览器中查看该servlet,会看到输出文字“hello”
    分析:此servlet虽然没有doget和dopost,但是我们分析HttpServlet中的doget方法源码可见:
     protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String method = req.getMethod();
            long lastModified;
            if (method.equals("GET")) {
                lastModified = this.getLastModified(req);
                if (lastModified == -1L) {
                    this.doGet(req, resp);
                } else {
                    long ifModifiedSince;
                    try {
                        ifModifiedSince = req.getDateHeader("If-Modified-Since");
                    } catch (IllegalArgumentException var9) {
                        ifModifiedSince = -1L;
                    }
    
                    if (ifModifiedSince < lastModified / 1000L * 1000L) {
                        this.maybeSetLastModified(resp, lastModified);
                        this.doGet(req, resp);
                    } else {
                        resp.setStatus(304);
                    }
                }
            } else if (method.equals("HEAD")) {
                lastModified = this.getLastModified(req);
                this.maybeSetLastModified(resp, lastModified);
                this.doHead(req, resp);
            } else if (method.equals("POST")) {
                this.doPost(req, resp);
            } else if (method.equals("PUT")) {
                this.doPut(req, resp);
            } else if (method.equals("DELETE")) {
                this.doDelete(req, resp);
            } else if (method.equals("OPTIONS")) {
                this.doOptions(req, resp);
            } else if (method.equals("TRACE")) {
                this.doTrace(req, resp);
            } else {
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[]{method};
                errMsg = MessageFormat.format(errMsg, errArgs);
                resp.sendError(501, errMsg);
            }
    
        }

     

    由此可见:servlet处理客户端的请求默认是通过service方法拦击所有的请求,并根据具体的客户端请求方式,调用对应的doXxx方法,而此题中service方法被重写,则客户端不管以何种method请求该servelt,均是执行重写后的service方法,而不会执行doXxx方法


    6. 评估下面一组SQL语句:
    CREATE TABLE DEPT (DEPTNO NUMBER(2),DNAME VARCHAR2(14),1oc VARCHAR2(13));
    ROLLBACK; DESCRIBE DEPT
    下面关于该组语句的描述哪个是正确的?()

    答案:A

    分析: CREATE TABLE时不需要commit

    describe 命令用于查看特定表的详细信息(oracle中)

    
    
    7. 一个输入项的合法范围是0-100的整数,则其边界值为   -1,0,100,101

    
    

    答案:D    

    分析: 其实我觉得B也有错,一个类实现了接口其实不一定非要实现接口的所有方法,只要该类为抽象类即可,让其子类再去实现方法;

             在java的重写中,遵循访问权限  重写前  <= 重写后的规则,而接口中所有的方法的访问修饰符都已经是public最大了,所以实现接口不可以修改其访问权限;

      接口中定义变量,实际上是定义的常量,在编译器编译时会自动追加: public static final 

     


    答案:  有错

    分析: 抽象方法不能有{}方法的实现体。


     

    答案: 0次
    分析:查看ArrayList的源码中的构造方法,在构造方法初始化的时候就已经创建大小为20的对象数组了。
     public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            }
        }

    可见,ArrayList在指定initialCapacity时是直接分配对象的数组空间为initialCapacity;

    如果是 List list  = new ArrayList();

    通过add方法插入20条记录的话,则遵循下面的法则:

    ArrayList在没指定initialCapacity时会使用延迟分配对象数组空间,当第一次插入元素时才分配10(默认)个对象空间。
    如果有20个数据需要添加,那么会分别在第一次的时候,将ArrayList的容量变为10;之后扩容会按照1.5倍增长。
    也就是当添加第11个数据的时候,Arraylist继续扩容变为10*1.5=15;当添加第16个数据时,继续扩容变为15 * 1.5 =22个。
  • 相关阅读:
    10. Regular Expression Matching
    9. Palindrome Number (考虑负数的情况)
    8. String to Integer (整数的溢出)
    7. Reverse Integer (整数的溢出)
    LeetCode Minimum Size Subarray Sum
    LeetCode Course Schedule II
    Linux 文件缓存 (一)
    LeetCode Tries Prefix Tree
    Linux : lsof 命令
    LeetCode Binary Tree Right Side View
  • 原文地址:https://www.cnblogs.com/dengcl/p/8000162.html
Copyright © 2020-2023  润新知