03/14牛客刷题总结

1.Java语言中,如果"xyz"没有被创建过,String s =new String(“xyz”);创建了几个string object?

答案: 2

类加载对一个类只会进行一次

"xyz"在类加载时就已经创建并驻留了,(如果该类被加载之前已经有"xyz"字符串被驻留过则不需要重复创建用于驻留的"xyz"实例)。驻留的字符串是放在全局共享的字符串常量池中的。

在HotSpot VM 里实现的string pool 功能的是一个StringTable 类,它是一个哈希表,里面存的是驻留字符串(也就是我们常说的双引号括起来的)引用(而不是驻留字符串实例本身)

也就是说在堆中的某些字符串实例被这个StringTable引用之后就等同被赋予了"驻留字符串"的身份。

这个StringTable在每个HotSpot VM 的实例只有一份,被所有的类共享。

在这段代码后续被运行的时候,"xyz"字面量对应的String实例已经固定了(前面的类加载过程),不会再被重复创建。所以这段代码将常量池中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s1持有。

对于这句代码,可以分为两个过程:

a. jvm首先在字符串常量池内里面看看找不找到字符串"xyz";找到,进入第二步;否则,创建新的String对象,并"放到"字符串常量池里面。

b.然后由于遇到了new,还会在堆创建String对象,其实是拷贝到常量池的那个,拷贝比创建大概快吧….最后将其返回给s1。如果写在类方法里,请参考前面的类加载,就是相比之下提前驻留了吧。

2.以下代码的输出结果是

public class B
{
    public static B t1 = new B();
    public static B t2 = new B();
    {
        System.out.println("构造块");
    }
    static
    {
        System.out.println("静态块");
    }
    public static void main(String[] args)
    {
        B t = new B();
    }
}

答案: 构造块 构造块 静态块 构造块

开始时JVM加载B.class, 对所有的静态成员进行声明,t1 t2 被初始化为默认值,为null,又因为t1 t2 需要被显示初始化,所以对t1进行显示初始化, 初始化代码块->构造函数(没有就是调用默认的构造函数)。那么,静态代码咋不初始化?因为在开始时已经对static部分进行了初始化,虽然只对static变量进行了初始化,但在初始化t1时也不会再执行static块了,因为JVM认为这是第二次加载类B了,所以static会在t1初始化时被忽略掉,所以直接初始化非static部分,也就是构造块部分(输出“构造块”),接着构造函数(无输出)。接着对t2进行初始化的过程与t1相同(输出“构造块”),此时就对所有的static变量都完成了初始化,接着就执行static块部分(输出"静态块"),接着执行,main方法,同样也new了对象,调用构造函数输出("构造块")

3.在Object类中包含以下方法:

(1). clone();

(2). equals()

(3). finalize()

(4). getClass();

(5). notify(),notifyAll()

(6). hashCode()

(7) toString()

(8) wait()

  1. servlet生命周期
03/14牛客刷题总结_第1张图片
servlet生命周期.png
  1. 说明输出结果:

    package test;
    import java.util.Date; 
    public class SuperTest extends Date{ 
        private static final long serialVersionUID = 1L; 
        private void test(){ 
           System.out.println(super.getClass().getName()); 
        } 
          
        public static void main(String[]args){ 
           new SuperTest().test(); 
        } 
    }
    
    

    输出: test.SuperTest

TestSuper和Date的getClass都没有重写,他们都是调用Object的getClass,而Object的getClass作用时返回运行时的类的名字。这个运行时的类就是当前类,所以

super.getClass().getName()

返回的是test.SuperTest,与Date类无关

要返回Date类的名字需要写super.getClass().getSuperClass()

6.抛出InterruptedException的代表方法有:

a. java.lang.Object类的wait方法

b. Java.lang.Thread类的sleep方法

c. java.lang.Thread类的join方法

注意: Thread.suspend()方法作用是阻塞一个线程,不会释放锁,直到其他的线程调用resume方法,才能继续向下执行。被打断不会导致InterruptedException。该方法容易造成死锁,且已经被弃用了。

CyclicBarrier类:

是一个屏障类,它的await方法可以简单的理解为:等待多个线程同时到达之后才能继续进行,在此之前它就是这些线程的屏障,线程不能继续进行,而对于失败的同步尝试,CyclicBarrier使用了一种要么全部要么全不(all-or-none)的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么在该屏障点等待的其他所有线程也将通过BrokenBarrierException(如果它们几乎同时被中断,则用InterruptedException)以反常的方式离开。因此它被中断也可以抛出InterruptedException的。

  1. Collection
03/14牛客刷题总结_第2张图片
Collection.png
  1. a.ConcurrentHashMap 使用segment来分段和管理锁,segment继承自ReentrantLock,因此ConcurrentHashMap使用ReentrantLock来保证线程安全。

​ b. HashMap 的定义规则

public class HashMap extends AbstractMap implements Map,Cloneable,Serializable

​ c. Array.asList() 方法,其将一个数组转化为一个List对象,这个方法会返回一个ArrayList类型的对象,这个ArrayList类并非java.util.ArrayList类,而是Arrays类的内部类。

​ d. SimpleDateFormat是线程不安全的

  1. a. Math.cos 为计算弧度的余弦值

    b. Math.toRadians()是将角度转换为弧度

    c. Math.toDegrees()是将弧度转换为角度

  1. int i = 0; i = i++;
    

    Java虚拟机栈(JVM Stack)描述的是Java方法执行的内存模型,而JVM内存模型是基于"栈帧"的,每个"栈帧"都有 局部变量表和操作数栈(还有动态链接、return address等),那么JVM是如何执行这个语句的呢?

    JVM指令执行代码:

    0: icons_0

    1:istore_1

    2:iload_1

    3:iinc 1, 1

    6:istore_1

    7:iload_1

    接下来分析一下JVM是如何执行的:

    第0: 将int类型的0入栈,就是放到操作数栈的栈顶

    第1:将操作数栈栈顶的值0弹出,保存到局部变量表index(索引)值为1的位置。(局部变量表也是从0开始的,0位置一般保存当前实例的this引用,当然静态方法例外,因为静态方法是类方法而不是实例方法)

    第2:将局部变量表index 1位置的值的副本入栈。(这时局部变量表index为1的值是0,操作数栈顶的值也是0)

    第3: iinc 是对int类型的值进行自增操作,后面第一个数值1表示,局部变量表的index值,说明要对此值进行iinc操作,第二个数值1表示要增加的数值(这时局部变量表index为1的值因为执行了自增操作变为1了,但是操作数栈中栈顶的位置仍然是0)

    第6:将操作数栈顶的值弹出(值0),放到局部变量表index为1的位置(旧值:1,新值0),覆盖了上一步局部变量表的计算结果。

    第7:将局部变量表index 1位置的值的副本入栈。(这时局部变量表index为1的值是0,操作数栈顶顶值也是0)

    总结: 从执行顺序可以看到,这里第1和第6执行了两次将0赋值给变量i的操作(=号赋值),i++操作是在这两次操作之间执行的,自增操作是对局部变量表中的值进行自增,而栈顶顶值没有发生变化,这里需要注意的是保存这个初始值的地方是操作数栈而不是局部变量表,最后再将栈顶的值覆盖到局部变量表i所在的索引位置中去。

  1. java使用了中间缓存变量机制:

    i = i++;等同于:

    temp = i; (等号右边的i)

    i = i+ 1; (等号右边的i)

    i = temp; (等号左边的i)

    而 i = ++i;则等同于:

    i = i+1;

    temp = i;

    i = temp ;

  1. java中true,false,null 在java中不是关键字也不是保留字,它们只是显式常量值,但是你在程序中不能使用它们作为标识符。其中const和goto是java的保留字。java中所有的关键字都是小写的,还要注意true,false,null,friendly,sizeof不是java的关键字,但是我们不能把它们当作标识符使用。

13.Spring是一系列轻量级Java EE 框架的集合,它包含一个"依赖注入"模式的实现,使用Spring可以实现声明式事务,但是Spring并没有给我们提供日志系统。

14.Spring事务传播特性

PROPAGATION_REQUIRED --支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择

PROPAGATION_SUPPORTS — 支持当前事务,如果当前没有事务,就以非事务方式执行

PROPAGATION_MANDATORY — 支持当前事务,如果当前没有事务,就抛出异常

PROPAGATION_REQUIRES_NEW —新建事务,如果当前存在事务,就把当前事务挂起

PROPAGATION_NOT_SUPPORTED — 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起

PROPAGATION_NEVER —以非事务方式执行,如果当前存在事务,则抛出异常。

  1. jvm相关 http://blog.csdn.net/sivyer123/article/details/17139443

    java的堆内存分为两块,permantspace(持久代)和heap space

    持久代中主要用于存放静态类型数据,如Java Class, Method等,与垃圾收集器要收集的Java对象关系不大,而heapspace分为年轻代和年老代。

    年轻代的垃圾回收叫做Young GC,年老代的垃圾回收叫Full GC。

    在年轻代中经历了N次(可配置)垃圾回收后仍然存活的对象,就会被复制到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

    年老代溢出的原因有: 循环上千万次的字符串处理,创建上千万个对象、在一段代码内申请上百M甚至上G的内存

    持久代溢出的原因 动态加载了大量Java类而导致溢出。

你可能感兴趣的:(03/14牛客刷题总结)