java面试必会的常规操作一

面向对象的三个基本特征
封装、继承和多态
封装:隐藏部分对象的属性和实现细节,对数据的访问只能通过外公开的接口。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分
继承:让某个类型的对象获得另一个类型的对象的属性的方法。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
多态:对于同一个行为,不同的子类对象具有不同的表现形式。多态存在的3个条件:1)继承;2)重写;3)父类引用指向子类对象。
访问修饰符public,private,protected,以及不写时的区别
在这里插入图片描述


// 报错int类型转换成short
short s1 = 1; s1 = s1 + 1;
// 成功执行
short s1 = 1; s1 += 1;

public static void main(String[] args) {
    Integer a = 128, b = 128, c = 127, d = 127;
    System.out.println(a == b);//false 执行 Integer a = 128,相当于执行:Integer a = //Integer.valueOf(128),基本类型自动转换为包装类的过程称为自动装箱(autoboxing)
    System.out.println(c == d);//true
    }
    
public static Integer valueOf(int i) {  //自动装箱的代码IntegerCache 默认情况下范围为:-128~127。
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);

用最有效率的方法计算2乘以8
2 << 3。

Java 中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(reference type)。

基本数据类型:数据直接存储在栈上
静态变量static 存放在方法区
引用数据类型区别:数据存储在堆上,栈上只存储引用地址
String 类不能被继承

String和StringBuilder、StringBuffer的区别
String:String 的值被创建后不能修改,任何对 String 的修改都会引发新的 String 对象的生成。

StringBuffer:跟 String 类似,但是值可以被修改,使用 synchronized 来保证线程安全。

StringBuilder:StringBuffer 的非线程安全版本,没有使用 synchronized,具有更高的性能,推荐优先使用。
String s = new String(“xyz”) 创建了几个字符串对象
一个或两个。如果字符串常量池已经有“xyz”,则是一个;否则,两个。
String s = “xyz” 和 String s = new String(“xyz”) 两个语句都会先去字符串常量池中检查是否已经存在 “xyz”,如果有则直接使用,如果没有则会在常量池中创建 “xyz” 对象。

另外,String s = new String(“xyz”) 还会通过 new String() 在堆里创建一个内容与 “xyz” 相同的对象实例。

所以前者其实理解为被后者的所包含。
两个对象的 hashCode() 相同,则 equals() bu一定为 true
当有 a.equals(b) = = true 时, 则 a.hashCode() == b.hashCode() 必然成立,

反过来,当 a.hashCode() == b.hashCode() 时,a.equals(b) 不一定为 true。

浅拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:只是复制了对象的引用地址,新旧对象指向同一个内存地址,修改其中一个对象的值,另一个对象的值随之改变

深拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:开辟新的内存空间,在新的内存空间里复制一个一模一样的对象,新老对象不共享内存,修改其中一个对象的值,不会影响另一个对象

并发:两个或多个事件在同一时间间隔发生。(在干一个活另一个活来了你去干那个完事干这个)

并行:两个或者多个事件在同一时刻发生。 (多个活一起干)

构造器Constructor 不能被 override(重写),但是可以 overload(重载)

当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递
值传递。Java 中只有值传递,对于对象参数,值的内容是对象的引用。
重载:一个类中有多个同名的方法,但是具有有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)。

重写:发生在子类与父类之间,子类对父类的方法进行重写,参数都不能改变,返回值类型无要求,但是必须是父类返回值的派生类。
阐述 final、finally、finalize 的区别
final:修饰类 不能被继承 修饰方法不被重写 修饰变量 不能变值
finally:try catch 里面那个(try、catch。finally 的基础用法,在try或者catch中若有 return 前会先执行 finally 语句块,再输出 return 的。)
finalize:Object 中的方法,在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

public class TryDemo {
    public static void main(String[] args) {
        System.out.println(test1());
    }
    public static int test1() {
        int i = 0;
        try {
            i = 2;
            return i;
        } finally {
            i = 3;
        }
    }
}

输出2
根本原因是,在执行 finally 之前,JVM 会先将 i 的结果暂存起来,然后 finally 执行完毕后,会返回之前暂存的结果,而不是返回 i,所以即使这边 i 已经被修改为 3,最终返回的还是之前暂存起来的结果 2。
List、Set、Map三者的区别?

List(对付顺序的好帮手)存储一组不唯一(可以有多个元素引用相同的对象)、有序的对象。
Set(注重独一无二的性质)
Map(用Key来搜索的专业户): 使用键值对存储
ArrayList 和 Vector 的区别
唯一的区别是 Vector 在方法上使用了 synchronized 来保证线程安全
Java 内存结构
程序计数器:线程私有。一块较小的内存空间,可以看作当前线程所执行的字节码的行号指示器。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空。

Java虚拟机栈:线程私有。它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

本地方法栈:线程私有。本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。

Java堆:线程共享。对大多数应用来说,Java堆是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

方法区:与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息(构造方法、接口定义)、常量、静态变量、即时编译器编译后的代码(字节码)等数据。方法区是JVM规范中定义的一个概念,具体放在哪里,不同的实现可以放在不同的地方。

运行时常量池:运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

什么是双亲委派模型
收到请求–让父类去加载–每一层都是直达顶层–如果父类加载不了自己在加载
扩中说明版:
类加载器收到了类加载的请求,不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
类加载的过程
类加载的过程包括:加载、验证、准备、解析、初始化,其中验证、准备、解析统称为连接。
加载:内存生成对象
通过一个类的全限定名来获取定义此类的二进制字节流,在内存中生成一个代表这个类的java.lang.Class对象。
验证:保护安全
确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
准备:分内存搞初值
为静态变量分配内存并设置静态变量初始值,这里所说的初始值“通常情况”下是数据类型的零值。
解析:将常量池内的符号引用替换为直接引用。
初始化:到了初始化阶段,才真正开始执行类中定义的 Java 初始化程序代码。主要是静态变量赋值动作和静态语句块(static{})中的语句。
————————————————

补充关于线程部分:

wait() 和 sleep() 方法的区别

  1. 来源不同:sleep() 来自 Thread 类,wait() 来自 Object 类。
  2. 对于同步锁的影响不同:sleep() sleep 是不会让线程释放同步锁的。wait() 会释放同步锁,让其他线程 进入 synchronized 代码块执行。
  3. 使用范围不同:sleep() 可以在任何地方使用。wait() 只能在同步控制方法或者同步控制块里面使用,否则会抛 IllegalMonitorStateException。
  4. 恢复方式不同:两者会暂停当前线程,但是在恢复上不太一样。sleep() 在时间到了之后会重新恢复;wait() 则需要其他线程调用同一对象的 notify()/nofityAll() 才能重新恢复。
    线程的 sleep() 方法和 yield() 方法有什么区别?
    线程执行 sleep() 方法后进入超时等待(TIMED_WAITING)状态,而执行 yield() 方法后进入就绪(READY)状态。

sleep() 方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程运行的机会;yield() 方法只会给相同优先级或更高优先级的线程以运行的机会。
线程的 join() 方法是干啥
用于等待当前线程终止。如果一个线程A执行了 threadB.join() 语句,其含义是:当前线程A等待 threadB 线程终止之后才从 threadB.join() 返回继续往下执行自己的代码
编写多线程程序有几种实现方式
通常来说,可以认为有三种方式:1)继承 Thread 类;2)实现 Runnable 接口;3)实现 Callable 接口。

其中,Thread 其实也是实现了 Runable 接口。Runnable 和 Callable 的主要区别在于是否有返回值。
Thread 调用 start() 方法和调用 run() 方法的区别
run():普通的方法调用,在主线程中执行,不会新建一个线程来执行。

start():新启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到 CPU 时间片,就开始执行 run() 方法。

补充关于锁部分:

synchronized 和 Lock 的区别

  1. Lock 是一个接口;synchronized 是 Java 中的关键字
  2. Lock 在发生异常时,如果没有主动通过 unLock() 去释放锁,很可能会造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁;synchronized 不需要手动获取锁和释放锁,在发生异常时,会自动释放锁,因此不会导致死锁现象发生;
  3. Lock 的使用更加灵活,可以有响应中断、有超时时间等;而 synchronized 却不行,使用 synchronized 时,等待的线程会一直等待下去,直到获取到锁;
  4. 在性能上,没差别。但推荐尽量使用 synchronized,除非 synchronized 无法满足需求时,则可以使用 Lock

synchronized 各种加锁场景的作用范围
死锁必要条件

1.互斥条件:一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
2. 请求和保持条件:进程已经获得了至少一个资源,但又对其他资源发出请求,而该资源已被其他进程占有,此时该进程的请求被阻塞,但又对自己获得的资源保持不放。
3. 不可剥夺条件:进程已获得的资源在未使用完毕之前,不可被其他进程强行剥夺,只能由自己释放。
4. 环路等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, …, pn},其中 Pi 等待的资源被 P(i+1) 占有(i=0, 1, …, n-1),Pn 等待的资源被 P0占 有,如下图所示。
在这里插入图片描述
如何预防:
打破四个必要条件中的任意一个即可
打破互斥条件:在系统里取消互斥。资源不被一个进程独占使用
打破请求和保持条件:1)采用资源预先分配策略,即进程运行前申请全部资源,满足则运行,不然就等待。 2)每个进程提出新的资源申请前,必须先释放它先前所占有的资源。
打破不可剥夺条件:当进程占有某些资源后又进一步申请其他资源而无法满足,则该进程必须释放它原来占有的资源。
打破环路等待条件:实现资源有序分配策略,将系统的所有资源统一编号,所有进程只能采用按序号递增的形式申请

垃圾回收部分:

介绍下垃圾收集机制
在触发GC的时候,具体如下,这里只说常见的 Young GC 和 Full GC。

触发Young GC:当新生代中的 Eden(伊甸) 区没有足够空间进行分配时会触发Young GC。

触发Full GC:

当准备要触发一次Young GC时,如果发现统计数据说之前Young GC的平均晋升大小比目前老年代剩余的空间大,则不会触发Young GC而是转为触发Full GC。(通常情况)
如果有永久代的话,在永久代需要分配空间但已经没有足够空间时,也要触发一次Full GC。
System.gc()默认也是触发Full GC。
heap dump带GC默认也是触发Full GC。
CMS GC时出现Concurrent Mode Failure会导致一次Full GC的产生。
对什么?

对那些JVM认为已经“死掉”的对象。即从GC Root开始搜索,搜索不到的,并且经过一次筛选标记没有复活的对象。

做了什么?

对这些JVM认为已经“死掉”的对象进行垃圾收集,新生代使用复制算法,老年代使用标记-清除和标记-整理算法。
GC Root有哪些
在Java语言中,可作为GC Roots的对象包括下面几种:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  • 方法区中类静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象

垃圾收集有哪些算法,各自的特点

标记 - 清除算法

首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它的主要不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

复制算法

为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半。

标记 - 整理算法

复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。

根据老年代的特点,有人提出了另外一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

分代收集算法

当前商业虚拟机的垃圾收集都采用“分代收集”(Generational Collection)算法,这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。

一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记—清理或者标记—整理算法来进行回收。

原文链接:https://blog.csdn.net/v123411739/article/details/115364158

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值