java基础知识

1、java中基本类型占用字节数

Java中有8种数据类型:char int short long byte float double  boolean 

字节是byte,位是bit  一个字节占8位:1byte = 8bit。

char在java中是2个字节,java采用unicode编码,2个字节(16位)来表示一个字符。

数据类型位数字节数
char 162
int324
short16          2
long 648

byte

81
float324
double648

boolean

81

2、java数组转List方法

public class  Arrays类提供了公有静态方法:public static List<T> asList (T... array);

用法:将基本类型的数组转化成List列表。

实例代码如下:

String[] str_int = { "1", "2" , "3" , "4" };

List<String> list = Arrays.asList(str_int);

3、 java静态代码块和静态变量

  1. java静态代码块在类被载入时执行,且只被执行一次。
  2. 静态变量先于静态代码块初始化。
  3. 类的构造方法每次通过new创建对象时,都会调用。

4、Object有哪些公共方法?

Object类有11个方法,有两个protected的方法,其中一个为clone方法,另一个是finalize()方法。

  • 所有方法
1. getClass()
2. hashCode()
3. equals()
4. toString()
5. clone()
6. wait()
7. notify()
8. notifyAll()
9. finalize()
  • 各个方法作用:
  • 方法摘要

protected Object clone() 创建并返回此对象的一个副本。
boolean equals(Object obj) 指示某个其他对象是否与此对象“相等”。
protected void finalize() 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
Class  getClass() 返回一个对象的运行时类。
int hashCode() 返回该对象的哈希码值。
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
String toString() 返回该对象的字符串表示。
void wait() 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout) 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
void wait(long timeout, int nanos) 导致当前的线程等待,直到其他线程调用此对象的 notify()。

5、String,StringBuilder和StringBuffer的区别

String是不可变的,任何修改都会创建新对象(比如concat(),substring())。
StringBuilder和StringBuffer底层是char[]数组实现的。是可变字符串,直接在原对象上修改。
String,StringBuffer是线程安全的,而StringBuilder是线程不安全的。
使用场景:String字符串常量、少量字符串操作;StringBuilder单线程下大量字符串操作;StringBuffer多线程下大量字符串操作。

6、wait()和sleep()的区别

  • sleep()是Thread类的静态方法,而wait是Object类的方法
  • 调用sleep()方法线程不会释放对象锁,而调用wait方法线程会释放对象锁。
  • sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU。
  • sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒。或调用interrupt()唤醒。wait需其他线程调用notify()/notifyAll()。

7、java中的四种引用

从jdk1.2版本开始,把对象的引用分为四种级别,这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用

1、强引用

如果一个对象具有强引用,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会回收具有强引用的对象来解决内存不足问题。如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话JVM在合适的时机就会回收该对象。

2、软引用

如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,软引用就会被垃圾回收器回收。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

3、弱引用

具有弱引用的对象拥有更短暂的生命周期。因为当JVM进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收,不过垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

4、虚引用

“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。

虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

8、java垃圾回收机制

在Java中,如果不再有引用指向对象,这样的对象将不可到达(unreachable)。垃圾回收用于释放不可到达对象所占据的内存。这是垃圾回收的基本原则。

怎么判断一个对象是否需要回收?

1. 引用计数(最简单古老的方法):指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。缺点:无法检测出循环引用

2. 跟踪收集器。对象引用遍历(现在大多数 jvm 使用的方法):对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。

垃圾收集算法

1. 标记清除算法:遍历对象图并且记录可到达的对象,以便删除不可到达的对象,一般使用单线程工作并且可能产生内存碎片。

2. 标记-压缩回收法:前期与第一种方法相同,只是多了一步,将所有的存活对象压缩到内存的一端,这样内存碎片就可以合成一大块可再利用的内存区域,提高了内存利用率。

3. 复制回收法:把现有内存空间分成两部分,gc运行时,它把可到达对象复制到另一半空间,再清空正在使用的空间的全部对象。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。

4. 分代回收法:把内存空间分为两个或者多个域,如年轻代和老年代,年轻代的特点是对象会很快被回收,因此在年轻代使用效率比较高的算法。当一个对象经过几次回收后依然存活,对象就会被放入称为老年的内存空间,老年代则采取标记-压缩算法。

9、StringBuilder使用注意事项

  • StringBuilder构造方法
public StringBuilder(String str)
str可以为空,但不能为null。构造方法内部调用append方法,将str添加到StringBuilder中
public StringBuilder(int capacity) capacity是初始容量大小
  • append方法

append方法添加的数据类型比较全,参数可传String,boolean,char,int,long,float,double,char[],StringBuffer,Object obj等等。比如传null,将添加一个"null"字符串。

10、Socket编程步骤

Socket编程步骤分为:服务器端(ServerSocket)客户端(Socket)

  1.  在服务器端建立一个ServerSocket绑定相应的端口号,并且在指定的端口进行侦听,等待客户端连接。ServerSocket  serverSocket = new ServerSocket(9090);
  2. 客户端创建连接Socket,并且向服务器端发送请求。
  3. 服务器收到请求,并且接受客户端的请求信息。调用accept方法等待客户连接。accept方法是一个阻塞的方法,一旦由客户请求,它就会返回一个新的Socket对象用于同客户进行交互。
  4. 客户端与服务器端通过相应的输入/输出流进行数据的交换。
  5. 当客户端和服务器端通信完毕后,需要分别关闭socket。

服务器端:
1.创建ServerSocket对象,绑定监听端口
2.通过accept()方法监听客户端请求
3.连接建立后,通过输入流读取客户端发送的请求信息
4.通过输出流向客户端发送响应信息
5.关闭相关资源
客户端:
1.创建Socket对象,指明需要连接的服务器的地址和端口号
2.连接建立后,通过输出流向服务器端发送请求信息
3.通过输入流获取服务器响应的信息
4.关闭相关资源

11、switch能够使用String做参数?

在Jdk1.7之前只支持byte,short,int,char或者对应的封装类以及Enum类型,不支持String和long类型。

在Jdk1.7中加入String支持,String不能传null做参数,同时case语句中使用的字符串也不能为null,因为底层是通过equals和hashmap实现的。

12、equals和==的区别

== 等于,equals相同

如果比较对象是值变量,只能用==,equals是不存在的。

如果比较对象是引用型变量:

==:比较两个引用是不是指向同一个对象实例。

equals:比较两个引用指向的对象实例的值是不是相同。

参考[如何“记住” equals 和 == 的区别?](https://www.zhihu.com/question/26872848/answer/34357265)

13、ScheduledThreadPool CachedThreadPool FixedThreadPool SingleThreadPool核心线程数比较

核心概念:什么是核心线程数?

  • 核心线程 (Core Threads):线程池中长期存在、保持活动状态的最小线程数量。即使它们处于空闲状态,也不会被回收(除非设置了 allowCoreThreadTimeOut)。

  • 最大线程数 (Maximum Pool Size):线程池允许创建的最大线程数量。

  • 工作队列 (Work Queue):用于存放待执行任务的队列。

详细对比与分析

下面的表格清晰地展示了这四种线程池在核心线程数和其他关键参数上的区别:

线程池类型核心线程数最大线程数存活时间 (Keep-Alive Time)工作队列特点与适用场景
FixedThreadPool
(Executors.newFixedThreadPool(n))
固定 (n)固定 (n)0 (无限)LinkedBlockingQueue
(无界队列)
资源池化思想。线程数量固定,可以控制最大并发数,超出线程数的任务会在队列中等待。适用于负载较重、需要限制资源使用的场景。
CachedThreadPool
(Executors.newCachedThreadPool())
0Integer.MAX_VALUE
(约21亿)
60秒SynchronousQueue
(直接传递)
弹性伸缩。无核心线程,有新任务且无空闲线程时,会立即创建新线程。空闲线程在60秒后回收。适用于执行很多短生命周期的异步任务。
SingleThreadPool
(Executors.newSingleThreadExecutor())
110 (无限)LinkedBlockingQueue
(无界队列)
顺序执行。保证所有任务按提交顺序串行执行。不需要处理线程同步问题。
ScheduledThreadPool
(Executors.newScheduledThreadPool(n))
固定 (n)Integer.MAX_VALUE0 (无限)
(针对核心线程)
DelayedWorkQueue
(延迟队列)
定时/周期任务。核心线程数决定了可并发执行的定时任务数量。用于执行延迟任务或周期性任务。

深入理解核心线程数的设计逻辑

1. FixedThreadPool (固定大小线程池)
  • 核心线程数 = 最大线程数 = n

  • 设计逻辑:创建一个固定大小的“资源池”。这就像一个有固定员工数量的团队,任务来了就处理,处理不完的任务就放进一个无限制的待办清单(无界队列)里排队。这种方式非常稳定,可以防止资源被耗尽,但如果任务积压过多,可能会导致内存溢出(OOM)。核心线程一旦创建,就永远不会被回收。

2. CachedThreadPool (缓存线程池)
  • 核心线程数 = 0

  • 设计逻辑:这是一个“按需创建”的线程池。它没有任何常驻的核心线程。当新任务到来时,它首先寻找空闲线程,如果找不到,就立即创建一个新线程来处理。空闲线程只有60秒的寿命,之后就会被回收。

    • 优点:对于大量短时任务,响应非常快,并且能有效利用系统资源(空闲时线程会自动消失)。

    • 风险:当任务提交速度超过处理速度时,可能会创建海量线程,最终耗尽系统资源。Integer.MAX_VALUE的最大线程数是一个非常危险的设置。

3. SingleThreadPool (单线程线程池)
  • 核心线程数 = 最大线程数 = 1

  • 设计逻辑:可以看作是 FixedThreadPool 的一个特例(n=1)。它保证所有任务在一个单独的线程中按顺序执行。这简化了任务调度,因为你不需要担心并发带来的线程安全问题。它还有一个优点是,如果这个唯一的线程因为异常而终止,线程池会自动创建一个新的线程来继续执行后续任务。

4. ScheduledThreadPool (定时任务线程池)
  • 核心线程数 = n

  • 设计逻辑:它的核心是用于执行定时周期性任务。核心线程数 n 在这里表示可以同时运行的定时任务数量。例如,如果你设置核心线程数为5,那么最多可以有5个定时任务同时执行。即使用 schedule() 执行的单次延迟任务,也需要核心线程来执行。核心线程即使空闲也不会被回收,以确保定时任务能够被准时触发。

总结与最佳实践

  • FixedThreadPool:最常用、最可控,适用于已知的、稳定的并发负载。

  • CachedThreadPool:慎用!仅适用于任务量不可预测且都是短平快的场景。

  • SingleThreadPool:适用于需要任务顺序执行,或任何需要保证任务互斥的场景。

  • ScheduledThreadPool:专门用于调度任务,是 Timer 的现代化、更安全的替代品。

重要提示:在阿里巴巴等公司的《Java开发手册》中,强制不允许使用 Executors 工具类直接创建线程池(尤其是 CachedThreadPool 和 FixedThreadPool),而是推荐通过 ThreadPoolExecutor 的构造函数来手动创建。这样做的好处是:

  1. 可以避免 FixedThreadPool 和 SingleThreadPool 无界队列可能导致的内存溢出(OOM)。

  2. 可以避免 CachedThreadPool 最大线程数过大可能导致的内存和线程资源耗尽。

  3. 让开发者明确线程池的运行规则,进行合理的参数配置。

14、Collection和Collections的区别

1. java.util.Collection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。

Collection子类有Set、List、LinkedList、AbstractCollection、Vector、ArrayList、HashSet、TreeSet、SortedSet、LinkedList

2. Collections是一个包装类,它包含各种有关集合操作的静态方法,此类不能实例化。类似的还有:Arrays。

15、ArrayList和Vector区别

ArrayList在Java1.2引入,用于替换Vector。

Vector:线程同步。当Vector中的元素超过它的初始大小时,Vector会将它的容量翻倍。

ArrayList:线程不同步,但性能很好。当ArrayList中的元素超过它的初始大小时,ArrayList只增加50%的大小。

HashMap是线程不安全且能放空键或空值,Hashtable线程安全且不能放空键或空值

16、ArrayList和LinkedList的区别

1.ArrayList 内部通过数组实现,它允许对元素进行快速随机访问。当在ArrayList的中间位置不断插入或者删除元素时,需要对数组进行复制,移动,代价比较高,因此适合随机查找和遍历,不适合插入和删除。不同步,允许重复元素

2.LinkedList 它是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值