牛客刷题笔记1
笔试题和算法题1
- HashMap如何解决哈希冲突?
HashMap是由数组+链表组成的,jdk1.8后加入了红黑树。它使用链地址法来解决哈希冲突,这样我们可以将具有相同哈希值的对象组织成一个链表放在hash值所对应的bucket下
- java中数组复制效率对比
在Java语言中,有几种数组复制方法,包括System.arraycopy、clone、Arrays.copyOf和for循环。其中,System.arraycopy的效率最高,其次是clone,然后是Arrays.copyOf,最后是for循环。
- java中二维数组创建的正确语句
float f [][]
= new float[6][6]
float []f[]
= new float[6][6]
float [][]f
= new float[6][6]
float [][]f
= new float[6][]
- 如何保证在多线程环境下保证线程顺序执行又保证线程安全
在多线程环境下,可以使用多种方法来保证线程顺序执行并保证线程安全。例如,可以使用Thread类中的join
方法来保证多个线程按指定的顺序执行。此外,还可以使用CountDownLatch、CyclicBarrier、Semaphore等并发工具类来实现线程的同步和顺序执行。
join方法:join方法是Thread类中的一个方法,它可以让当前线程等待调用join方法的线程执行完成后再继续执行。例如,如果线程A调用了线程B的join方法,那么线程A会等待线程B执行完成后再继续执行。
CountDownLatch:CountDownLatch是一个并发工具类,它允许一个或多个线程等待其他线程完成操作。它的构造函数接受一个int类型的参数,表示需要等待的线程数量。当一个线程完成操作时,它可以调用CountDownLatch的countDown方法来减少计数器的值。其他线程可以调用CountDownLatch的await方法来等待计数器减为0。
CyclicBarrier:CyclicBarrier也是一个并发工具类,它允许一组线程互相等待,直到所有线程都到达某个屏障点。它的构造函数接受一个int类型的参数,表示需要等待的线程数量。当一个线程到达屏障点时,它会调用CyclicBarrier的await方法来等待其他线程。当所有线程都到达屏障点时,屏障将打开,所有线程都将继续执行。
Semaphore:Semaphore是一个计数信号量,它可以用来控制对共享资源的访问。它的构造函数接受一个int类型的参数,表示允许同时访问共享资源的最大线程数量。当一个线程需要访问共享资源时,它可以调用Semaphore的acquire方法来获取许可。如果当前没有可用的许可,那么该线程将阻塞,直到有可用的许可为止。当一个线程完成对共享资源的访问后,它可以调用Semaphore的release方法来释放许可。
这些方法都可以用来保证多个线程按指定顺序执行并保证线程安全。
- 针对jdk1.7,不属于JVM堆内存中的区域,
java7,字符串常量池从方法区移到堆中。java8 整个常量池从方法区中移除。方法区使用元空间(MetaSpace)实现 。
关于jvm的一些看法,,
- JVM大体分为堆、栈、方法区和程序计数器四个部分。其中堆和方法区对线程共享,栈和程序计数器对线程隔离。
- 堆:存放数组和对象实例 ,- 栈:存放局部变量和数据类型 ,- 方法区:存放静态变量、常量、类信息和代码,,程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行 到了第几行,是线程隔离的 ,原则上讲,所有的对象都是在堆区上分配内存,是线程之间共享的 , Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的 ,
TreeSet使用二叉树对元素进行排序
读写锁的一些知识:
CopyOnWriteArrayList适用于写少读多的并发场景 ,ReadWriteLock即为读写锁,他要求写与写之间互斥,读与写之间互斥, 读与读之间可以并发执行。在读多写少的情况下可以提高效率 ,ConcurrentHashMap是同步的HashMap,读写都加锁,volatile只保证多线程操作的可见性,不保证原子性
- Servlet中HttpServletRequest.getParameter获取的参数
由客户端浏览器和web容器配置共同决定编码。
成员内部类前面可以修饰public,protected,private.
在接口interface主体内声明常量的
public static int answer = 42;
在java7中能做switch()参数的类型:
- int 型
- 枚举类型
- 字符串类型(String ) jdk7以后新增
- short
- char
- long
不能作为switch的类型:
- float
- double
- boolean
jre判断程序是否执行结束的标准:
所有前台线程执行完毕
后台线程:指为其他线程提供服务的线程,也称为守护线程。JVM的垃圾回收线程就是一个后台线程。 前台线程:是指接受后台线程服务的线程,其实前台后台线程是联系在一起,就像傀儡和幕后操纵者一样的关系。傀儡是前台线程、幕后操纵者是后台线程。由前台线程创建的线程默认也是前台线程。可以通过isDaemon()和setDaemon()方法来判断和设置一个线程是否为后台线程。
//以下代码输出什么 null public class Base { private String baseName = "base"; public Base(){ callName(); } public void callName(){ System. out. println(baseName); } static class Sub extends Base{ private String baseName = "sub"; public void callName(){ System. out. println (baseName) ; } } public static void main(String[] args){ Base b = new Sub(); } }
(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。