java面试题每日一练(5)


1、java中为什么会有GC机制呢?

  • For security ---- 安全性考虑;
  • Erase memory leak in some degree ---- 减少内存泄露
  • don’t worry about memory releasing ---- 减少程序员工作量。

2、什么是java中的内存溢出?什么又是Java中的内存泄露?

内存溢出:out of memory
是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。

内存泄露:memory leak
是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

3、谈谈JVM的内存结构和内存分配

JVM内存结构

Java虚拟机将其内存大致分三个逻辑部分:


1、方法区(Method Area)是静态分配的,编译器将变量绑定在某个存储位置上,而且这些绑定不会在运行时改变

2、栈(stack)是一个逻辑概念,特点是后进先出 一个栈的空间可能是连续的,也可能是不连续JVM每调用一次方法就创建一个方法帧(frame)退出该方法则对应的方法帧被弹出(pop)

3、堆分配heap allocation)意味着以随意的顺序,在运行时进行存储分配和收回的内存管理模型,堆中存储的数据是大小、数量和生命期在编译时无法确定的。对象内存总是在heap中分配

JVM内存分配

1、基础数据类型直接在栈空间分配;
2、方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收:
3、引用数据类型,需要用 new 来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量;
4、方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完后从栈空间回收;
5、局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待 GC 回收;
6、方法调用时传入的实际参数,先在栈空间分配,在方法调用完成后从栈空间释放;
7、字符串常量在DATA区域分配,this在堆空间分配;
8、数组既在栈空间分配数组名称,又在堆空间分配数组实际的大小。

4、简述下TCP协议和UDP协议间的区别。

1.UDP 在传送数据之前不需要先建立连接,远地主机在收到 UDP 报文后,不需要给出任何确认。虽然UDP不提供可靠交付,但在某些情况下UDP确是一种最有效的工作方式(一般用于即时通信) 比如: QQ语音、QQ 视频 、直播等等

2.TCP 提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。 TCP不提供广播或多播服务。由于TCP要提供可靠的,面向连接的运输服务(TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源),这一难以避免增加了许多开销,如确认,流量控制,计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。TCP
一般用于文件传输、发送和接收邮件、远程登录等场景。

5、说说synchronized关键字和volatile关键字的区别

1.volatile关键字是线程同步的轻量级实现, 所以 volatile 性能肯定比synchronized关键字要好。但volatile关键字只能用于变量而 synchronized关键字可以修饰方法以及代码块。synchronized关键字在Javase1.6之后进行了主要包括为减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升,实际开发中使用synchronized 关键字场景还是更多一些。


2.多线程访问volatile关键字不会发生阻塞,而 synchronized关键字可能会发生阻塞 volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。


3.volatile关键字主要用于解决变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间访问资源的同步性。

6、运行时异常和受检异常有何异同?

Exception 又有两个分支:
一个是运行时异常 RuntimeException
一个是检查时异常 checkedException


1.运行时异常:RuntimeException
一般是由程序逻辑错误引起的,只有在程序运行时才会出现的异常,程序应该从逻辑角度尽可能避免这类异常的发生。即使没有用 throws子句声明抛出它或者使用 try…catch块去捕获,也会编译通过。


2.检查异常:checkedException

一般是外部错误,这种异常都发生在编译阶段,Java编译器会强制程序去捕获此类异常,即会出现要求你把这段可能出现异常的程序进行try…catch,或者用 throws子句声明抛出,该类异常一般包括几个方面:
1)试图在文件尾部读取数据
2)试图打开一个错误格式的URL
3)试图根据给定的字符串查找 class对象, 而这个字符串表示的类并不存在

7、什么是多线程并发安全问题?提出解决方案

1.多线程并发安全问题
多个线程操作同一临界资源(critical Resource),由于线程调度器分配时间片不均匀,而出现访问时数据不一致,导致数据紊乱的现象,严重时可以导致系统奔溃.


2.解决方案: 为了保证数据在方法中被访问时的正确性,在访问时加入锁机制 synchronized,当一个线程获得对象的排它锁、独占资源,其他线程必须等待,使用后释放锁即可。

8、提供3种获取Class对象的方法。

一、调用某个对象的getclassO方法:
Person p=new Person();
Class clazz=p.getClass();

二、调用某个类的class属性来获取该类 对应的 class 对象:
Class clazz=person.class;


三、使用 class 类中的 forName()静态方法(最安全/性能最好):
【最常用】
Class.forName(“类的全路径”);

9、为什么要用线程池?常用的创建线程池的方法有哪些?

使用线程池的好处:

1、降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

2、提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

3、提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性。

4、使用线程池可以进行统一的分配,调优和监控。
线程池有两种创建方法
1)通过Executors去创建 2)通过ThreadPoolExecutor去创建(建议使用)

实际上最好用第二种方式来创建,我写过一篇关于多线程的文章,在这篇文章中有详细介绍,可以参考阅读:进阶 - 线程池核心技术ThreadPoolExecutor(源码分析)

10、List的常见实现类:ArrayList、LinkedList、Vector、Stack作比较。

ArrayList是一个数组队列,相当于动态数组。它由数组实现,随机访问效率高,随机插入、随机删除效率低。
LinkedList是一个双向链表。它也可以被当作堆栈、队列或双端队列进行操作。LinkedList随机访问效率低,但随机插入、随机删除效率高。
Vector是矢量队列,和Arraylist一样,它也是一个动态数组,由数组实现。但是ArrayList是非线程安全的,而vector是线程安全的。

Stack 是栈,它继承于vector。它的特性是:先进后出(FIlo, First In Last out)。

11、对B-,B+,B*树做简要的区分。

B-树(或B树)是一种平衡的多路查找(又称排序)树,在文件系统中有所应用。主要用作文件的索引。其中的B就表示平衡(Balance)


1.B+树的叶子节点链表结构相比于B-树便于扫库和范围检索。


2.B+树支持range-query(区间查询)非常方 便,而B树不支持。这是数据库选用B+树的最主要原因。


3.B树是B+树的变体,B树分配新结点的概 率比B+树要低,空间使用率更高;

12、System.out.println(3|9)输出什么?

| 和 | | :

共同点
两者都可做逻辑运算符。它们都表示运算符的两边任意一边为true,结果为true,两边都不是true,结果就为false;


不同点
| 也是位运算符。| 表示两边都会运算,然后再判断结果;
|| 表示先运算符号左边的东西,然后判断是否为true,是true就停下来直接输出不会再运行后面的东西,是false就继续运算右边的然后判断并输出。


回到本题: 3|9=0011(二进制) | 1001(二进制)
=1011(二进制)
=11(十进制)

答案:输出11

13、java中的关键字final、finally、finalize间的区别?

final

  • 1、如果一个类被声明为final,则意味着它不能被继承。
  • 2、将变量声明为final,则表示它是一个常量,也就是保证它在使用过程中不被修改;被final修饰的变量,在声明时必须给出值。
  • 3、将方法声明为final,则表示该方法不能被子类重写。

finally  
  finally用在异常处理中定义总是执行代码,无论try块中的代码是否引发异常,catch是否匹配成功,finally块中的代码总是被执行,除非JVM被关闭,通常用作释放外部资源(不会被垃圾回收器回收的资源)。

finalize  
  finalize方法在垃圾回收器执行内存对象清理时会调用finalize()方法进行前期的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。

14、TreeMap和TreeSet在排序时如何比较元素?

  • TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小
  • TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进行排序

15、sleep()、yield()和wait()方法有什么区别?

sleep()
sleep()方法需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行,进入阻塞状态,该方法既可以让其他同优先级或者高优先级的线程得到执行的机会,也可以让低优先级的线程得到执行机会。但是sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。


yield()
yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yield()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。


wait()
会释放对象的“锁标志”;当调用某一对象的wait()方法后,会使当前线程暂停执行,并将当前线程放入对象等待池中,直到调用了notify()方法后,将从对象等待池中移出任意一个线程并放入锁标志等待池中,只有锁标志等待池中的线程可以获取锁标志,它们随时准备争夺锁的拥有权。

原文链接:https://blog.csdn.net/xiangwanpeng/article/details/54972952

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰棍hfv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值