牛客网Java错题总结(4)

目录

一、类的加载顺序

二、HashMap和Hashtable的区别(第二次错误)

三、抽象类和接口

四、JVM

五、字符串赋值

六、锁资源

七、关键字


一、类的加载顺序

解析:

  • 1.首先:需要明白类的加载顺序。
    • (1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
    • (2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
    • (3) 父类非静态代码块(包括非静态初始化块,非静态属性)
    • (4) 父类构造函数
    • (5) 子类非静态代码块(包括非静态初始化块,非静态属性)
    • (6) 子类构造函数
    • 其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的)
  • 2.其次:需要理解子类覆盖父类方法的问题,也就是方法重写实现多态问题。
    • Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类; 理解为b编译时表现为Base类特性,运行时表现为Sub类特性
    • 当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。
    • 由1.可知,此时只执行到步骤4.,子类非静态代码块和初始化步骤还没有到,子类中的baseName还没有被初始化。所以此时baseName为空。 所以为null。

二、HashMap和Hashtable的区别(第二次错误)

解析:

记忆:

  • Table为表格,更严格,所以不允许null值,同样也是安全的同步的
  • Map为图,更随意,所以允许null值,不安全也不同步

Hashtable 和 HashMap 的区别:

  • 1、继承的父类不同
    • Hashtable继承自Dictionary类
    • HashMap继承自AbstractMap类
    • 但二者都实现了Map接口
  • 2、线程的安全性
    • Hashtable是同步(方法中使用了Synchronize)的,是线程安全的
    • HashMap是未同步(方法中缺省Synchronize)的,是线程不安全的
  • 3、是否有contains方法
    • Hashtable有一个contains(Object value)方法,功能和containsValue(Object value)功能一样
    • HashMap把Hashtable的contains方法去掉了,改成containsValue(Object value)和containsKey(Object key)
  • 4、是否允许null值
    • Hashtable中,key和value都不允许出现null值
    • HashMap允许null值(key和value都可以),因为在HashMap中null可以作为健,而它对应的值可以有多个null
  • 5、遍历方式
    • HashTable使用Enumeration
    • HashMap使用Iterator
  • 6、Hash值
    • Hashtable直接使用对象的hashCode

      //hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值
      int hash = key.hashCode();
      int index = (hash & 0x7FFFFFFF) % tab.length;

    • HashMap要重新计算key值和hash值

      int hash = hash(k);
      int i = indexFor(hash, table.length);

      static int hash(Object x) {
        int h = x.hashCode();

        h += ~(h << 9);
        h ^= (h >>> 14);
        h += (h << 4);
        h ^= (h >>> 10);
        return h;
      }
      static int indexFor(int h, int length) {
        return h & (length-1);
      }

  • 7、数组初始化和扩容
    • Hashtable中hash数组默认大小是11,增加的方式是2*n+1(n为当前数组的大小)
    • HashMap中hash数组的默认大小是16,增加的方式是2*n(n为当前数组的大小)

三、抽象类和接口

解析:

  • 抽象类
    • 1.抽象类中可以构造方法
    • 2.抽象类中可以存在普通属性,方法,静态属性和方法。
    • 3.抽象类中可以存在抽象方法。
    • 4.抽象类只能单继承
    • 5.如果一个类中有一个抽象方法,那么当前类一定是抽象类;抽象类中不一定有抽象方法
    • 6.抽象类中的抽象方法,需要有子类实现,如果子类不实现,则子类也需要定义为抽象的。
  • 接口
    • 1.接口中没有构造方法,也不能实例化接口的对象。
    • 2.在接口中只有常量,因为定义的变量,在编译的时候都会默认加上:public static final 
    • 3.在接口中的方法,永远都被public来修饰,在接口中只有方法的声明,没有方法体。
    • 5.接口可以实现多继承
    • 6.接口中定义的方法都需要有实现类来实现,如果实现类不能实现接口中的所有方法,则实现类定义为抽象类。

四、JVM

解析:

  • A:通过 ClassLoader 寻找和装载 class 文件
  • B:解释字节码成为指令并执行,提供 class 文件的运行环境
  • C:进行运行期间垃圾回收
  • D:提供与硬件交互的平台

D选项感觉有争议。。。个人理解是操作系统在和硬件打交道,而JVM是负责与操作系统打交道的

五、字符串赋值

解析:

当执行下列语句时:

lx = "Fenqile";

不会改变lx原来所在存储地址中的“LeXin”,而是jvm会另外开辟一块空间存储“Fenqile”,让lx指向该空间,

所以nb还是“LeXin”

六、锁资源

解析:

  • sleep():线程沉睡,当沉睡结束后又会马上运行,所以不释放锁资源。
  • wait():线程等待,暂停进程并且进入等待状态,且不参与锁资源争夺,等待唤醒后才有资格继续争夺
  • join():坑点就在这里了,这里join是抢占主线程的锁资源,然后等该线程结束后再继续运行主线程,这里是主线程释放了锁资源
  • yield():线程礼让,这里可能会释放锁资源,但是不一定,因为礼让的线程也可以参加锁资源抢夺,优先级高的概率更大而已

所谓的释放锁资源实际是通知对象内置的monitor对象进行释放,而只有所有对象都有内置的monitor对象才能实现任何对象的锁资源都可以释放。

又因为所有类都继承自Object,所以wait()就成了Object方法,也就是通过wait()来通知对象内置的monitor对象释放,而且事实上因为这涉及对硬件底层的操作,所以wait()方法是native方法,底层是用C写的。

其他都是Thread所有,所以其他3个是没有资格释放资源的,

而join()有资格释放资源其实是通过调用wait()来实现的

七、关键字

解析:

  • java中true、false、null在java中不是关键字,也不是保留字,它们只是显式常量值,但是你在程序中不能使用它们作为标识符。
  • 其中const和goto是java的保留字。java中所有的关键字都是小写的。
  • instanceof用来测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。

猜你喜欢

转载自blog.csdn.net/weixin_39478524/article/details/115001000