• 明航凯亚面试题


     


    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个。
  • 相关阅读:
    转:细说一个汉字等于几个字符,以及汉字,字符,字节,位之间的关系
    iOS8 无缝切换WKWebView,借鉴IMYWebview,解决进度条,cookie,本地页面等问题
    ios加载本地html
    如何做一个细心的人
    学习h5(开始)
    JLRoute 使用
    大二下学期学习进度(四)
    求首尾相接的数组的最大子数组和
    大二下学期学习进度(三)
    构建之法阅读笔记01
  • 原文地址:https://www.cnblogs.com/dengcl/p/8000162.html
Copyright © 2020-2023  润新知