1.Java application与Java Applet的区别
Java语言程序分为三类:Applet(网页应用小程序)application(完整应用小程序)、servlet(服务器中的应用小程序)
Java application指能够独立运行的Java应用程序。
Java Applet程序是运行于各种网页文件中,用于增强网页的人机交互、动画显示、声音播放等功能的程序。
(Java应用小程序,可以直接嵌入到网页中,并能够产生特殊的效果,applet经编译后会产生.class文件,把.class文件嵌入到html页面中,用户在链接网页时,applet便会伴随网页一起下载到用户计算机运行。
applet主要用来创建动态交互的web应用程序。
)
Java Applet和Java Application在结构方面的主要表现在:
- 运行方式不同。Java Applet程序不能单独运行,必须依附于一个HTML语言编写的网页并嵌入其中,通过与Java兼容的浏览器来控制执行。Java Application是完整的程序,可以独立运行,只要有支持的Java的虚拟机,他可以独立运行而且不需要其他文件的支持。
- 运行工具不同。运行Java Applet程序的解释器不是独立的软件,而是嵌在浏览器中作为浏览器软件的一部分。Java Application程序被编译以后,用普通的Java解释器就可以使其解释执行,而Java Applet必须通过网络浏览器或者Applet观察器才能执行。\
2.Java语言的包
Java采用包结构来组织和管理类和接口文件。本文介绍Java语言类库中几个常用的包,因为这几个包在软件开发与应用中经常需要用到,其中有些包是必要的。若是离开它,还真不能做事情了。
第一个包:java.lang包。
该包提供了Java语言进行程序设计的基础类,它是默认导入的包。该包里面的Runnable接口和Object、Math、String、StringBuffer、System、Thread以及Throwable类需要重点掌握,因为它们应用很广。
第二个包:java.util包。
该包提供了包含集合框架、遗留的集合类、事件模型、日期和时间实施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。
第三个包:java.io包。
该包通过文件系统、数据流和序列化提供系统的输入与输出。
第四个包:java.net包。
该包提供实现网络应用与开发的类。
第五个包:java.sql包。
该包提供了使用Java语言访问并处理存储在数据源(通常是一个关系型数据库)中的数据API。
第六个包:java.awt包
第七个包:javax.swing包。
庆庆说:这两个包提供了GUI设计与开发的类。java.awt包提供了创建界面和绘制图形图像的所有类,而javax.swing包提供了一组“轻量级”的组件,尽量让这些组件在所有平台上的工作方式相同。
第八个包:java.text包。
提供了与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。
关于上述这些包结构,除了第一个包是自动导入外,其余的包都需要使用import语句导入,才可使用其包里面的类与接口。若想深入了解它们,请多阅读JDKAPI文档,同时,多使用这些包里的类与接口来解决问题和满足需求。
总结
1)Java语言采用包结构组织和管理类与接口,避免命名冲突,结构富有条理而清晰。
2)关注上述常用包,实则是掌握这些包结构下的类与接口的应用。利用它们,加上创意,设计和造就一个个“产品”。
包装类、 math类、Object类、class类
3.什么是Java虚拟机?为什么Java被称为是“平台无关的编程语言”?
Java虚拟机是一个可以执行的Java字节码的虚拟机进程。Java源程序被编译成能被Java虚拟机执行的字节码文件。
Java被设计成允许应用程序可以以运行在任意的平台,而不需要程序员为每一个平台单独重写或者重新编译。Java虚拟机让这个编程可能,因为它知道底层硬件平台的指令长度和其他特性。
链接:https://www.nowcoder.com/questionTerminal/a90230b35b5f4a7287f779ecdd88841d
来源:牛客网
java的跨平台不是java源程序的跨平台 ,如果是这样,那么所以语言都是跨平台的, java源程序先经过javac编译器编译成二进制的.class字节码文件(java的跨平台指的就是.class字节码文件的跨平台,.class字节码文件是与平台无关的),.class文件再运行在jvm上,java解释器(jvm的一部分)会将其解释成对应平台的机器码执行,所以java所谓的跨平台就是在不同平台上安装了不同的jvm,而在不同平台上生成的.class文件都是一样的,而.class文件再由对应平台的jvm解释成对应平台的机器码执行。 最后解释下机器码和字节码的区别: 一,机器码,完全依附硬件而存在~并且不同硬件由于内嵌指令集不同,即使相同的0 1代码 意思也可能是不同的~换句话说,根本不存在跨平台性~比如~不同型号的CPU,你给他个指令10001101,他们可能会解析为不同的结果~ 二,我们知道JAVA是跨平台的,为什么呢?因为他有一个jvm,不论哪种硬件,只要你装有jvm,那么他就认识这个JAVA字节码~~~~至于底层的机器码,咱不用管,有jvm搞定,他会把字节码再翻译成所在机器认识的机器码~~~
4.JDK和JRE的区别是什么?
Java运行时的环境(JRE)。它包括Java虚拟机、Java核心类库和技术文件。它不包含开发工具(JDK)-编译器、调试器和其他工具。
Java开发工具包(JDK)是完整的Java软件开发包,包含了JRE,编译器和其他工具(比如:JavaDOc、Java调试器),可以让开发者开发、编译、执行Java应用程序。
5.static关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?
详解static关键字:https://www.cnblogs.com/dolphin0520/p/3799052.html
“static”关键字表明一个成员变量或者成员方法可以在没有所属的类的实例变量的情况下被访问。
Java中static方法不能被覆盖,以内方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
Java中不可以覆盖private的方法,因为private修饰的变量和方法只能在当前类中使用,如果是其他类继承当前类是不能访问到private变量或者方法的,当然也不能覆盖。
6.是否可以在static环境中访问非static变量?
static变量在Java中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
7.Java支持的数据类型有哪些?什么是自动拆装箱?
Java语言支持的8种基本类型是:
整数型:byte、 short、 int 、long
浮点型: float、 double
布尔型: boolean
字符型: char
整数默认int型,小数默认是double型。Float和long类型的必须加后缀。
自动装箱是Java编译器在基本数据类型和对应的对象包装类型之间的一个转化。比如:把int转化成Integer,double转化为Double,等等。反之就是自动拆箱。
Java支持的数据类型包括两种: 一种是基本数据类型。包括byte、char、short、long、float、double、char、Boolean;
另一种是引用类型:如String等,其实是对象的引用,JVM中虚拟机中存的是对象的地址,创建的对象实质在堆中,通过地址来寻找堆中的对象的过程,即为引用类型。
8.Java中的方法覆盖(Overriding)和方法重载(Overload)是什么意思?
Java中的方法重载发生在同一个类里面两个或者多个方法的方法名相同但是参数不同的情况。于此相对,方法覆盖是说子类重新定义了父类的方法。方法覆盖必须有相同的方法名,参数列表和返回类型。覆盖者可能不会限制它所覆盖的方法的访问。
9.Java中,什么是构造方法?什么是构造方法重载?什么是复制构造方法?
当新对象被创建的时候,构造方法会被调用。每一个类都有构造方法。在程序员没有给类提供构造方法的情况下,Java编译器会为这个类创建一个默认的构造方法。
Java中构造方法重载和方法重载很相似。可以为一个类创建多个构造方法。每一个构造方法必须有它自己唯一的参数列表。
Java不支持像C++中那样的复制构造方法,这个不同点是因为如果你不自己写构造方法的情况下,Java不会创建默认的复制构造方法。
10.Java支持多继承么?
Java中类不支持多继承,只支持单继承(即一个类只有一个父类)。但是Java中的接口支持继承,即一个子接口可以有多个父接口。(接口的作用是用来扩展对象的功能,一个子接口继承多个父接口,说明子接口扩展了多个功能,当类实现接口时,类就扩展了相应的功能)。
11.接口和抽象类的区别?
从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
(接口只能定义一系列方法,算是定义行为,而不能包含具体的变量,不能拥有自己的属性,但是抽象类能够拥有变量)
- 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象方法。
- 类可以实现很多个接口,但是只能继承一个抽象类
- 类可以不实现抽象类和接口声明的所有方法,前提时类必须是抽象的。
- 抽象类可以在不提供接口方法实现的情况下实现接口。
- Java接口中声明的变量默认都是final的,抽象类可以包含非final的变量。
- Java接口中的成员函数默认是public的。抽象类的成员函数可以是prviate、protcet、public。
- 接口是绝对抽象的,不可以被实例化,抽象类页不可以被实例化。
注:java8新特性:在接口中用default修饰的方法可以有函数体
抽象类、抽象方法的详解:
http://baijiahao.baidu.com/s?id=1601409724518057393&wfr=spider&for=pc
https://www.cnblogs.com/ibelieve618/p/6410910.html
12..值传递和引用传递?
值传递是对基本型变量而言的,传递的是该变量的一个副本。改变副本不影响原变量。
引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身。
一般认为,Java内基础类型数据传递是值传递,Java实例对象的传递是引用传递。
详解:https://www.nowcoder.com/questionTerminal/b296e9e1c40542ec8677c1e452b6b576
13.进程和线程的区别?
进程是执行着应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫轻量级进程。
线程与进程的区别:
- 地址空间和其他资源:进程间相互独立,用一个进程的各线程间共享。某进程的线程在其他进程不可见。
- 通信:进程间的通信(IPC),线程间可以直接读写进程数据段(如全局变量)来进行通信----需要进程同步和互斥手段的辅助,以保证数据的一致性。
- 调度和切换:线程上下文切换比进程上下文切换要快的多。
- 在多线程os中,进程不是一个可执行的实体。
进程是运行中的程序,线程是进程的内部的一个执行序列
进程是资源分配的单元,线程是执行行单元
进程间切换代价大,线程间切换代价小
进程拥有资源多,线程拥有资源少
多个线程共享进程的资源
14.创建线程有哪几种不同的方式?你喜欢哪一种?为什么
1.继承Thread类,重写run方法;
2.实现Runable接口,重写run方法,但是比继承Thread类好用,实现接口还可以继承类,避免了单继承带来的局限性。
3.实现callable和Future接口,重写call方法,有返回值。
4.实现了Executor接口的ThreadPoolExecutor来创建线程池。
一般情况下,常见的是第二种。
* Runnable接口有如下好处:
*①避免单继承的局限,一个类可以继承多个接口。
*②适合于资源的共享
详解:
https://blog.youkuaiyun.com/m0_37840000/article/details/79756932
https://www.nowcoder.com/questionTerminal/e33c72bceb4343879948342e2b6e3bca
15.概括的解释下线程的几种可用状态
- 新建(new):新创建一个线程对象。
- 可运行(runnable):线程对象创建后,其他线程(比如mian线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权。
- 运行(running):可运行状态(Runable)的线程获取了CPU的时间片(timeslice),执行程序代码。
- 阻塞(block):阻塞状态是指线程因为某种原因放弃了CPU的使用权,即让出了CPU timeslice,暂时停止运行。直到线程进入可运行(Runable)状态,才能有机会再次获得CPU timeslice转到运行(running)状态。
阻塞分三种:
一、等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waiting queue)中。
二、同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用。则jvm会把该线程放入锁池中。
三、其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或发出了 I / O 请求时, JVM 会把该线程置为阻塞状态。
当 sleep ()状态超时、 join ()等待线程终止或者超时、或者 I / O 处理完毕时,线程重新转入可运行( runnable )状态。
5.死亡(dead):线程run()、mian()方法执行结束,或者因异常退出run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
详解:https://www.nowcoder.com/ta/review-java/review?page=13
16.同步方法和同步代码块的区别?
链接:https://www.nowcoder.com/questionTerminal/08ee355c9e7948ed9afbcf9a0d19998d
来源:牛客网
为何要使用同步?
java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),
将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,
从而保证了该变量的唯一性和准确性。
区别:
同步方法默认用this或者当前类class对象作为锁。
同步代码块可以选择以什么来加锁,比同步方法要更细颗粒度,我们可以选择只同步会发生同步问题的部分代码而不是整个方法;
同步方法使用关键字 synchronized修饰方法,而同步代码块主要是修饰需要进行同步的代码,用 synchronized(object){代码内容}进行修饰
17.在监视器(monitor)内部,是如何做到线程同步的?程序应该做哪种级别的同步?
监视器和锁在Java虚拟机中是一块使用的。监视器监视一块同步代码,确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。线程在获取锁之前不允许执行同步代码块。
在 java 虚拟机中, 每个对象( Object 和 class )通过某种逻辑关联监视器,每个监视器和一个对象引用相关联, 为了实现监视器的互斥功能, 每个对象都关联着一把锁.
一旦方法或者代码块被 synchronized 修饰, 那么这个部分就放入了监视器的监视区域, 确保一次只能有一个线程执行该部分的代码, 线程在获取锁之前不允许执行该部分的代码
另外 java 还提供了显式监视器( Lock )和隐式监视器( synchronized )两种锁方案
18.什么是死锁?
所谓死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
死锁的条件:
- 互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
- 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
- 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
- 循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。
19.如何保持N个线程可以访问N个资源同时又不导致死锁?
链接:https://www.nowcoder.com/questionTerminal/7192c9454277483d8711a7b4237a0bbe
来源:牛客网
指定获取锁的顺序,并强制线程按照指定的顺序获取锁。
多线程产生死锁需要四个条件,分别是互斥性,保持和请求,不可剥夺性还有要形成闭环,这四个条件缺一不可,只要破坏了其中一个条件就可以破坏死锁,其中最简单的方法就是线程都是以同样的顺序加锁和释放锁,也就是破坏了第四个条件。
20.Java集合类框架的基本接口有哪些?
链接:https://www.nowcoder.com/questionTerminal/709828a56a4443d899d89ae95b7c2940
来源:牛客网
集合类接口指定了一组叫做元素的对象。集合类接口的每一种具体的实现类都可以选择以它自己的方式对元素进行保存和排序。有的集合类允许重复的键,有些不允许。
Java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。
总共有两大接口:Collection 和Map ,一个元素集合,一个是键值对集合; 其中List和Set接口继承了Collection接口,一个是有序元素集合,一个是无序元素集合; 而ArrayList和 LinkedList 实现了List接口,HashSet实现了Set接口,这几个都比较常用; HashMap 和HashTable实现了Map接口,并且HashTable是线程安全的,但是HashMap性能更好;
21.为什么集合类没有实现clonerable和Serilizable接口?
克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。
链接:https://www.nowcoder.com/questionTerminal/2a4902f67d5b49b6b4c05f9d7e422caf
来源:牛客网
Java集合类里最基本的接口有:
Collection:单列集合的根接口
List:元素有序 可重复
ArrayList:类似一个长度可变的数组 。适合查询,不适合增删
LinkedList:底层是双向循环链表。适合增删,不适合查询。
Set:元素无序,不可重复
HashSet:根据对象的哈希值确定元素在集合中的位置
TreeSet: 以二叉树的方式存储元素,实现了对集合中的元素排序
Map:双列集合的根接口,用于存储具有键(key)、值(value)映射关系的元素。
HashMap:用于存储键值映射关系,不能出现重复的键key
TreeMap:用来存储键值映射关系,不能出现重复的键key,所有的键按照二叉树的方式排列
实现Serializable序列化的作用
- 将对象的状态保存在存储媒体中以便可以在以后重写创建出完全相同的副本;
- 按值将对象从一个从一个应用程序域发向另一个应用程序域。
实现 Serializable接口的作用就是可以把对象存到字节流,然后可以恢复。所以你想如果你的对象没有序列化,怎么才能进行网络传输呢?要网络传输就得转为字节流,所以在分布式应用中,你就得实现序列化。如果你不需要分布式应用,那就没必要实现实现序列化。
22.什么是迭代器 (iterator)?
Iterator接口提供了很多对集合元素进行迭代的方法。
每一个集合类都包含了可以返回迭代器实例的
迭代方法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调用集合的
remove(Object Obj)删除,可以通过迭代器的remove()方法删除。
链接:https://www.nowcoder.com/questionTerminal/8863f297b1fc4bbca6de95528b6051e1
来源:牛客网
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
23.Iterator和ListIterator的区别是什么?
1.iterator可用来遍历set和list集合,但是listiterator只能用来遍历list
2.iterator对集合只能是向前遍历,listiteraor既可以向前也可以向后。
3.listerator实现了iterator接口,并包含其他的功能,例如:增加元素、替换元素,获取前一个和后一个元素的索引等等。
24.快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
一:快速失败(fail—fast)
在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的结构进行了修改(增加、删除),则会抛出Concurrent Modification Exception。
原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果结构发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。
场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。
二:安全失败(fail—safe)
采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。
缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。
场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。
25.Java中的HashMap的工作原理是什么?
Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和equals()方法向集合/匆匆集合添加和检索元素。当调用put()方法的时候,HashMap会计算hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在,value会被更新成新值。HashMap的一些重要特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。
详解:https://www.nowcoder.com/questionTerminal/6bd3857199564b3fb2d3fee4f4de06ea
26.hashCode()和equals()方法的重要性体现在什么地方?
Java中的HashMap使用hashCode()和equals()方法来确定键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确的实现这两个方法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现对HashMap的精确性和正确性是至关重要的。
详解:https://blog.youkuaiyun.com/u010223904/article/details/46295439
27.HashMap和Hashtable有什么区别?
HashMap和Hashtable都实现了Map接口。
1、HashMap是非线程安全的,HashTable是线程安全的。
2、HashMap的键和值都允许有null值存在,而HashTable则不行。
3、因为线程安全的问题,HashMap效率比HashTable的要高。
4、Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
一般现在不建议用HashTable, ①是HashTable是遗留类,内部实现很多没优化和冗余。②即使在多线程环境下,现在也有同步的ConcurrentHashMap替代,没有必要因为是多线程而用HashTable。
详解:https://blog.youkuaiyun.com/wangxing233/article/details/79452946
28.数组(Array)和列表(Arraylist)有啥区别?什么时候应该使用Array而不是Array List?
ArrayList可以算是Array的加强版,(对array有所取舍的加强)。
- 存储内容比较:
- Array数组可以包含基本类型和对象类型,
- ArrayList却只能包含对象类型。
但是需要注意的是:Array数组在存放的时候一定是同种类型的元素。ArrayList就不一定了,因为ArrayList可以存储Object。
- 空间大小比较:
- 它的空间大小是固定的,空间不够时也不能再次申请,所以需要事前确定合适的空间大小。
- ArrayList的空间是动态增长的,如果空间不够,它会创建一个空间比原空间大一倍的新数组,然后将所有元素复制到新数组中,接着抛弃旧数组。而且,每次添加新的元素的时候都会检查内部数组的空间是否足够。(比较麻烦的地方)。
方法上的比较:
ArrayList作为Array的增强版,当然是在方法上比Array更多样化,比如添加全部addAll()、删除全部removeAll()、返回迭代器iterator()等。
适用场景:
如果想要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以将它们放进一个全局数组里,但是如果我们单纯只是想要以数组的形式保存数据,而不对数据进行增加等操作,只是方便我们进行查找的话,那么,我们就选择ArrayList。而且还有一个地方是必须知道的,就是如果我们需要对元素进行频繁的移动或删除,或者是处理的是超大量的数据,那么,使用ArrayList就真的不是一个好的选择,因为它的效率很低,使用数组进行这样的动作就很麻烦,那么,我们可以考虑选择LinkedList。
29.ArrayList和LinkedList有什么区别?
ArrayList的实现用的是数组,LinkedList是基于链表,ArrayList适合查找,LinkedList适合增删。
ArrayList和LinkedList都实现了List接口,他们有以下的不同点:
ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。
相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
也可以参考ArrayList vs. LinkedList。
30.Comparable和Comparator接口是干什么的?列出它们的区别。
Java提供了只包含一个compareTo()方法的Comparable接口。这个方法可以个给两个对象排序。具体来说,它返回负数,0,正数来表明已经存在的对象小于,等于,大于输入对象。
Java提供了包含compare()和equals()两个方法的Comparator接口。compare()方法用来给两个输入参数排序,返回负数,0,正数表明第一个参数是小于,等于,大于第二个参数。equals()方法需要一个对象作为参数,它用来决定输入参数是否和comparator相等。只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果是相同的时候,这个方法才返回true。
链接:https://www.nowcoder.com/questionTerminal/99f7d1f4f8374e419a6d6924d35d9530
来源:牛客网
Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。 Comparator位于包java.util下,而Comparable位于包 java.lang下 Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口) 自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序, 这里的自然顺序就是实现Comparable接口设定的排序方式。 而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。 可以说一个是自已完成比较,一个是外部程序实现比较的差别而已。 用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。 比如:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不需要去修改 Integer 类(实际上你也不能这么做)去改变它的排序行为,只要使用一个实现了 Comparator 接口的对象来实现控制它的排序就行了。
链接:https://www.nowcoder.com/questionTerminal/99f7d1f4f8374e419a6d6924d35d9530
两种方式,各有各的特点:使用Comparable方式比较时,我们将比较的规则写入了比较的类型中,其特点是高内聚。但如果哪天这个规则需要修改,那么我们必须修改这个类型的源代码。如果使用Comparator方式比较,那么我们不需要修改比较的类,其特点是易维护,但需要自定义一个比较器,后续比较规则的修改,仅仅是改这个比较器中的代码即可。
31.Java的优先级队列
PriorityQueue是一个基于优先级堆的无界队列,它的元素是按照自然顺序(natural order)排序的。
优先级队列中的元素可以按照任意的顺序插入,却总是按照排序的顺序进行检索。无论何时调用remove方法,总会获得当前优先级队列中的最小元素,但并不是对所有元素都排序。它是采用了堆(一个可以自我调整的二叉树),执行增加删除操作后,可以让最小元素移动到根。
32.如何权衡是使用无序的数组还是有序的数组?
查询 | 插入 | |
有序数组 | O(logN) | O(logN) |
无序数组 | O(N) | O(1) |
有序数组查询容易,插入难。无序数组插入容易,查询难
33.Enumeration接口和Iterator接口的区别有哪些?
1.Enumeration速度是Iterator的2倍,同时占用更少的内存。I
2.terator远远比Enumeration安全,因为其他线程不能够修改正在被iterator遍历的集合里面的对象。
3.Iterator允许调用者删除底层集合里面的元素,这对Enumeration来说是不可能的。
34.HashSet和TreeSet区别?
HashSet是由一个hash表来实现的,因此,它的元素是无序的。add(),remove(),contains()方法的时间复杂度是O(1)。
另一方面,TreeSet是由一个树形的结构来实现的,它里面的元素是有序的。因此,add(),remove(),contains()方法的时间复杂度是O(logn)。
35.Java中的垃圾回收有什么目的?什么时候进行垃圾回收?
目的:回收堆内存中不再使用的对象,释放和重用资源
回收时间:当对象永久地失去引用后,系统会在合适的时候回收它所占的内存。(即触发GC的时间,在新生代的Eden区满了,会触发新生代GC(Mimor GC),经过多次触发新生代GC存活下来的对象就会升级到老年代,升级到老年代的对象所需的内存大于老年代剩余的内存,则会触发老年代GC(Full GC)。当程序调用System.gc()时也会触发Full GC)
36.System.gc()和Runtime.gc()会做些什么事情?
调用 System.gc() 实际上等效于调用。 Runtime.getRuntime().gc()这两个方法用来提示JVM要进行垃圾回收。但是,立即开始还是延迟进行垃圾回收是取决于JVM的。
37.finalize()方法什么时候被调用?析构函数(finalization)的目的是什么?
垃圾回收器(garbage collector)决定回收某对象时,就会运行该对象的finalize()方法 但是在Java中很不幸,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说filalize()可能永远不被执行,显然指望它做收尾工作是靠不住的。 那么finalize()究竟是做什么的呢?它最主要的用途是回收特殊渠道申请的内存。Java程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++),finalize()的工作就是回收这部分的内存。
参:《深入理解Java虚拟机》
对于Java而言:
调用时机:当垃圾回收器要宣告一个对象死亡时,至少要经过两次标记过程:如果对象在进行可达性分析后发现没有和GC Roots相连接的引用链,就会被第一次标记,并且判断是否执行finalizer( )方法,如果对象覆盖finalizer( )方法且未被虚拟机调用过,那么这个对象会被放置在F-Queue队列中,并在稍后由一个虚拟机自动建立的低优先级的Finalizer线程区执行触发finalizer( )方法,但不承诺等待其运行结束。
finalization的目的:对象逃脱死亡的最后一次机会。(只要重新与引用链上的任何一个对象建立关联即可。)但是不建议使用,运行代价高昂,不确定性大,且无法保证各个对象的调用顺序。可用try-finally或其他替代。
38.如果对象的引用被置空,立即收集器是否会立即释放对象占用的内存。
不会立即释放对象占用的内存。 如果对象的引用被置为null,只是断开了当前线程栈帧中对该对象的引用关系,而 垃圾收集器是运行在后台的线程,只有当用户线程运行到安全点(safe point)或者安全区域才会扫描对象引用关系,扫描到对象没有被引用则会标记对象,这时候仍然不会立即释放该对象内存,因为有些对象是可恢复的(在 finalize方法中恢复引用 )。只有确定了对象无法恢复引用的时候才会清除对象内存。
39.Java堆的结构是什么样子的?什么是堆中的永久代?
JVM的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。它在JVM启动的时候被创建。对象所占的堆内存是由自动内存管理系统也就是垃圾收集器回收。
堆内存是由存活和死亡的对象组成的。存活的对象是应用可以访问的,不会被垃圾回收。死亡的对象是应用不可访问尚且还没有被垃圾收集器回收掉的对象。一直到垃圾收集器把这些对象回收掉之前,他们会一直占据堆内存空间。
详解链接:https://www.nowcoder.com/questionTerminal/5c3dc3914da548e5b0617f4da9da7488
40.串行(serial)收集器和吞吐量(throughput)收集器的区别?
链接:https://www.nowcoder.com/questionTerminal/46b6030921164ab0a3cb3dbd6d64f01a
来源:牛客网
串行GC:整个扫描和复制过程均采用单线程的方式,相对于吞吐量GC来说简单;适合于单CPU、客户端级别。串行收集器对大多数的小应用(在现代处理器上需要大概100M左右的内存)就足够了。
吞吐量GC:采用多线程的方式来完成垃圾收集;适合于吞吐量要求较高的场合,比较适合中等和大规模的应用程序。
41.在Java中,对象什么时候可以被垃圾回收?
当对象对当前使用这个对象的应用程序变得不可触及的时候,这个对象就可以被回收了。
当一个对象到GC Roots不可达时,在下一个垃圾回收周期中尝试回收该对象,如果该对象重写了finalize()方法,并在这个方法中成功自救(将自身赋予某个引用),那么这个对象不会被回收。但如果这个对象没有重写finalize()方法或者已经执行过这个方法,也自救失败,该对象将会被回收。
42.Java中的两种异常类型是什么?他们有什么区别?
Throwable包含错误(error)和异常(Exception)两类。
异常类又包含运行时异常(RuntimeException,非检查异常)和非运行时异常(Exception,检查性异常)。
(1) Error是程序无法处理了, 如果OutOfMemoryError等等, 这些异常发生时, java虚拟机一般会终止线程 .
(2) 运行时异常都是RuntimeException类及其子类,如 NullPointerException、IndexOutOfBoundsException等, 这些异常是不检查的异常, 是在程序运行的时候可能会发生的, 所以程序可以捕捉, 也可以不捕捉. 这些错误一般是由程序的逻辑错误引起的, 程序应该从逻辑角度去尽量避免.
(3) 检查异常是运行时异常以外的异常, 也是Exception及其子类, 这些异常从程序的角度来说是必须经过捕捉检查处理的, 否则不能通过编译. 如IOException、SQLException等
43.throw和throws区别?
1.Throw用于方法内部,Throws用于方法声明上。
2.Throw后跟异常对象,Throws后跟异常类型。
3.Throw后只能跟一个异常对象,Throw后可以一次声明多个异常类型。
44.异常处理完成以后,Exception对象会发生什么变化?
某个Exception异常被处理后,该对象不再被引用,gc将其标记,在下一个回收过程中被回收。
45.finally代码块和finalize()方法有什么区别?
1. final是关键字,final可以修饰类、方法、属性。
如果一个类被final修饰,那么这个类就是最终类,不能派生出新的子类,不能作为父类被继承,该类中的所有方法都不能被重写,但是final类中的成员变量是可以改变的,要想final类中的成员变量的不可以改变,必须给成员变量添加final修饰。因此,一个类不能同时被final和abstract修饰,这两个关键字相互矛盾。
如果final修饰方法,那么这个方法是最终方法,不允许任何子类重写该方法,但子类仍可以使用该方法,注意:final参数用来表示这个参数在这个函数内部不允许被修改。
final修饰属性,被final修饰的变量不可变。这里的不可变有两重含义:引用不可变和对象不可变。final指的是引用不可变,即它只能指向初始化时指向的那个对象,而不关心指向对象内容的变化。因此,被final修饰的变量必须初始化,该变量其实就是常量。
2. finally作为异常处理的一部分,只能用在try/catch语句快中,finally代码块中的语句一定会被执行,经常被用来释放应用占用资源,如IO流和数据库资源的释放。
3. finalize是Object类的一个方法,该方法在Object类中声明: protected void finalize() throws Throwable { } 在垃圾回收器执行时会调用被回收对象的finalize()方法,可以覆盖此方法来实现对其资源的回收。注意:一旦垃圾回收器准备释放某个对象占用的空间,将首先调该对象的 finalize()方法,并且在下一次垃圾回收动作发生时,才真正将该对象占用的内存回收。
44.Applet的生命周期:
一个 Applet 的生命周期
Applet 类中的四个方法给了你构建 applet 程序时的框架:
- init: 这个方法适用于你的 applet 程序所需要的任何初始化。它在 applet 标记中的参数标签被处理后被调用。
- start: 这个方法在浏览器调用 init 方法后被自动调用。它也在无论何时使用者在去其他页面后返回到包含 applet 的页面时被调用。
- stop: 这个方法在使用者离开有 applet 所在的页面时被自动调用。因此,它在同一个 applet 中能被重复调用。
- destroy: 这个方法仅当浏览器正常关闭时被自动调用。(即卸载applet之前,做最后的清理工作)
45.当applet被载入的时候会发生什么?
首先,创建applet控制类的实例,然后初始化applet,最后开始运行。
46.Java applet有哪些限制?
主要是由于安全的原因,给applet施加了以下的限制:
applet不能够载入类库或者定义本地方法。
applet不能在宿主机上读写文件。
applet不能读取特定的系统属性。
applet不能发起网络连接,除非是跟宿主机。
applet不能够开启宿主机上其他任何的程序。
47.不受信任的applet是指不能访问或是执行本地系统文件的Java applet,默认情况下,所有下载的applet都是不受信任的。
48.从网络上加载的applet和从本地文件系统加载的applet有什么区别?
从网络上加载:applet是由applet类加载器载入的。它受applet安全管理器 的限制。
从本地文件系统加载时,applet是由文件系统加载器载入的。它允许在客户端读文件,写文件,加载类库,并且也允许执行其他程序,但是,却通不过字节码校验。
类加载器:
类加载器有自己的java名称空间等级结构。类加载器会保证来自文件系统的类有唯一的名称空间,来自网络资源的类有唯一的名称空间。
当浏览器通过网络载入applet的时候,applet的类被放置于和applet的源相关联的私有的名称空间中。然后,那些被类加载器载入进来的类都是通过了验证器验证的。验证器会检查类文件格式是否遵守Java语言规范,确保不会出现堆栈溢出(stack overflow)或者下溢(underflow),传递给字节码指令的参数是正确的。
applet安全管理器:
是给applet施加限制条件的一种机制。浏览器可以只有一个安全管理器。安全管理器在启动的时候被创建,之后不能被替换覆盖或者是扩展
49.弹出式选择菜单(choice)和列表(list)的区别
1.Choice是以一种紧凑的形式展示的,需要下拉才能看到所有的选项。List同时可以有多个元素可见,
2.Choice中一次只能选中一个选项。List支持选中一个或者多个元素。
50.布局管理器分类:
FlowLayout 流式布局
BorderLayout 边框式布局
GridLayout 网格布局
CardLayout 卡片布局
GridBagLayout 复杂的网格布局
51.滚动条(Scrollbar)和滚动面板(JScrollPane)有什么区别?
Scrollbar是一个组件,不是容器。而ScrollPane是容器。ScrollPane自己处理滚动事件。
52.哪些Swing的方法是线程安全的?
Swing的规则是:一旦Swing组件被具现化(realized),所有可能影响或依赖于组件状态的代码都应该在事件派发线程中执行。所以有这3个线程安全的方法:repaint(),revalidate(),andinvalidate()。
53.说出三种支持重绘(painting)的组件。
Canvas, Frame, Panel,和Applet支持重绘。
54.MenuItem和CheckboxMenuItem的区别是什么?
CheckboxMenuItem类继承自MenuItem类,支持菜单选项可以选中或者不选中.
55.边缘布局(BorderLayout)里面的元素是如何布局的?
是按照容器的东西南北中进行布局的。