前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java基础总结

java基础总结

作者头像
高大北
发布2022-12-31 15:43:00
4260
发布2022-12-31 15:43:00
举报

Java基础面试题

一: Java基础

1java是什么类型语言

一、你可以说它是编译型的:因为所有的Java代码都是要编译的,.java不经过编译就什么用都没有。 二、你可以说它是解释型的:因为java代码编译后不能直接运行,它是解释运行在JVM上的,所以它是解释运行的,那也就算是解释的了。 三、但是,现在的JVM为了效率,都有一些JIT优化。它又会把.class的二进制代码编译为本地的代码直接运行,所以,又是编译的。

2简单说说Java中对象如何拷贝?
代码语言:javascript
复制
一、浅拷贝clone()

如果对象中的所有数据域都是数值或者基本类型,使用clone()即可满足需求,如:

Person p = new Person();

Person p1 = p.clone();

这样p和p1分别指向不同的对象。

二、深度拷贝

如果在对象中包含子对象的引用,拷贝的结果是使得两个域引用同一个对象,默认的拷贝是浅拷贝,没有拷贝包含在对象中的内部对象。

如果子对象是不可变的,如String,这没有什么问题;如果对象是可变的,必须重新定义clone方法;

三、序列化可克隆(深拷贝)

四、BeanUtils.copyProperties()
3: 什么是Object,有哪些常用的方法,怎么创建对象?
代码语言:javascript
复制
1、使用new关键字;
2、使用Class类的newInstance方法,可调用无参的构造函数创建对象;
3、使用Constructor类的newInstance方法;
4、使用clone方法;
5、使用反序列化。
4:什么是内部类,说说你对他的理解以及实战场景
5: 说说 static 和 final 在Java中的意义
代码语言:javascript
复制
使用final的意义:

为方法上锁,防止任何继承类改变它的本来含义和实现。设计程序时,若希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写,就可以采取这种做法。
提高程序执行的效率,将一个方法设成final后,编译器就可以把对那个方法的所有调用都置入嵌入调用里(内嵌机制)。

static总结
static修饰成员函数:该成员函数不能使用this对象
static不能修饰构造函数
static不能修饰函数参数
static不能修饰局部成员变量
static修饰成员字段
当类被虚拟机加载时,首先按照字段声明的先后顺序对static成员字段进行初始化
static修饰语句块
当类被虚拟机加载时,按照声明顺序先后初始化static成员字段和static语句块
static所修饰的方法和字段是只属于类,所有对象共享。
在static所修饰的函数和语句块中不能使用非static成员字段。
在Java不能直接定义全局变量,是通过static来实现的
在Java中没有const,不能直接定义常量,通过static final来实现
6:int和Integer有什么关联?为什么需要Integer?装箱拆箱
7:什么是序列化,反序列化.说说运用场景
代码语言:javascript
复制
https://www.cnblogs.com/binarylei/p/10987540.html
8:你知道运算符&和&& ,| 和||的区别吗?
代码语言:javascript
复制
& 按位与操作:只有对应的两个二进制数位1时,结果位才为1
    1&1=1;
|按位或操作:有一个为1时,结果位就为1
    1|0=1    
&& ||短路运算符 在逻辑判断中常见
9:用最有效率的方法计算 2*8(位运算)
代码语言:javascript
复制
将一个数左移,相当于乘以2的n次方,位运算是cpu直接支持的,所以效率高
2 << 3

hashmap的初始容量 1<< 4 //16
直接二进制操作,表示1左移4,变成10000,转为10进制就是16
10 写个方法传递两个非0的int数值进去,实现变量交换,有几种方式?
代码语言:javascript
复制
a= a+b;
b=a-b;
a=a-b;
代码语言:javascript
复制
a=a^b;
b=b^a;
a=a^b;
11 java基础数据类型分类
代码语言:javascript
复制
基础数据类型
byte  short int long
float double char boolean
引用数据类型:其他引用类型
string和enum分别是什么类型:引用类型
12 运算
代码语言:javascript
复制
int i=5
return i++; 5
return ++i; 6 
13 == 和equals的区别
代码语言:javascript
复制
基本数据类型 比较要用==判断是否相等
引用数据类型 == 比较的就是内存地址是否一样,不同对象的内存地址不一样,equals比较的是具体的内容
14 string stringbuffer与stringbuilder的区别

三者都是final不允许被继承 本质上都是通过char[]数组实现的 string stringbuffer与stringbuilder中,string是不可变对象。另外两个都是可变的

  • stringbuilder
    • 效率快,因为不需要加锁,但是不具备线程安全
  • stringbuffer
    • 有枷锁操作,不具备线程安全。
15 面向对象oop理解

四大特性 - 抽象 - 声明的类叫抽象类,抽象方法(只有一个声明没有方法体) - 封装 - 让代码更容易理解和维护,加强了安全性 - 继承 - 具有公共的方法和属性 - 多态

16 overload与override区别
  • overload
    • 重载
    • 在同一个类中存在多个名称相同的方法,但是这些方法的参数列表不相同,参数个数或者这个类型不同
  • override
    • 重写
    • 表示子类重写父类的方法
17 接口是否可以继承接口,接口是否支持多继承,类是否支持多继承,接口里面是否可以有方法实现
  • 接口里面可以有静态方法和方法体
  • 接口不是被类继承,而是被实现
  • 接口支持多继承,类不支持多继承
  • 一个类只能继承一个类,但是可以实现多个接口
18 jdk8接口的新特性
  • 接口中可以有static方法,但必须有方法实现体,该方法只属于该接口,接口名直接调用该方法。
  • 接口中新增default关键字修饰的方法,default方法只能定义在接口中,可以在子类或者子类接口中被重写default定义的方法必须有方法体。
19 为什么重写equals还要重写hashcode
  • hashcode
    • 底层是c语言写的,根据对象内存地址,转换成整数类型
  • equals
    • 如果说两个对象的hashcode值一样,对象的内容值不一定相等 set集合的底层就是基于hashmap,key,比较hashcode值和equest值

二: 多线程

一 线程
1 线程的创建方式有哪些
  • 继承thread类,本质还是实现了runable接口的实例,代表一个线程的实例,start方法。没有返回值
  • 实现runable接口,实现run方法,没有返回值,无法抛出异常,使用的时候还需要新建thread。
  • 实现callable接口,实现call方法,任务执行后有返回值,可以抛出异常,需要使用futureTask(本质上还是继承了runable)传递进去,还需要创建thread类进行传递。
2 线程的状态?
  1. 新建状态,new start线程
  2. 运行状态(就虚,和运行),调用线程的start方法
    • 就虚调用了start方法,cpu嗨没有分配时间片
    • 运行掉一哦那个了start方法,cpu正在调度
  3. 堵塞状态:当竞争锁的时候,没拿到,线程挂起
  4. 等待状态:join,wait,park方法
  5. 超时等待状态,thread.sleep,wait,join。。。
  6. 死亡状态:run方法结束
3 进程和线程的区别

进程是操作系统的基本单位,是操作系统结构的基础 线程是cpu调度的最小单位。

4 sleep/yied/join wait/notify/notifyAll
  • thread类
    • sleep
      • 让当前线程暂缓执行,等待预计时间之后,在恢复,不会释放锁,会进入阻塞状态,让出cpu执行权
    • yied
      • 让当前线程暂缓执行,执行其他线程,不会释放锁,不会让线程进入阻塞状态,直接变为就绪,只需要重新获得cpu使用权
    • join
      • 优先执行join的线程,不会释放已经持有的对象锁
  • object类
    • wait
      • 释放当前对象的锁,进入等待队列,需要依靠notify/notifyAll/wait(timeout)时间唤醒
    • notify
      • 唤醒在对象监视器等待的单个线程,是任意的一个
    • notifyAll
      • 唤醒在对象监视器等待的全部线程
5 threadlocal到底是什么/实现原理

存储Thread的局部变量, 从而达到各个Thread之间的隔离运行。它被广泛应用于框架之间的用户资源隔离、事务隔离等。

6 threadlocal的内存泄露问题

ThreadLocal操作不当会引发内存泄露,最主要的原因在于它的内部类ThreadLocalMap中的Entry的设计。 Entry继承了WeakReference<ThreadLocal<?>>,即Entry的key是弱引用,所以key’会在垃圾回收的时候被回收掉, 而key对应的value则不会被回收, 这样会导致一种现象:key为null,value有值。 久而久之,value累加就会导致内存泄漏。

  • 每次使用完ThreadLocal都调用它的remove()方法清除数据。因为它的remove方法会主动将当前的key和value(Entry)进行清除。
  • ThreadLocal的设计者也意识到了这一点(内存泄漏), 他们在一些方法中埋了对key=null的value擦除操作,这里拿ThreadLocal提供的get()方法举例,它调用了ThreadLocalMap#getEntry()方法,对key进行了校验和对null key进行擦除。
二 线程池
1 线程池的核心参数

java提供了基于Executor构建线程池的方式 ThreadPoolExecutor 中

代码语言:javascript
复制
int corePoolSize, //核心线程数
int maximumPoolSize,//最大线程数
BlockingQueue<Runnable> workQueue,任务队列/阻塞队列(array数组,like链表,优先级,delay延迟)
long keepAliveTime, //生存时间
TimeUnit unit,//生存时间的单位
RejectedExecutionHandler handler//拒绝策略
ThreadFactory threadFactory //线程工厂的名称
2 线程池的执行流程
  • 提交任务到线程池中,让线程池中的线程去执行任务
    • 如果有空闲的核心线程数,直接执行
      • 如果没有空闲的核心线程,尝试创建核心线程,去执行任务。
    • 如果已经达到了核心线程数配置
      • 将任务扔到任务队列排队,等待狠心线程执行完其他任务再来执行
        • 如果任务队列满了放不下,放不下任务,构建最大线程数
          • 如果最大线程数也慢了,执行拒绝策略
4 线程池中的ctl是干什么的。

线程池中一个属性,本质 就是int类型的数值,高三位描述线程池的状态,低29位,描述工作线程的数量,线程池在执行任务时,需要多次判断线程池状态,来确定任务是否需要执行,低29位,表述线程池中现存的工作线程数量。

5 线程池的状态有哪些?(5种)
代码语言:javascript
复制
running :线程池正在正常工作,可以处理提交的任务
shutdown:调用线程池的shutdown方法,不接受新的任务,但是会处理现有的任务
stop:调用线程池的shutNow(),不接受新的任务,中断正在处理的任务,不管工作队列
ttdying:过度状态,会从shutdown(工作队列和线程位空)和stop转换成ttdying状态,要停止,但是没停止
terminated:当线程池达到了ttdying状态后,在源码中,会自动调用,进入到了terminated状态。线程池就没了。
6 什么是工作线程

worker对象继承aqs实现runable,线程池执行任务,其实就是调用了worker种的run方法内部的runworker方法 线程池中的工作线程是用worker对象表述的 worker - true 核心线程 - false 最大线程数

7 worker对象为什么继承aqs

其实是为了添加标识来判断当前工作线程,是否可以被打断。

8 工作线程保存在哪里?

保存在线程池的hashset里面。

9 拒绝策略

线程池一共有 4个拒绝策略

  • abort 抛出一个异常
  • discard 扔掉不处理了
  • discardOldest 扔掉排队时间久的
  • callerruns 调用者处理服务
10 如何在线程池执行任务前后做任务处理

befareExecute(前置钩子)-默认空实现

afterExecute(后置钩子)-默认空实现

11 如何合理的分配线程池的大小

在分配线程池容量大小时,必须要根据业务类型来决定。 cpu密集 - 更多的是cpu在计算,一直在工作 - 线程数少一些(推荐:cpu内核数+1) io密集 - 更多的时候线程在等待io - 线程数多一些(推荐:cpu内核数*2)

三 并发编程
1 项目哪里用到了多线程
  • 用户注册
    • 异步renwu用户注册,记录日志
    • 定时任务,定期备份日志,备份数据库
2 线程不安全的数据结构

hashmap,arraylist linkedlist

3 线程安全的数据结构

CopyOnWriteArrayList Vector ConcurrentHashMap

4 如果保证多线程的安全性
  1. 通过volatile 关键字修饰变量,可以实现线程之间的可见性, 避免变量脏读的出现,底层是通过限制jvm指令的重排序来实现的 适用于一个线程修改,多个线程读的场景
  2. 通过synchronized锁(任意对象)来实现线程同步,自动锁的思想, 底层实现原理:当有线程进入同步代码块之后,利用jvm的计数器将 锁的标记置为1,当别的线程再想进入的时候,发现锁的标记为1, 该线程就去锁池等待,当第一个线程出来之后,锁的标记会置为0, 之后cpu会随机分配一个线程再次进入同步代码块.
  3. 通过lock锁的机制,进行手动lock,和unlock,但是这种很容易出现死锁。 注意加锁以及解锁的顺序,就可以避免死锁
  4. 通过线程安全的集合类,可以解决并发问题 ConcurrentHashMap CopyonWriteArrayList
  5. 使用并发包下面的原子类,底层使用的是cas机制(乐观锁),可以解决并发问题 atomicInteger 线程安全的原子整型类
  6. 使用线程池来创建和管理线程,也可以一定程度上解决并发问题
  7. 使用ThreadLocal来修饰变量,可以解决并发问题 ThreadLocal底层是怎么实现的? 多个线程会复制一份threadLocao变量的副本进行操作,互不影响,来保证线程安全的
5 volatile与synchronized有什么区别
  • volatile
    • 是一个轻量级的synchronized,都是保证共享变量的可见行,但是保证不了原子性,避免出现脏毒现象
    • 可以避免指令冲排
      • 包含编译器冲排序和运行时冲排序,jvm在编译的时候,对现有的指令进行重新排序,在不改变程序运行结果的情况下,会进行排序
  • synchronized
    • 保证可见行,也能保证原子性
    • 悲观锁
    • 独占锁
    • 可重入锁
    • 非公平锁
    • 获取不到锁的状态
6 并发编程三要素
  • 原则性
    • 要么全成功 要么全失败 不能中段
  • 有序性
  • 可见行
7 cas(自旋锁)/存在的问题

就是 比较和交换 完了再改。

  • aba问题
    • 追加版本号解决
  • cAS是循环判断如果失败次数过多,占用cpu资源
8 aqs

aqs其实是并发包juc下面的类,实现了一个先进先出的队列,底层就是一个双向链表。使用Node实现队列,利用int类型标识状态。在AQS类中有一个叫做state的成员变量,线程会首先尝试获取锁,如果失败就将当前线程及等待状态等信息包装成一个node节点加入到同步队列sync queue里,接着会不断的循环尝试获取锁。

独占方式。 共享方式。

9 ReentrantLock重入锁

ReentrantLock(重入锁)是lock接口的实现类,,悲观锁,底层是aqs

  • 公平锁
    • 先获取锁资源,拿到当前线程的状态,判断有没有在排队。没有的话给锁
    • 如果已经拿到了,在把锁的次数+1
  • 非公平锁(默认)
    • 不管有没排队,直接拿锁,只要能拿到。
    • 非公平锁的效能高一点
10 ReentrantReadWriteLock重入读写锁
  • 实现了ReadWriteLock接口
    • 读写分离
  • 支持公平和非公平
  • 读锁是共享的,写锁是独占的。

三: 集合框架

一 list
1 arraylist底层如何实现?

arrayli - 数组 arraylist.get()是根据index下标查询的,时间复杂度是(0)1。

2 arraylist add方法/扩容

创建空的数组 给elementData,初始化并且没有容量,采用懒加载的形式, 当使用add方法的时候, 首先判断是否需要扩容 - 如果等于空的时候,直接10的大小的数组 - ArrayList 每次扩容之后容量都会变为原来的 1.5 倍左右。 完了通过index负值。

3 arraylist get方法

会先判段是否越界直接根据下标查询

4 arraylist与Vector

相同点都是基于数组实现的,默认的初始容量都是10

  • arraylist
    • 线程不安全
    • 扩容1.5
  • Vector
    • 线程安全
    • 扩容2倍
4 LinkedList底层原理

底层基于链表【双向】实现的。

5 copyonwritearraylist/synchronizedlist
  • copyonwritearraylist
    • 执行修改的时候,会拷贝一份新的数据,代价昂贵,修改后会将原来的集合指向新的集合。ReentrantLock锁
    • 读的话不需要加锁。
    • 读写分离+最终一致
  • synchronizedlist
    • 每个方法都➕synchronized锁了,
    • 写操作可以,读操作并不如copyonwritearraylist
二 map
1 hashmap key是否允许重复

不允许,比较hashcode值和equest值

2 hashmap如何避免内存泄漏问题

内存泄漏,key一直占用内存,不被回收 如果使用hashmap,自定义key对象,一定要重写hashcode值和equals。

3 hashmap底层如何实现?

使用entry对象存放健值对

3.1 arraylist

不需要考虑hash膨胀,但是查询很慢

3.2 (jdk1.7)数组+链表

初始化大小是16 同一个链表中存放的都是hashCode值可能相同,但是内容值却不同

3.3 (jdk1.8)数组+链表+红黑树/hash如何解决hash冲突

初始化大小是16(1<<4),当数组容量大于等于64()并且链表长度大于8的时候,就会把链表转红黑树存储(红黑树的个数小于6的时候转为链表),hash碰撞以后,链表长度就回很长。hashmap通过长度n-1 余hash,降低hash冲突。如果hashmap中元素超过阈值的时候会通过0.75扩展因子扩容,

3 hashmap如果key为null

存放在0个位置

4 hashmap1.7与1.8的区别
6 hashmap与hashtable区别
  • hashmap
    • 线程不安全
    • 允许存放key为null
  • hashtable
    • 默认11
    • 线程安全(synchronized)
    • 不允许存放key为null
7 hashmap与treeMap区别
  • hashmap
    • 无序
  • treeMap
    • 有序
8 concurrentHashmap
  • 线程安全
    • 分段锁(node+cas+synchronized)[1.8]
    • 分段锁(ReentrantLock)[1.7]
三 set
1 hashset底层实现原理

对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-12-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java基础面试题
    • 一: Java基础
      • 二: 多线程
        • 三: 集合框架
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档