java面试题

1、面向对象

什么是面向对象:封装、继承、多态
封装:内部细节对外部调用透明。外部只需调用,无需关注内部细节。常用的是:javaBean和orm框架(mybatis)
内部逻辑由javaBean本身决定,而不能被外部直接修改

private String name;

public String setName(String name){
	this.name = "ljs"+name;
}

继承:一个子类extend父类。继承基类的方法。做出自己的改变或扩展。
共性东西抽取放于父类。个性东西放于子类。。。这样子类就不需要重新定义共性的东西。直接使用父类定义好的。

多态:父类引用指向子类对象。

父类 父类引用 = new 子类();1
父类引用.方法();2

这里的调用方法其实是调用了子类的方法,如果有多个子类,则只换1的代码部分。2及以下的代码不用更换。更利于程序的维护和拓展

弊端:子类必须重写父类的方法。否则父类引用.方法()是调用不了子类特有的方法

2、jdk、jre、jvm三者区别于联系

jdk:java开发工具
jre:java运行时环境
jvm:java虚拟机

jdk包含jre,jre里bin文件就是jvm。lib文件为类库

jvm工作原理:
.java文件->.class文件->jvm->系统映射

3、==与equals的区别

==对比的是栈中的值。基本数据类型对比的是变量值、引用数据类型对比内存地址
equals在object中与 ==是一致的,除非重写了equals方法

String重写了equals方法。其实就是对比字符串的内容

String str1 = "hello";
String str2 = new String("hello");
String str3 = str2

str1 == str2 false;
str1 == str3 false;
str2 == str3 true
str1.equals(str2)  true
str2.equals(str3) true
str1.equals(str3) true

4、final

1、简述fianl的作用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、为什么局部的内部类或匿名内部类。只能访问局部final变量?
在这里插入图片描述

局部内部类
在这里插入图片描述

5、String、StringBuilder、StringBuffer的区别?

String是由final修饰。是不可变的。每次操作产生新的对象。
StringBuilder和StringBuffer都是在原对象基础上操作的。
StringBuilder线程不安全,StringBuffer线程安全。
StringBuffer的方法都有synchronized修饰的
性能上StringBuilder>StringBuffer>String

对于修改字符串内容,需要使用StringBuilder或StringBuffer。
优先使用StringBuidler,对线程安全要求的使用StringBuffer

6、重载和重写的区别?

重载:发生在同一个类中,方法名必须相同,参数类型不同,个数不同,顺序不同,方法返回值和访问修饰符可以不同,发生在编译时

重写:发生在父子类中,方法名,参数列表必须相同。返回值范围小于等于父类,抛出的异常范围小于等于父类。访问修饰符范围大于等于父类。如果父类访问修饰符为private则不可以被重写。

7、接口和抽象类的区别?

1、抽象类可以有抽象方法和普通方法。接口方法只能是public abstract(公共抽象的)

2、抽象类只能单继承。接口可以多实现

3、抽象类的成员变量可以为各种类型。接口的只能是 public static final类型

进阶:1、接口是用于约束类的行为。不管你如何实现
抽象类不是约束类的行为,只是代码复用。
2、从设计角度来说,定义抽象类,功能远超接口,它既有实现方法也有未实现方法。抽象类每个类只能继承一个。维护成本高
接口相反。

8、list和set的区别?

list是有序集合。元素可重复。按对象进入顺序保存对象。可以允许重复多个Null元素。可以迭代器取出元素。也可以get(int index)下标取出元素。

set无序集合,元素不可重复,只允许一个Null元素,只能用迭代器取出元素

9、hashcode和equals?

hascode是获取对象的哈希值
equals相当于重写方法规则,如无重写,则等同于Object的==,基本数据类型比较栈中变量的值。引用数据类型看内存地址。
hashSet如何检查重复元素?
hashSet会调用hashCode()方法计算出对象在散列表的位置。看该位置是否有值,如果有值才调用equals方法。如果equals方法相同,则不允许插入该元素。如果该位置无值,则散列到其他位置插入该元素。大大减少了equals的次数。提高效率。

如果两个对象相等,则hashcode一定相等
hascode相同,equals不一定相同
两个对象相等,那么互相调用equals方法一定返回true
hashcode是堆上默认产生的独特值,如果未重写hashcode方法。则该class的两个对象一定不相等,因内存地址不一样

10、arrayList和linkedList的区别?

arrayList是一个动态数组,需要申请一块连续的内存空间。适合下标访问,具备扩容机制,由于数组长度固定,超过长度会自己新建数组,把老数组数据移到新数组,并回收掉老数组。适合查询。###arrayList可以使用尾插法+指定初始容量,性能会超过LinkedList插入。
linkedList基于链表,随机分散在内存中存储。删除,插入,修改都很快。

linkedList不适合使用for循环去遍历。性能消耗大

linkedList不适合用indexOf方法返回下标。性能消耗大

11、hashmap和hashTable

1、hashmap是线程不安全的,它底层所有方法没有用synchronize修饰
hashTable是线程安全的,它底层所有方法有用synchronize修饰

2、hashmap允许key和value为null
hashTable不允许

##hashmap底层是数组+链表+红黑树。
jdk1.8时候,当链表高度达到8,数组长度超过64.则转为红黑树结构

hashmap底层原理:
1、在进行存储时,计算key的hash值,二次hash对数组长度进行取模。对应到数组下标。
2、没有产生hash冲突(数组下标无元素),则创建node存入数组。
3、如果产生hash冲突。则调用equals方法判断,如果相等,则替代该元素。如果不等,则转化为链表结构。插入链表。。当链表高度达到8,数组长度超过64.则转为红黑树。当链表高度减为6,则红黑树退化为链表

12、concurrentHashMap原理,和它在jdk7,jdk8的区别?

jdk1.7:ReentranLock+segment+HashEntry
1个segment包含一个HashEntry数组。每个hashEntry是一个链表结构
元素查询方式:两次hash。第一次hash定位到segment,第二次hash定位到元素所在链表的头部
get方法无需加锁。volatile保证变量的可见性

jdk1.8:synchronized+CAS+node+红黑树
查询赋值替换都用CAS,当CAS(乐观锁)保证不了线程安全时,会使用synchronized。这样导致锁粒度更细。效率更优。锁的是链表的header。

13、如何实现一个ioc容器?

1、配置文件配置包扫描路径
2、递归包扫描获取.class文件
3、反射需要交给ioc管理的类
4、对需要注入的类进行依赖注入

14、什么是字节码文件?好处是?

.class文件就是字节码文件
java源代码->编译器->字节码->jvm->jvm解释器->机器可执行的二进制机器码->程序运行
好处:java语言通过字节码的方式,在一定程度上解决了传统解释性语言效率低的问题。同时又保留了解释性语言可移植的特点。无需编译处处运行。

15、java类加载器有哪些?

jdk自带的三个类加载器:bootstrapClassLoader ExtClassLoader AppClassLoader

bootstrapClassLoader是ExtClassLoader的父类加载器。默认负责加载%JAVA_HOME%lib下的jar包和class文件
ExtClassLoader是AppClassLoader的父类加载器。负责加载%JAVA_HOME%/lib/ext文件下的jar包和class文件
AppClassLoader是自定义加载器父类。负责加载classPath下类文件。也是系统类加载器和线程上下文加载器。

16、双亲委派机制

jdk中有三个类加载器。
bootstrapClassLoader是ExtClassLoader的父类加载器。默认负责加载%JAVA_HOME%lib下的jar包和class文件
ExtClassLoader是AppClassLoader的父类加载器。负责加载%JAVA_HOME%/lib/ext文件下的jar包和class文件
AppClassLoader是自定义加载器父类。负责加载classPath下类文件。也是系统类加载器和线程上下文加载器。
双亲委派就是:向上委派,查找缓存,在向上过程中,如果类加载器在缓存中找到了。就不用加载了。直接返回。如果查找缓存找不到,则向下查找类加载路径。查找到了返回类。最终查找不到返回找不到类
在这里插入图片描述

17、java中异常体系

java中所有的异常来自于Throwable顶级父类
Throwable有两个子类:Error和Exception
Error是程序无法处理的错误。一旦发生,系统停止执行
Exception是程序可以处理的错误。程序不会终止。程序员可以干预。又分为:RuntimeException和CheckedException。
RuntimeExcetion称为运行时异常。只会导致当前线程异常,可以通过try catch干预。
CheckedException称为检查异常。通常是编译时异常

18、GC如何判断对象是可以回收

引用计数器:java中每个对象有一个引用计数器。被引用一次+1,释放引用-1.当引用为0时被回收。
java不是用的这种方式回收对象
因为引用计数法会存在循环依赖,无法解决的难题。

所以java中采取可达性分析法:从GC Roots对象开始向下搜索,搜索所走过的路径称为调用链。当一个对象到GC Roots对象没有任何调用链时。证明对象不可用,可以被回收

GC Roots对象有:虚拟机栈引用对象、方法区静态属性引用对象、方法区常量引用对象、本地方法栈中JNI(Native方法)

可达性分析的不可达对象不会立即被回收。会进行二次可达性分析。第一次,可达性分析发现不可达对象。第二次,执行对象的finalize方法。如果无此方法,被覆盖了。则直接被回收。如可以执行。则看此方法中,有无创建新对象。如无则被回收。每个对象finalize方法只能执行一次

19、线程的生命周期,哪些状态

创建、就绪、运行、阻塞、死亡
阻塞分为三种情况:
等待阻塞:线程调用了wait()方法后,线程进入等待池中。是不能被唤醒的。除非其他线程调用notify方法
或者notifyAll
同步阻塞:运行的线程获取对象的同步锁时。被其他线程抢了。则该线程被jvm放入锁池中。
其他阻塞:线程发起sleep、join、io请求时会引起阻塞。当sleep超时,join执行完毕,io执行完毕时。线程重新转为就绪状态

1、新建状态:创建了一个线程对象
2、就绪状态:调用了该线程的start方法。等待cpu分配资源
3、运行状态:获取到了cpu资源。执行程序代码
4、阻塞状态:因为某种原因放弃了对cpu的使用权。直到线程进入就绪状态
5、死亡状态:线程因为异常或者退出了Run方法,线程生命周期结束

20、sleep、wait、join、yield

sleep与wait的区别
1、sleep是thread本地方法。wait是object的本地方法
2、sleep方法不会释放锁。wait会,把线程加入等待序列中
3、sleep方法不依赖于synchronized,但是wait依赖
4、sleep不需要被唤醒,但是wait需要
5、sleep用于当前线程休眠,wait用于多线程之间通信
6、sleep会让出cpu执行时间,且强制上下文交换。但wait不一定,会重新竞争到锁再执行的

yield执行后线程直接进入就绪状态,马上释放cpu执行权,但是保留了cpu执行资格。让其他线程来抢,如果抢不到,有可能还是它继续执行

join执行后线程进入阻塞状态,如果在线程B中调用A的join方法,则B阻塞,直到线程A执行完毕

21、对线程安全的理解

线程安全指的就是内存安全。堆是共享内存可以被所有线程访问
当多个线程访问一个对象。不做任何控制的时候。返回的预期结果跟单线程时访问的一样。就可以认定为线程安全

###堆和栈的概念
堆:进程和线程的共有空间,分为全局堆和局部堆。全局堆就是没有分配的空间。局部堆是分配给用户的空间,堆在操作系统对进程初始化的时候进行分配。用完还给操作系统,否则内存泄漏

栈:每个线程独有的,保存运行状态和局部变量的,在线程开始的时候初始化,不存在线程安全问题

操作堆时有线程安全问题

22、thread和Runnable区别

thread是类。runnable是接口。thread实现了Runnable

这是因为两个实例。就应该卖出两倍。与线程安全没太大关系
有复杂线程需求用thread。简单需求用runnable

23、什么是守护线程

java中有两种线程:守护线程(后台线程)和非守护线程(用户线程)
守护线程相当于所有非守护线程的保姆。但是程序终止时理都不理它直接终止掉它。他也不太靠谱。不该将File或者io操作设置为守护线程

比如垃圾回收机制就是守护线程
守护线程用于:1、支持其他线程 2、在任何情况下程序关闭,守护线程应当立即关闭

thread.setDeamon(true)可以将线程设置为守护线程,但必须在thread.start之前设置,否则抛异常。
守护线程中新创建的子线程自己默认就是守护线程。
线程池中ExecutorService使用会将守护线程自动转化为用户线程

24、threadLocal原理和使用场景

threadLocal对象:每一个thread对象都有一个threadLocalMap类型的成员变量threadlocals
它存储本线程所有threadlocal对象及其对应的值

set方法就是threadLocal首先会获取当前线程对象,然后会获取当前线程的ThreadLocalMap对象。再以当前的threadLocal对象为key。set value到ThreadLocalMap中

get方法类似。

使用场景:1、在进行对象跨层传递时,使用threadLocal可以避免多次传递,打破层次间约束。
2、线程间数据隔离
3、进行事务操作,用于存储线程事务信息。
4、数据库连接,session会话管理

25、threadLocal内存泄漏原因如何避免

threadLocal占用了内存,因为各种原因无法回收,这种叫做内存泄漏
每一个thread维护一个threadLocalMap,key为弱引用的ThreadLocal实例。value为线程变量的副本。
因为每次jc,必定回收弱引用对象。形成一个红色调用链。
如果key为强引用对象。可能会导致无法回收。
如果key为弱引用。只需调用一下ThreadLocalMap的set,get或者remove方法即可回收这个对象。

threadLocal的正确使用方法:
1、每次使用完threadLocal需要调用remove方法
2、将threadLocal变量定义成private static,这样就一直存在threadLocal的强引用。也就能保证任何时候threadLocal的弱引用能访问到Entry的key值。从而清除掉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值