面试题
接口的意义:规范、扩展、回调。
抽象类的意义:封装子类中重复内容定义成抽象方法,子类虽有不同方法,但是定义是一样的。
抽象类和接口的区别:
1、默认的方法实现:抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现。
2、实现:子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
3、抽象类可以有构造器,接口不能有构造器。
4、与正常Java类的区别:除了你不能实例化抽象类之外,它和普通Java类没有任何区;接口是完全不同的类型。
5、访问修饰符:抽象方法可以有public、protected和default这些修饰符;接口方法默认修饰符是public。你不可以使用其它修饰符。
6、main方法:抽象方法可以有main方法并且我们可以运行它;接口没有main方法,因此我们不能运行它。
7、多继承:抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。
8、速度:它比接口速度要快,接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
9、添加新方法:如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类。
内部类的作用:
- 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
- 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
- 创建内部类对象的时刻并不依赖于外围类对象的创建。
- 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
- 内部类提供了更好的封装,除了该外围类,其他类都不能访问
父类的静态方法能否被子类实现:不能。
JVM的特性:跨平台,不需要重新编译代码。
gc回收机制:最基本做法是分代回收。(待补充)
进程和线程的区别:
进程是系统进行资源分配和调度的一个独立单位。一个程序中至少有一个进程,一个进程中至少有一个线程。进程在执行过程中拥有独立的内存单元,多个线程共享内存。线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
HashMap的实现原理
1. HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。无序的
2.HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。HashMap底层就是一个数组结构,数组中的每一项又是一个链表。
string-stringbuffer-stringbuilder区别
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
String:不可变对象,每次改变时等同于生成一个新的String对象。
StringBuffer:每次结果都会对 StringBuffer 对象本身进行操作,大部分情况下速度要快于String字符串拼接。主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。
StringBuilder:用在字符串缓冲区被单个线程使用的时候,不能保证同步。大部分情况下速度优于StringBuffer。
多态
定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。
作用:消除类型之间的耦合关系。
多态存在的三个必要条件: 一、要有继承; 二、要有重写; 三、父类引用指向子类对象。
多态的好处:可替换性(substitutability)、可扩充性(extensibility)、、接口性(interface-ability)、灵活性(flexibility)、简化性(simplicity)。
实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
线程的阻塞
阻塞指的是暂停一个线程的执行以等待某个条件发生。
阻塞方法:
1、sleep():以毫秒为单位的一段时间作为参数,使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。
2、suspend() 和 resume() 方法:只能在 synchronized 方法或块中调用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume() 被调用,才能使得线程重新进入可执行状态。
3、yield() 方法:yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。
4、wait() 和 notify() 方法:两个方法配套使用,wait() 使得线程进入阻塞状态,释放锁。它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用。notify()随机解锁阻塞线程。调用 notifyAll() 方法将把因调用该对象的 wait() 方法而阻塞的所有线程一次性全部解除阻塞。
死锁:suspend() 方法和不指定超时期限的 wait() 方法的调用都可能产生死锁。
有序否
|
允许元素重复否
|
||
Collection
|
否
|
是
|
|
List
|
是
|
是
|
|
Set
|
AbstractSet
|
否
|
否
|
HashSet
|
|||
TreeSet
|
是(用二叉树排序)
|
||
Map
|
AbstractMap
|
否
|
使用key-value来映射和存储数据,Key必须惟一,value可以重复
|
HashMap
|
|||
TreeMap
|
是(用二叉树排序)
|