java面试题2023最新

java的跨平台

概念:java编写的程序一次编译后,可以在运行在任何操作系统上
在这里插入图片描述

原理:java的跨平台关键是借助jvm,JVM是一个”桥梁“,不同的平台对应不同的jvm(如Windows,linxu,mac),java程序被javac编译生成.class文件,.class文件再被jvm翻译成当前所在平台能够识别的机器码文件,所以,对于程序员来说,只需要完成编码,就能过进行跨平台了

jvm,jre,jdk

jvm:java virtual mechine,java虚拟机,java程序运行在jvm上,不同平台有不同的jvm,jvm是实现java跨平台的关键
jre:java runtime evironment java运行时环境,主要包含java.lang,包装类,日期类等核心类库,如果是运行开发并编译好的java程序只需要jre便可
jdk:java development kit 提供给java开发人员使用的,包含了jre,安装了jdk就不需要考虑安装jre和jvm了,jdk中含有很多重要开发工具如javac.exe用于编译 jar.exe用于打包
在这里插入图片描述

6 java是强语言,基本数据类型如下

  • 整数型:int short long byte
  • 浮点型:float double
  • 字符型:char
  • 布尔型:boolean
  • 引用数据型:类(String,包装类,工具类,自定义类) 接口 数组
    在这里插入图片描述
    switch中只能是整形

7 计算2*8最有效的方法
2 <<< 3 :相当于2乘2的三次方,同理2>>>3相当于2除以2的三次方

8 Math.round(11.5) 等于多少?Math.round(-11.5)等于多少
这是个四舍五入方法,前者是12,后者是-11

9 float f=3.4;是否正确
不正确,3.4代表双精度类型,将3.4赋值给f相当于向下转型会损失掉精度,应该写成

float f = (fliat)3.4;    
float f = 3.4F;

10 short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗
对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。

而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。

10 java编码
采用Unicode编码,为没一个字符指定单独的数组,任何程序,语言,平台都可以使用

11 访问修饰符
public:任何类都能访问
protected:子类和同一包下可以访问
default:同一包才能访问
private:只能在本类访问
注意:public和defalut也能修饰外部类,protected的private不能修饰外部类,四种修饰符都能修饰内部类,内部类可以看出方法
在这里插入图片描述

&和&&(|和||)的区别

都表示逻辑与的区别,但&&无论
&运算符有两种用法:(1)按位与;(2)逻辑与。

&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。&&之所以称为短路运算,是因为如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。

注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。

13 fianl的作用

  • 修饰类,表示这个类是最终类不能被继承
  • 修饰类,表示最终方法,不能被重写
  • 修饰变量,表示是最终变量,被fianl修饰的常量如果是基本数据,那么就表示一个常量(常量最好大写),如果被修饰的是一个引用类型,那就表示该引用类型的指向是不能变的,但是引用所指向的对象的堆空间是能够通过getter/setter发送变化的
  • 注意:①不能和abstract修饰抽象类和抽象方法共存②final修饰的变量必须初始化且只能初始化一次

14 fianl与String的搭配,先看题目

public class Main {
   public static void main(String[] args) {
       String a = "wzh2";
       final String b = "wzh";
       String d = "wzh";
       String c = b + 2;
       String e = d + 2;
       System.out.println((a == c));
       System.out.println((a == e));
   }
}

这段代码的输出结果是什么呢?
答案是: true 和 false

1、变量a指的是字符串常量池中的 wzh2;
2、变量 b 是 final 修饰的,变量 b 的值在编译时候就已经确定了它的确定值,换句话说就是提前知道了变量 b 的内容到底是个啥,相当于一个编译期常量;
3、变量 c 是 b + 2得到的,由于 b 是一个常量,所以在使用 b 的时候直接相当于使用 b 的原始值(wzh)来进行计算,所以 c 生成的也是一个常量,a 是常量,c 也是常量,都是 wzh2 ,而 Java 中常量池中只生成唯一的一个 wzh2 字符串,所以 a 和 c 是相等的!
4、d 是指向常量池中 wzh,但由于 d 不是 final 修饰,也就是说在使用 d 的时候不会提前知道 d 的值是什么,所以在计算 e 的时候就不一样了,e的话由于使用的是 d 的引用计算,变量d的访问却需要在运行时通过链接来进行,所以这种计算会在堆上生成wzh2 ,所以最终 e 指向的是堆上的 wzh2 , 所以 a 和 e 不相等。
总结:a、c是常量池的wzh2,e是堆上的wzh2

15 final finally finalize区别

  • final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
  • finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
  • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的最后判断。

16 this和super
this关键字用法,this代表当前对象的引用,是一个指针

  • 构造器中用于区分形参和属性,尤其是形参和引用重名,属性被形参屏蔽的时候,的情况必须使用this
  • this在方法中可以调用当前类的属性和方法,能省就省,那个对象调用的方法或属性,this就代表哪个对象
  • this可以在当前类的构造函数数调用本类其它的构造函数,如果是调用本类无参构造函数可以省略,调用有参函数就不能省略
  • this可以调用静态属性和方法,反之静态方法或静态域不能出现this

super可以看出是父类(离自己最近的超类)对象的指针

  • 可以用于子类构造器中初始化父类构造器,但必须是在第一行,有两种情况①父类中显示声明无参构造或者父类中没有显示声明任何构造器,那么子类构造器默认第一行就是super();此时整个子类的无参构造器都可以省略②父类中定义了参构造器且没有显示声明无参构造器,那么子类构造器就不能在隐式声明或定义无参构造器,必须通过super(参数)来显示构造带参构造器
  • 如果子类对父类的方法进行了重写,而后又想在本来调用父类的方法,必须用super来引用,否则直接使用重写的方法名调用在子类中默认是调用的子类的重写方法
  • 如果父类和子类中有重名的非private属性,那么就可以通过super来调用到父类的属性
  • 如果一个子类没有继承任何类,super依然是有用的,可以用来调用Object的方法

17谈谈static

  • 修饰内容:static可用用来修饰内部类,变量,方法,代码块
  • 存储位置:静态变量和方法都在JVM方法区
  • 加载时机:static修饰的静态方法和变量在类加载期间就初始化完毕,远远早于对象加载的时间,对象的加载时在类加载完成后进行的,这是为何不能和this共存的原因,但是this可以调用到静态属性和方法,只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行,所以我们通常利用这一个
  • 作用范围:static修饰的静态变量和静态方法被类的实例所共享,他们是属于类的,不属于任何一个实例,可以被类的实例对象this调用,也可以被通过类直接调用
  • 实际应用:①某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量②工具类中的方法通常声明的static,理由是方便调用

18 流程控制语句
break ,continue ,return 的区别及作用

  • break 跳出总上一层循环,不再执行循环(结束当前的循环体)

  • continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件)

  • return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)

面向对象的三大特征

封装

封装其实是对外隐藏复杂细节,提供简单易用的接口,便于外界调用,从而提高系统的可扩展性、复用性、降低耦合,的同时隐藏了实现细节,保障安全性,比如开发中将类属性设为私有private,对外提供getter/setter方法,通过四种权限修饰符

继承

子类可以通过继承一个父类,继承原有的功能(父类的方法和属性),在此基础上扩展自己的新功能(子类的属性和方法、重写父类方法),子类基础父类后,通过super显示或隐式地调用父类的构造器,但这里其实并没有去创造父类的对象,我理解只不过是调用父类构造方法来初始化属性,都子类通过super调用父类,new指令开辟空间,用于存放对象的各个属/性引用等,反编译字节码你会发现只有一个new指令,所以开辟的是一块空间,一块空间就放一个对象。获取到父类信息后即用来解析父类方法啊,属性名称等,解析完后实际变量内容存储在new出来的空间那里,子类无法获取

多态

多态机制就是父类或接口的引用可以指向子类或实现类对象,即父类或接口引用所指向的对象和他们引用所调用的方法在编译期间都无法确定,因为我们通过父类或接口的引用对应n个子类或实现类,同时,通过父类或接口的引用所调用的方法又极可能是子类重写的方法,也就说,编译看左边,看左边父类的类型,运行时看右边,也就是看到的是构造的那个子类对象

  • 多态:多态的实现依靠继承或接口、方法重写、向上转型(父类的引用指向子类),只有满足这三个条件
  • 意义:多态的意义就是屏蔽下面的实现类和子类的差距,写出通用性和扩展性更强的代码,例如模板方法,模板类通常是一个抽象类作为模板类,模板方法作为一个模块框架,模板方法由具体类和抽象类组成,具体类这是公用的固定流程,抽象类则是需要把实现步骤推迟到子类。

20 抽象类 vs 接口
抽象类abstrac是在类的基础上,提取类的公共特征进一步抽象得来的模板,适合做基类BaseClass,主要是为了提高代码的复用性,是一种has a关系
接口是一种规范(但这种规范只是用来规定行为的有无,但不规定行为的实现),表示该类具有什么能力,是一种like a关系

参数抽象类接口
是否多继承一个类最多继承一个抽象类一个类可以实现多个接口
是否有构造器有构造器但无法实例化没有构造器,更无法实例化
内部方法抽象方法与普通方法共存java8前必须全是抽象方法
访问修饰符没有限制必须是public或默认,不允许出现private和protected,接口方法默认是public abstract,接口类默认是public static final,这两个都是可以省略的,jdk8出现public default/default和public static/staic
实现方式通过继承实现,子类对于抽象父类的抽象方法要全部实现,否则子类也要声明为抽象类子类对于接口的抽象方法要全部实现,否则子类也要声明为抽象类
声明方式abstract和extendsinterface和implements

jdk8出现public default/default和public static/staic|大大增强了接口的性能,实际开发我们通过更多使用接口而不是抽象类

21 普通类和抽象类有哪些区别?

  • 普通类不能包含抽象方法,抽象类可以包含抽象方法。
  • 抽象类不能直接实例化,普通类可以直接实例化。

22抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类

23 实例变量、静态变量与局部变量的区别有哪些

参数局部变量实例变量静态变量
jvm中的位置方法区
作用域所在方法或代码块的范围内对象范围内整个类
初始化必须有初始值不必须指定初始值,有默认值不必须指定初始值,有默认值
生命周期所在的类或代码块执行结束就是对象的生命周期就是类的生命周期
修饰符不能使用修饰符除了final能使用任何修饰符不能使用fianl
使用规则就近原则
定义位置方法内定义方法外定义方法外定义
加载时期方法执行时加载到栈中对象初始化时加载到堆中类初始化时加载到方法区
补充:
成员变量包括实例变量和静态变量
  • 静态变量不属于任何实例,被static修饰,可以通过对象名和类名调用,整个类声明周期中只加载一次,被对象所共享
  • 实例变量是属于某个实例对象的,只能通过对象名调用,每次创建对象都会为实例变量在堆中分配特点的空间,类生命周期中创建了每创建一个实例对象都会创建相应的实例变量
    在这里插入图片描述

24 在Java中定义一个不做事且没有参数的构造方法的作用
如果它内部定义了有参构造且没有显示定义无参构造,那么就相当于这个类没有无参构造,作为连带效应它的子类也就没有无参构造,如果此时子类定义了无参构造器或者子类没有显示定义父类构造器那么都无法通过编译,而且子类构造器必须通过带参的super进行显示构造

25 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
子类初始化的首要任务就是通过super先在子类对象所在堆中加载父类对象

26 一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么
构造方法会在初始化对象时自动调用,作用是在对象初始化期间加载对象所具有的属性和方法和子类所继承父类的非private属性和方法,如果是有参构造还会在这一过程为对象的属性赋值,即使没有显示声明任何构造函数该类内部也会有默认的构造器

public class Test{
   pulic test{super()}
}

27 构造函数的特点

  • 名字与类名相同
  • 没有任何返回值类型,修饰符不限
  • 生成类的对象时自动执行,无需调用。

28 什么是内部类?

https://blog.csdn.net/wwwwwww31311/article/details/114895737

重载与重写

重载(overlaod):方法名相同,参数的个数,类型,位置(不同类型的参数顺序变化才叫重载)不同,不考虑访问修饰符和返回值类型
重写(override):重写 要求两同两小一大原则

  • 两同:方法名相同,参数类型相同
  • 两小:子类返回类型小于等于父类方法返回类型, 子类抛出异常小于等于父类方法抛出异常,
  • 一大:访问修饰符权限大于等于父类(如果父类的修饰符是private那么子类就无法重写父类的这个私有方法),抛出异常小于等于父类,返回值类型小于等于父类

向上转型与向下转型

30 == 和equals 的区别是什么

== 是判断两个对象是否为同一个对象,也就是只有两个对象的存储位置(也就是内存地址值)一致才能返回true,如果是比较基本数据类型只要值相等就返回true;
equals分为重写前和重写后两种情况

  • 重写前也就是Object类中的equals和==用法一致
  • 类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等

案例:
String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象值的内容,不必非得地址值相等,当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。

31 什么是hashCode

  • 该方法值java.lang.Object中,意味着任何对象都要哈希值
  • 根据hashCode()获取哈希码,也叫散列吗,使用对象调用该方法返回给对象整形的哈希值
  • 散列表存储的是键值对(key-value)特点,哈希码的作用就是根据key快速在散列表中检索出目标值

32 hasCode()的具体用法
当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与插入位置中的对象hashcode 值作比较,如果该位置没有重复的hashcode,HashSet会假设对象没有重复出现,插入成功。但是该位置如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来判断两个对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,大大提高了执行速度。

33 为什么重写equals时必须重写hashCode方法
因为,hashCode()与equals()的相关规定

如果两个对象调用equals返回true,则hashcode一定也是相同的

两个对象有相同的hashcode值,他们调用equals也不一定相等

因此,equals 方法被覆盖过,则hashCode 方法也必须被覆盖,否则会出现两个对象调用equals相等但hasCode不相等的情况,因为原生hascode的值是和地址相关的,而重写后的equals判断时只看属性值是否相等而不再考虑地址的情况

34 两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
如何同时重写了equals和hasCode或都没有重写,那么两个对象的哈希值相同,equals的值也不一定返回true,但如果两个对象的equals返回true,那么这两个对象的哈希值一定相同

35 HashSet如何检查重复
前言:HashSet是无序但并非随机的,不可重复的(理解为集合)。无序指的是HashSet添加元素的方式不是顺序添加的而是根据添加元素的哈希值来计算该元素在底层map中所在的位置(HashSet的底层其实是HashMap)

36 对象的相等与指向他们的引用相等,两者有什么不同?
对象的相等 比的是内存中存放的内容是否相等而 引用相等 比较的是他们指向的内存地址是否相等。

37 值传递和引用传递的区别

  • 值传递是值方法调用期间,传递的是值的拷贝,传递后就没有关系了,不会影响到实际参数
  • 引用传递是值方法调用期间,把引用中的地址值也就是对象的存储地址传递过去,也就是传值前和传值后的都是指向同一个对象

38 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
答:值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对象实际的引用却不会发生变化

39 为什么 Java 中只有值传递

  • 普通变量的传递是值传递
  • java中没有指针的概念,只有类似于指针的引用概念
  • 当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用的副本,虽然都指向了同一对象,但不是引用本身。对象的属性可以在被引用调用过程中被改变,但引用的改变不会影响到调用者,说白了就是引用只不过是栈上的一个临时存储对象地址值的变量,当方法或代码块结束就会回收这个变量

38 常见的包有哪些

  • java.lang 核心包
  • java.util 这是工具类包
  • java.sql 这是操作sql相关的包
  • java.io 输入流输出流相关的包
  • java.net:网络编程相关的包

39 import java和javax有什么区别
刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来说使用。然而随着时间的推移,javax 逐渐的扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java 包将是太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准API的一部分。

40 java的流如何分类

  • 按照方向可以分为输入流和输出流,分别是读文件和写文件
  • 按类型分为字节流(有InputStream和OutputStream,读写二进制文件)和字符流(传递的是字符,有Reader和Writer,读写文本文件),字符流在操作过程中用到了缓冲区而字节流没有用
  • 按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类。①节点流:可以从或向一个特定的地方读写数据。如FileReader②处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

按操作方式分类结构图:
在这里插入图片描述
按操作对象分类结构图:
在这里插入图片描述
41 Files的常用方法都有哪些?
Files. exists():检测文件路径是否存在。
Files. createFile():创建文件。
Files. createDirectory():创建文件夹。
Files. delete():删除一个文件或目录。
Files. copy():复制文件。
Files. move():移动文件。
Files. size():查看文件个数。
Files. read():读取文件。
Files. write():写入文件。

42 反射的定义
反射在程序运行期间,可以获取类的全部信息,构造任意的对象并通过对象调用到它的属性和方法,这种动态获取类的信息及动态调用对象的功能我们称之为反射,反射是java被成为动态语言的关键。

反射的应用

  • jdbc中sql操作方法和数据库驱动程序的加载
  • spring的ioc的自动装配和aop面向切面思想的实现

43 字符型常量和字符串常量的区别

  • 形式上,前者是单引号,后者是双引号
  • 本质上,前者本质是一个ASCII码,介意参加运算,后者是存储在字符串常量池上的地址值
  • 大小上一个字符串常量代表一个字节,后者代表若干字节,字符串的结尾符’\0’代表一个字节

44 什么是字符串常量池?
字符串常量池位于JVM的在方法区中,为了避免内存利用率,提高程序运行性能,常量池避免创建相同的字符常量,方法是,无论是创建一个字符串变量还是字符串对象,都是先从方法区中进行查找,如果存在则直接返回引用,否则就先创建实例化一个字符串常量放入常量池再返回其引用

45 String 是最基本的数据类型吗
不是,基本数据类型有8种,int short long byte char float double boolean,此外就是引用类型数组[],类,接口,String是类类型的引用数据类型
开发中如果我们需要连续使用字符数组,这样操作很麻烦,String底层就是char[],使用String可以使我们轻松处理字符串

46 String有哪些特征

  • 不可变性,这是由于String底层的使用fianl修饰char[]数据导致的,也就是我们对String对象的任何操作都是开辟一个新的String对象空间,并把之前的引用指向新的对象,所有String是只读对象,典型的immutable类型对象,String不可变性不代表引用也是不可变的,引用可以指向不同的对象,比如
/*
实际上,原来String的内容是不变的,只是str由原来指向"Hello"的
内存地址转为指向"Hello World"的内存地址而已,也就是说多开辟了一
块内存区域给"Hello World"字符串。
*/
String str = "Hello";
str = str + " World";
System.out.println("str=" + str);
  • 常量池化,String创建对象时会首先从JVM的字符串常量池中查找,如果有就返回引用,否则就新建常量池字符串再返回引用,这样避免在常量池中出现重复元素,结束内存提高程序运行效率
  • 不可被继承性,这是因为String类也是被fianl修饰,String是一件被设计很完美的艺术品,但并不结实,所以通过fianl禁止熊孩子去接触它,否则String的安全性,共享性,高效性都会遭到破坏

47 String str="i"与 String str=new String(“i”)一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

48 String s = new String(“xyz”);创建了几个字符串对象
两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象。

49 数组有没有 length()方法?String 有没有 length()方法
数组没有 length()方法 ,有 length 的属性。String 有 length()方法。JavaScript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。

更多String面试题:https://blog.csdn.net/wwwwwww31311/article/details/113482513

50 String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的

  • 前者是不可变的,后两者是可变的
  • StringBuffer效率高但不线程安全,StringBuilder效率低但线程安全
  • 如果要操作少量的数据用 = String,单线程操作字符串缓冲区 下操作大量数据 = StringBuilder 多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

算法设计:统计String各字符出现的次数

创建一个hashmap对象,key位置上存储String中出现的字符,value上维护一个计数器,循环遍历String每一个字符,根据字符从map中取,取不出来就成功put到map中,否则就将响应键值对上的计数器+1

51 自动装箱与拆箱
装箱:将基本类型用它们对应的引用类型包装起来,通过Interger.valueOf(i)
拆箱:将包装类型转换为基本数据类型,通过Interger.inValue(i)

52 int 和 Integer 有什么区别
java是一个纯面向对象语言,但为了编程方便还是引入了8中数据类型,但即便如此他们都对应着各自的包装类,这样在编程时还是会将基本数据类型的变量安装对象类型来处理

53 Integer a= 127 与 Integer b = 127相等吗

  • 由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false
  • 非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为 ①当变量值在-128~127之间时,非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同;②当变量值在-128~127之间时,非new生成Integer变量时,java API中最终会按照new Integer(i)进行处理(参考下面第4条),最终两个Interger的地址同样是不相同的)
Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false
  • 非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为 ①当变量值在-128~127之间时,非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同;②当变量值在-128~127之间时,非new生成Integer变量时,java API中最终会按照new Integer(i)进行处理(参考下面第4条),最终两个Interger的地址同样是不相同的)
Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false
  • 4、对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false

54 面向对象与面向过程
面向对象的核心是高度抽象,将所分析的问题抽象为类,进而实例化出它的对象,建立对象的目的并不是用于解决问题,而是描述次事物在整套解决方案中的实现步骤
面向过程是自顶向下编程,分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了
对比:面向对象性能上弱于面向过程,但是可扩展性和可维护性强于面向过程

55 serialVersionUid作用
XXX类实现了serialable接口后,定义一个serialVersionUid,这样在序列化时(java程序内容写入磁盘)连同erialVersionUid一同写入磁盘,反序列化时从磁盘读出serialVersionUid到java程序,判断读出来的的serialVersionUid和XXX类的serialVersionUid是否一致,一致的话才能成功读取,serialVersionUid的意思在在于实现java对象在java程序和磁盘间的双向传输,即使XXX类发生了变化也能精准的进行反序列化

56 定义一个java.lang.String能否取代jdk8中的
类的分类

  • java自带的核心类库:$JAVA_HOME/jre/lib路径下
  • java扩展类:$JAVA_HOME/jre/lib/ext下
  • 我们自己开发的类或者引用的第三方jar包

类的加载

  • 核心类由BootStrapClassLoader进行加载,此加载器无法获取,由JVM内部实现
  • 扩展类类由ExtClassLoader进行加载
  • 核心类由AppClassLoader进行加载

类加载器使用顺序

  • BootStrapClassLoader > ExtClassLoader > AppClassLoader
  • 上面没有才有下面的,如果上面的加载了就不再加载后面的

双亲委派机制
启动main方法通常使用的是AppClassLoader,它会向上查找缓存,如果向上到了BootStrapClassLoader还没有查找到缓存,那么就向下查找,也就是首先用BootStrapClassLoader加载核心类,然后用Ext加载扩展类,最后使用AppClassLoader加载自定义类即第三方jar包,如果还没找到就要报ClassNotFountException异常了,这样目的首先是①保证安全性,举个反例,没有类加载机制,那么我们自己定义一个java.lang.String就很容易替换jdk8中的核心类②避免了类的重复加载

57 自动装箱与拆箱

// 装箱:把基本类型的数据,包装到包装类中(基本类型的数据->包装类)
// 在包装类中取出基本类型的数据(包装类->基本类型的数据)
public class Test {

    public static void main(String[] args) {
        int a = 1;String b = "2";
        //装箱
        Integer integer = new Integer(a);
        Integer integer2 = new Integer(b);
        Integer integer3 = Integer.valueOf(a);
        Integer integer4 = Integer.valueOf(b);
        //拆箱
        int int1 = integer.intValue();
        //自动装箱
        Integer integer5 = 5;
        //自动拆箱
        int sum = integer5 + 1;
    }
}

58 五种IO模型

  • 阻塞型BIO:在系统内核加载完成之前套接字一直等待,无法进行其它操作,例如socket中accept、读方法(read必须等待write结束才能执行)write方法就是阻塞型io,就好像专心钓鱼等鱼上钩一样
  • 非阻塞型NIO:每次客户询问服务器端是否已加载好,如果加载好就正常处理请求,否则就回复客户端还没加载好,用户会在下一阶段再次轮询请,B不想将自己的所有时间都花费在钓鱼上,在等鱼上钩这个时间段中做了些其他的事情,但B每隔一个固定的时间检查鱼是否上钩。一旦检查到有鱼上钩,就停下手中的事情,把鱼钓上来。
  • 信号驱动io:C比较聪明,他给鱼竿上挂一个铃铛,当有鱼上钩的时候,这个铃铛就会被碰响,C就会将鱼钓上来。应用进程告诉内核,当你加载成功后给我发个信号,我会调用我的信号处理函数接收你的报文信息,然后进行请求发送
  • IO多路转接(I/O multiplexing),D拿了很多的鱼竿,一次性有很多鱼竿在等,D不断的查看每个鱼竿是否有鱼上钩。增加了效率,减少了等待的时间;本身是一个阻塞型io,区别是它内部有一个select函数,对文件扫描符进行循环监听
  • 异步非阻塞io,E也想钓鱼,但E有事情,于是他雇来了F,让F帮他等待鱼上钩,一旦有鱼上钩,F就打电话给E,E就会将鱼钓上去。当应用程序调用aio_read时,内核一方面加载响应数据,另一方面回复客户端将控制权交给应用进程,也就是nio的形式,客户端获得了控制权可以腾出手去做别的,而内核数据加载完毕再回复给应用进程即可

阻塞程度:阻塞IO>非阻塞IO>多路转接IO>信号驱动IO>异步IO,效率是由低到高的。

59 内存泄露(Memory Leak):
是指一个不再被使用的对象或者变量还在内存中占有存储空间,在C/C++语言中,内存泄露出现在开发人员忘记释放已分配的内存就会造成内存泄露。在java语言中引入垃圾回收机制,有GC负责进行回收不再使用的对象,释放内存。但是还是会存在内存泄露的问题。例如访问资源文件,流不关闭,访问数据库等连接不关闭,将对象的引用存储到了全局(静态)map中…

60 OOM

GC如何判断对象被回收
可达性分析:从GCRoot开始详细搜索,走过的路径称为引用链,当一个对象到GCroot没有任何引用链相连时证明这个对象是不可用的,例如a依赖于b,b依赖于c,当a与b的依赖关系断裂时,GC会将b联通c一起回收,GCRoot引用对象所在区域有

  • 虚拟机栈中
  • 堆中
  • 方法区中(静态区和常量区)
  • 本地方法区中

补充:GCRoot不可达并不会立刻回收这个对象,而是先看这个对象是否重写finalize(),没有重写则立刻移除,否则继续

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值