第一天
1.重载和重写的区别?
重载发生在一个类中,同名的方法如果有不同的参数列表(类型不同、个数不同、顺序不同)则视为重载。
重写发生在子类与父类之间,重写要求子类重写之后的方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常。
2.String 和 StringBuffer、StringBuilder 的区别是什么?
- 不可变性:
- String类是不可变的,即一旦创建了String对象,就不能修改它的值。每次对String对象的操作都会创建一个新的String对象,导致内存开销较大。
- StringBuffer和StringBuilder类是可变的,它们允许修改已有的字符串内容。对于频繁的字符串操作,使用可变的类可以避免频繁地创建新对象,提高性能。
- 线程安全性:
- String类是线程安全的,因为它的不可变性使得多个线程可以共享同一个String对象,不会出现并发修改的问题。
- StringBuffer类是线程安全的,它的方法都是同步的(synchronized),因此多个线程可以安全地使用它进行字符串操作。但是,由于同步操作的开销,它的性能相对较低。
- StringBuilder类是非线程安全的,它的方法没有进行同步。因此,在多线程环境下使用StringBuilder时需要自行保证线程安全。
- 性能:
- 由于String类的不可变性,每次对字符串进行修改时都会创建一个新的String对象,导致频繁的内存分配和回收,对性能有一定影响。
- StringBuffer和StringBuilder类的可变性使得它们在进行字符串操作时不会频繁创建新对象,性能较高。StringBuilder类比StringBuffer类的性能稍高,因为它的方法没有进行同步。
综上所述,如果需要频繁进行字符串操作且不涉及多线程环境,推荐使用StringBuilder类,它具有较高的性能。如果涉及多线程环境或需要线程安全,使用StringBuffer类。String类则适用于不需要修改字符串内容的情况。
3.== 与 equals 的区别?
"=="操作符: - 对于基本数据类型,"=="比较的是值是否相等。
- 对于引用类型(对象),"=="比较的是对象的引用是否相等,即两个对象是否指向同一个内存地址。"equals()"方法: "equals()"方法是Object类的方法 , 默认情况下,Object类的"equals()"方法比较的是两个对象的引用是否相等,等价于"=="操作符。 通常,我们需要在自定义类中重写"equals()"方法,根据类的实际需求来定义两个对象是否相等的判断逻辑。 比如:`String str1 = "Hello"; String str2 = new String("Hello"); boolean result = str1.equals(str2); // true`
4.抽象类和接口的区别是什么?
抽象类(Abstract Class)和接口(Interface)是Java中用于实现抽象类型的两种机制,他们的区别如下:实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。构造函数:抽象类可以有构造函数;接口不能有。实现数量:类可以实现很多个接口;但只能继承一个抽象类【java只支持单继承】。访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的抽象方法可以使用Public和Protected修饰.设计层面:抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。
5. 面向对象的特点
面向对象编程(Object-Oriented Programming,简称OOP)具有以下特征:封装:
封装是将数据和对数据的操作封装在一个单元中,通过定义类来实现。
类通过公共接口(方法)来控制对内部数据的访问,隐藏了内部实现的细节,提供了数据的安全性和保护。继承:
继承是通过定义一个新的类来继承现有类的特性(属性和方法)。
继承实现了代码的重用,可以建立类之间的层次关系,并通过父类的特性扩展子类的功能。
子类可以继承并重写父类的方法,实现多态性。多态性:
多态性指的是同一类型的对象,在不同的情境下表现出不同的行为。
多态性通过方法的重写和方法的重载实现。
多态性使得程序可以更加灵活和可扩展,提高了代码的可读性和可维护性。这些特征共同构成了面向对象编程的核心思想和基本原则,使得代码具有可重用性、可扩展性、可维护性和可理解性。面向对象编程使得程序更易于设计、实现和维护,提高了软件开发的效率和质量。
第二天
1.Collection 和 Collections 有什么区别?
- Collection:
- Collection是Java集合框架中定义的接口,它是所有集合类的根接口。
- Collection接口提供了对一组对象进行集合操作的通用方法,如添加、删除、查找等。
- Collection接口的常见实现类包括List、Set和Queue等。
- Collections:
- Collections是Java中提供的一个工具类,包含了各种操作集合的静态方法。
- Collections类提供了一系列静态方法,用于对集合进行排序、查找、替换、同步等操作。
- Collections类中的方法都是通过传入集合对象作为参数来操作集合。
需要注意的是,Collection和Collections之间没有直接的继承或关联关系。Collection是一个接口,定义了集合的通用行为,而Collections是一个工具类,提供了对集合的操作方法。我们可以使用Collections类的方法对实现了Collection接口的具体集合对象进行操作。
2.List、Set、Map 之间的区别是什么?
- List是一个有序的集合,允许元素重复,可以通过索引访问和修改元素。
- Set是一个不允许重复元素的集合,元素无固定顺序,无法通过索引访问元素。
- Map是一种键值对的映射结构,键唯一,值可以重复,可以通过键来获取值。
需要根据具体的需求选择适当的接口和实现类。如果需要有序的集合,可以选择List;如果需要去重的集合,可以选择Set;如果需要根据键查找对应的值,可以选择Map。
3. HashMap 和 Hashtable 有什么区别?
存储:HashMap 运行 key 和 value 为 null,而 Hashtable 不允许。
线程安全:Hashtable 是线程安全的,而 HashMap 是非线程安全的。
性能:HashMap的性能通常比Hashtable更好。Hashtable的方法是同步的,因此在单线程环境下会产生额外的性能开销。HashMap允许使用null值,避免了对null值的判断和同步操作,有利于性能优化。
4. 说一下 HashMap 的实现原理?
HashMap 基于 Hash 算法实现的,我们通过 put(key,value)存储,get(key)来获取。 当传入 key 时,HashMap 会根据 key. hashCode() 计算出 hash 值,根据 hash 值将 value 保存在 数组 里。当计算出的 hash 值相同且equals不同时,我们称之为 hash 冲突,HashMap 的 做法是用链表和红黑树存储相同 hash 值的 value。当 hash 冲突的个数比较少时,使用链表当hash冲突大于8且数组长度大于64位时使用红黑树。
5. 说一下 HashSet 的实现原理?
HashSet 是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相 关方法来完成,HashSet 不允许重复的值。
第三天
1.ArrayList和LinkedList的区别
ArrayList:基于动态数组,连续内存存储,适合下标访问(随机访问),扩容机制:因为数组长度固定,超出长度存数据时需要新建数组,然后将老数组的数据拷贝到新数组,如果不是尾部插入数据还会涉及到元素的移动(往后复制一份,插入新元素),使用尾插法并指定初始容量可以极大提升性能、甚至超过linkedList (需要创建大量的node对象)LinkedList:基于链表,可以存储在分散的内存中,适合做数据插入及删除操作,不适合查询:需要逐一遍历,遍历LinkedList必须使用iterator,不能使用for循环,因为每次for循环体内通过get(i)取得某一元素时都需要对list重新进行遍历,性能消耗极大。ArrayList基于动态数组实现的非线程安全的集合;LinkedList基于链表实现的非线程安全的集合。
对于随机index访问的get和set方法,一般ArrayList的速度要优于LinkedList。因为ArrayList直接通过数组下标直接找到元素;LinkedList要移动指针遍历每个元素直到找到为止。
新增和删除元素,一般LinkedList的速度要优于ArrayList。因为ArrayList在新增和删除元素时,可能扩容和复制数组;LinkedList实例化对象需要时间外,只需要修改指针即可。
LinkedList集合不支持 高效的随机访问(RandomAccess)
ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
2. Java集合容器有哪些?
Java中的集合容器是用于存储和操作一组对象的数据结构。Java提供了许多内置的集合容器。以下是一些常见的Java集合容器:
Collection:
--List: 有序可重复集合接口
ArrayList:动态数组,可以根据需要自动增长大小。
LinkedList:双向链表,可以在任意位置插入和删除元素。
–Set:无序不可重复集合接口
HashSet:基于哈希表实现的集合,不允许重复元素。
TreeSet:基于红黑树实现的有序集合,按照元素的自然顺序进行排序。
LinkedHashSet:基于哈希表和链表实现的集合,保持元素的插入顺序。
Map: 键值对集合对象
- HashMap:基于哈希表实现的键值对映射,不允许重复键。
- TreeMap:基于红黑树实现的有序键值对映射,按照键的自然顺序进行排序。
- LinkedHashMap:基于哈希表和链表实现的键值对映射,保持元素的插入顺序。
以上仅是一些常见的集合容器。每种集合容器都有其特定的用途和适用场景,选择合适的容器可以提高代码效率和可读性。
3.哪些集合类是线程安全的?
Vector、Hashtable、Stack 都是线程安全的,而像 HashMap 则是非线程安全 的,不过在JDK1.5之后随着 Java.util.concurrent 并发包的出现,它们也有 了 自 己 对 应 的 线 程 安 全 类 , 比 如 HashMap 对 应 的 线 程 安 全 类 就 是 ConcurrentHashMap.
4.创建线程有哪几种方式?
创建线程有三种方式:
继承 Thread 重写 run 方法;
实现 Runnable 接口;
实现 Callable 接口。
5.说一下 runnable 和 callable 有什么区别?
runnable 没有返回值,callable 可以拿到有返回值,callable 可以看作是 runnable 的补充。
1.callable 任务体有返回值
2.callable 任务体抛出异常了
3.callable 是Runnable补充
第四天
1.线程有哪些状态?
- 新建(New):当线程对象被创建但尚未启动时处于新建状态。
- 可运行(Runnable):线程对象调用了
start()
方法后,线程处于可运行状态。在可运行状态下,线程可能正在执行,也可能正在等待系统资源(如处理器时间片)。- 运行(Running):线程获得了处理器时间片并正在执行其任务。
- 阻塞(Blocked):线程被阻塞并暂时停止执行,通常是因为等待某个操作的完成(如等待I/O操作、等待获取锁、等待某个条件满足等)。
- 等待(Waiting):线程等待某个特定条件的发生,需要其他线程显式地唤醒(如通过
wait()
方法)。- 超时等待(Timed Waiting):线程等待一段特定的时间,超过时间后会自动唤醒。
- 终止(Terminated):线程执行完毕或出现异常导致终止,不再可运行。
2.sleep() 和wait() 有什么区别?
类的不同:sleep() 来自 Thread,wait() 来自 Object。
释放锁:sleep() 不释放锁;wait() 释放锁。
用 法 不 同 : sleep() 时 间 到 会 自 动 恢 复 ; wait() 可 以 使 用 notify()/notifyAll()直接唤醒。
3.notify()和 notifyAll()有什么区别?
notifyAll()会唤醒所有的线程,notify()只会唤醒一个线程。notifyAll() 调用后, 会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则 留在锁池等待锁被释放后再次参与竞争。而 notify()只会唤醒一个线程,具体唤醒哪一个 线程由虚拟机控制。
4.线程的 run() 和 start() 有什么区别?
start() 方法用于启动线程,run() 方法用于执行线程的运行时代码。run() 可以重复 调用,而 start() 只能调用一次。
5.说一说几种常见的线程池及适用场景?
- 固定大小线程池(FixedThreadPool):
- 特点:创建一个固定大小的线程池,线程数量固定,任务提交后会一直保持执行状态,直到线程池关闭。
- 适用场景:适用于需要限制并发线程数量的场景,如服务器后台处理任务、Web服务器。
- 缓存线程池(CachedThreadPool):
- 特点:创建一个可以动态调整大小的线程池,根据任务的数量自动增加或减少线程数量。
- 适用场景:适用于需要处理大量短期任务的场景,如异步任务处理、大量并发请求的服务器。
- 单线程线程池(SingleThreadExecutor):
- 特点:只有一个工作线程的线程池,任务按顺序执行,保证任务的顺序性。
- 适用场景:适用于需要顺序执行任务的场景。
- 调度线程池(ScheduledThreadPool):
- 特点:用于定时执行任务和周期性执行任务的线程池。
- 适用场景:适用于需要定时执行或周期性执行任务的场景,如定时任务调度、定时数据备份。