Java—零碎难记笔试考点(持续更新)

String类是final类

“对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。

public class Test{
    public static void main(String[] args){
        String a = "aaaa";
        String b = a.replace('a', 'b');
        System.out.println(a);
        System.out.print(b);
    }
}

当对String类对象进行subString(),replace()等,应该赋值给新的String对象,因为a还是原来的内容。

String str="hello world"和String str=new String("hello world")的区别:

public class Test{
    public static void main(String[] args){
        String a = new String("aaaa");
        String b = new String("aaaa");
        String c = "aaaa";
        System.out.println(a==b);
        System.out.println(a.equals(b));
        System.out.println(a==c);
        System.out.println(a.equals(c));
    }
}

String c = "aaaa";在编译期间生成了 字面常量和符号引用,运行期间字面常量"aaaa"被存储在运行时常量池(当然只保存了一份)。通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。

通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。

String类的equals方法只比较内容。所以equals返回true。

StringBuilder和StringBuffer类区别:

StringBuilder和StringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized,StringBuffer类是线程安全的

线程阻塞与唤醒方法:

    1. sleep() 方法

  sleep(毫秒),指定以毫秒为单位的时间,使线程在该时间内进入线程阻塞状态,期间得不到cpu的时间片,等到时间过去了,线程重新进入可执行状态。不会释放资源。(暂停线程,不会释放锁)

  2.suspend() 和 resume() 方法:。

  挂起和唤醒线程,suspend()使线程进入阻塞状态,只有对应的resume()被调用的时候,线程才会进入可执行状态。(不建议用,容易发生死锁)

  3. yield() 方法:

  会使的线程放弃当前分得的cpu时间片,但此时线程任然处于可执行状态,随时可以再次分得cpu时间片。yield()方法只能使同优先级的线程有执行的机会。调用 yield()的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。(暂停当前正在执行的线程,并执行其他线程,且让出的时间不可知)

  4.wait() 和 notify() 方法

  两个方法搭配使用,wait()使线程进入阻塞状态,调用notify()时,线程进入可执行状态。wait()内可加或不加参数,加参数时是以毫秒为单位,当到了指定时间或调用notify()方法时,进入可执行状态。(属于Object类,而不属于Thread类,wait()会先释放锁住的对象,然后再执行等待的动作。由于wait()所等待的对象必须先锁住,因此,它只能用在同步化程序段或者同步化方法内,否则,会抛出异常IllegalMonitorStateException.)

  5.join()方法

  也叫线程加入。是当前线程A调用另一个线程B的join()方法,当前线程转A入阻塞状态,直到线程B运行结束,线程A才由阻塞状态转为可执行状态。

transient关键字

将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。保证属性不会被传递,安全。

static关键字

静态变量在JVM初始化阶段就被赋值。

类初始化的顺序:

父类静态变量->父类静态代码块->子类静态变量->子类静态代码块->父类普通变量->父类普通代码块->父类构造函数->子类普通变量->子类普通代码块->子类构造函数

假设类A有静态内部类B和非静态内部类C,创建B和C的区别为:
A a=new A();
A.B b=new A.B();
A.C c=a.new C();

volatile关键字

所有线程的共享变量都存储在主内存中,每一个线程都有一个独有的工作内存,每个线程不直接操作在主内存中的变量,而是将主内存上变量的副本放进自己的工作内存中,只操作工作内存中的数据。当修改完毕后,再把修改后的结果放回到主内存中。这就导致多线程的环境下可能会出现脏数据,加上volatile关键字修饰的话,它可以保证当线程对变量值做了变动之后,会立即刷回到主内存中,而其它线程读取到该变量的值也作废,强迫重新从主内存中读取该变量的值,这样在任何时刻,线程总是会看到变量的同一个值。

树:

满二叉树:除了叶节点外每一个结点都有左右子女且叶节点都处在最底层的二叉树。

完全二叉树只有最下面的两层结点度小于2,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树。

二叉树查找最好O(logN),最差O(N),最差情况是所有的数据全部在一端时。

二叉搜索树:查找最好O(logN),最差O(N),最差情况是所有的数据全部在一端时

1.若任意结点的左子树不空,则左子树上所有结点的值均不大于它的根结点的值。

2. 若任意结点的右子树不空,则右子树上所有结点的值均不小于它的根结点的值。

3.任意结点的左、右子树也分别为二叉搜索树。

平衡二叉树:又称为AVL树查找O(logN),它是一颗空树或它的左右两个子树的高度差的绝对值不超过1

哈夫曼树:带权路径长度达到最小的二叉树,也叫做最优二叉树。

k层的二叉树,最多有节点个数为 2^k-1,最少有k个节点

第k层,最多有节点个数为 2^(k-1)个

红黑树:查找删除插入时间复杂度O(logN)

红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉查找树强制的一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:

  1. 节点是红色或黑色。
  2. 根是黑色。
  3. 所有叶子都是黑色(叶子是NIL节点)。
  4. 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
  5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

排序算法:

插入排序:

直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。

当数据正序时,执行效率最好,每次插入都不用移动前面的元素,时间复杂度为O(N)。
当数据反序时,执行效率最差,每次插入都要前面的元素后移,时间复杂度为O(N^2)。

希尔排序:

第一趟排序中,通过计算gap1=N/2(即10/2),将10个元素分为5组,即(9,4),(1,8),(2,6),(5,3),(7,5),然后对每组内的元素进行插入排序。
第二趟排序中,把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。分组后依旧对每组的元素进行插入排序。
第三趟排序中,再次把 gap 缩小一半,即gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。再进行一次插入排序。
需要注意的是,图中有两个相等数值的元素 5 和 5 。我们可以清楚的看到,在排序过程中,两个元素位置交换了。所以,希尔排序是不稳定的算法。

时间复杂度为O(N^(1.3—2))

冒泡排序算法:
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素会是最大的数。

其时间复杂度依然为O(N^2)

选择排序:
1.从待排序序列中,找到最小的元素;
2.如果最小元素不是待排序序列的第一个元素,将其和待排序序列的第一个元素互换;

时间复杂度为 O(N*2)

异常:

所有的异常都是继承Throwable的,自定义异常不可以继承自Error。

URI与URL

1.URL 比较实体   表示一个具体的

2.URI 比较抽象 表示一个相对的意思

URL --   比如 http://www.baidu.com/124/123    是一个绝对的路径

URI -- 比如 /124/123 是一个相对的路径

泛型中的限定通配符和非限定通配符:

限定通配符包括两种:
1. 表示类型的上界,格式为:<? extends T>,即类型必须为T类型或者T子类
2. 表示类型的下界,格式为:<? super T>,即类型必须为T类型或者T的父类

非限定通配符:类型为<T>,可以用任意类型来替代。

迭代器(Iterator)

  迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

  Java中的Iterator功能比较简单,并且只能单向移动:

  (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。

  (2) 使用next()获得序列中的下一个元素。

  (3) 使用hasNext()检查序列中是否还有元素。

  (4) 使用remove()将迭代器新返回的元素删除。

  Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章