1、解释下什么是面向对象?面向对象和面向过程的区别?

面向对象是⼀种基于面向过程的编程思想,是向现实世界模型的自然延伸,这是⼀种“万物皆对象”的编程思想。由执行者变为指挥者,在现实生活中的任何物体都可以归为⼀类事物,而每⼀个个体都是⼀类事物的实例。面向对象的编程是以对象为中心,以消息为驱动。
区别:

  • 面向过程更注重事情的每一个步骤及顺序
  • 面向对象更注重事情有哪些参与者(对象)、及各自需要什么

比如洗衣机洗衣服:
面向过程:会将任务拆解成一系列的步骤:打开洗衣机——->放衣服——->放洗衣粉——->清洗——->烘干
面向对象:会拆出人和洗衣机两个对象:

  • 人:打开洗衣机 放衣服 放洗衣粉
  • 洗衣机:清洗 烘干
  1. 封装:封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,内部细节对外部调用透明,外部调用无需修改或者关心内部实现。
  2. 继承:继承基类的方法,并做出自己的改变和/或扩展,子类共性的方法或者属性直接使用父类的,而不需要自己再定义,只需扩展自己个性化的。
  3. 多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。

    2、面向对象的三大特性?分别解释下?

  4. 封装:通常认为封装是把数据和操作数据的方法封装起来,对数据的访问只能通过已定义的接口。也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

  5. 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类/基类)得到继承信息的被称为子类(派生类)。 它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”
  6. 多态:分为编译时多态(方法重载)和运行时多态(方法重写)。要实现多态需要做两件事:⼀是子类继承父类并重写父类中的方法,二是用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为。

几点补充

  1. 子类拥有父类对象所有的属性和方法(包括私有属性和私有⽅法),但是父类中的私有属性和方法子类是无法访问,只是拥有。因为在⼀个子类被创建的时候,首先会在内存中创建⼀个父类对象,然后在父类对象外部放上子类独有的属性,两者合起来形成⼀个子类的对象;
  2. 子类可以拥有自己的属性和方法;
  3. 子类可以用自己的方式实现父类的方法。(重写)

    3、JDK、JRE、JVM 三者之间的关系?

  • JDK:是 Java 开发工具包,是整个 Java 的核心,包括了 Java 运行环境 JRE、Java 工具 和 Java 基础类库。
  • JRE:是 Java 的运行环境,包含 JVM 标准实现及 Java 核心类库。
  • JVM:是 Java 虚拟机,是整个 Java 实现跨平台的最核心的部分,能够运行以 Java 语言写作的软件程序。所有的 Java 程序会首先被编译为 .class 的类文件,这种类文件可以在虚拟机上执行。

Snipaste_2021-12-22_09-45-27.png

4、重载和重写的区别?

  1. 重载:「编译时多态」、同⼀个类中同名的方法具有不同的参数列表、不能根据返回类型进行区分
    1. 【因为:函数调用时不能指定类型信息,编译器不知道你要调哪个函数】;
  2. 重写(⼜名覆盖):「运行时多态」、子类与父类之间、子类重写父类的方法具有相同的返回类型。

    重载:发生在同一个类中,若多个方法之间方法名相同、参数列表不同,则它们构成重载的关系。 重载方法的返回值以及「访问修饰符无关」,即重载的方法不能根据返回类型进行区分。

重写子类返回值要小于等于父类方法,抛出的异常要小于等于父类方法,「访问修饰符则要大于等于」父类方法。还有,若父类方法的访问修饰符为private,则子类不能对其重写。

5、Java 中是否可以重写一个 private 或者 static 方法?

Java 中 static 方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而 static 方法是编译时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。
静态方法是类在加载时就被加载到内存中的方法,在整个运行过程中保持不变,因而不能重写。
Java 中也不可以覆盖 private 的方法,因为 private 修饰的变量和方法只能在当前类中使用, 如果是其他的类继承当前类是不能访问到 private 变量或方法的,当然也不能覆盖。

静态方法补充:静态的方法可以被继承,但是不能重写如果父类和子类中存在同样名称和参数的静态方法,那么该子类的方法会把原来继承过来的父类的方法隐藏,而不是重写。通俗的讲就是父类的方法和子类的方法是两个没有关系的方法,具体调用哪⼀个方法是看是哪个对象的引用;这种父子类方法也不在存在多态的性质。

6、构造器是否可以被重写?

在讲继承的时候我们就知道父类的私有属性和构造方法并不能被继承,所以 Constructor 也就不能被 Override(重写),但是可以 Overload(重载),所以你可以看到⼀个类中有多个构造函数的情况。
每一个类必须有自己的构造函数,负责构造自己这部分的构造。子类不会覆盖父类的构造函数,相反必须一开始调用父类的构造函数。

7、构造方法有哪些特性?

  1. 名字与类名相同;
  2. 没有返回值,但不能⽤ void 声明构造函数;
  3. 成类的对象时自动执行,⽆需调⽤。

    8、在 Java 中定义一个不做事且没有参数的构造方法有什么作用?

    Java 程序在执行子类的构造方法之前,如果没有用super() 来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”
    因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中⼜没有用super() 来调⽤父类中特定的构造方法,则编译时将发生错误,因为Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是:在父类里加上⼀个不做事且没有参数的构造方法。

    9、Java 中创建对象的几种方式?

  4. 使用 new 关键字;

  5. 使用 Class 类的 newInstance 方法,该方法调用无参的构造器创建对象(反射)Class.forName.newInstance();
  6. 使用 clone() 方法;
  7. 反序列化,比如调用 ObjectInputStream 类的 readObject() 方法。

    10、抽象类和接口有什么区别?

  8. 抽象类中可以定义构造函数,接口不能定义构造函数;

  9. 抽象类中可以有抽象方法和具体方法,而接口中只能有抽象方法(public abstract);
  10. 抽象类中的成员权限可以是 public、默认、protected(抽象类中抽象方法就是为了重写,所以不能被 private 修饰),而接口中的成员只可以是 public(方法默认:public abstrat、成员变量默认:public static final);
  11. 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

JDK 8 中的改变

  1. 在 JDK1.8中,允许在接口中包含带有具体实现的方法,使用 default 修饰,这类方法就是默认方法。
  2. 抽象类中可以包含静态方法,在 JDK1.8 之前接口中不能包含静态⽅法,JDK1.8 以后可以包含。之前不能包含是因为,接口不可以实现方法,只可以定义方法,所以不能使用静态方法(因为静态方法必须实现)。现在可以包含了,只能直接用接口调用静态方法。JDK1.8 仍然不可以包含静态代码块。

    11、静态变量和实例变量的区别? (全局变量和局部变量的区别)

    静态变量:是被static修饰的变量,也称为类变量,它属于类,因此不管创建多少个对象,静态变量在内存中有且仅有⼀个拷贝;静态变量可以实现让多个对象共享内存。
    实例变量:属于某⼀实例,需要先创建对象,然后通过对象才能访问到它。
    Java中的变量分为成员变量和局部变量,它们的区别如下:
    成员变量(全局变量):

  3. 成员变量是在类的范围里定义的变量;

  4. 成员变量有默认初始值;
  5. 未被static修饰的成员变量也叫实例变量,它存储于对象所在的堆内存中,生命周期与对象相同;
  6. 被static修饰的成员变量也叫类变量(静态变量),它存储于方法区中,生命周期与当前类相同。

局部变量:

  1. 局部变量是在方法里定义的变量;
  2. 局部变量没有默认初始值;
  3. 局部变量存储于栈内存中,作用的范围结束,变量空间会自动的释放。

    注意事项 Java中没有真正的全局变量,面试官应该是出于其他语言的习惯说全局变量的,他的本意应该是指成员变量。

实例变量若为引用数据类型,其默认值一律为null。若为基本数据类型,其默认值如下:

byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
char ‘\u0000’
boolean false

12、short s1 = 1;s1 = s1 + 1;有什么错?那么 short s1 = 1; s1 += 1;呢?有没有错误?

对于 short s1 = 1; s1 = s1 + 1; 来说,在 s1 + 1 运算时会⾃动提升表达式的类型为 int ,那么将 int 型值赋值给 short 型变量,s1 会出现类型转换错误。
对于 short s1 = 1; s1 += 1; 来说,+= 是 Java 语⾔规定的运算符,Java 编译器会对它进行特殊处理,因此可以正确编译。

13、Integer 和 int 的区别?

  1. int 是 Java 的⼋种基本数据类型之⼀,而Integer 是 Java 为 int 类型提供的封装类;
  2. int 型变量的默认值是 0,Integer 变量的默认值是 null,这⼀点说明 Integer 可以区分出未赋值和值为0 的区分;
  3. Integer 变量必须实例化后才可以使⽤,而 int 不需要。

Integer 和 int 的比较延伸

  1. 由于 Integer 变量实际上是对⼀个 Integer 对象的引⽤,所以两个通过 new ⽣成的 Integer 变量永远是不相等 的,因为其内存地址是不同的;
  2. Integer 变量和 int 变量⽐较时,只要两个变量的值是相等的,则结果为 true。因为包装类 Integer 和基本数据类型 int 类型进⾏⽐较时,Java 会⾃动拆包装类为 int,然后进⾏⽐较,实际上就是两个 int 型变量在进⾏⽐较;
  3. ⾮ new ⽣成的 Integer 变量和 new Integer() ⽣成的变量进⾏⽐较时,结果为 false。因为⾮ new ⽣成的 Integer 变量指向的是 Java 常量池中的对象,⽽ new Integer() ⽣成的变量指向堆中新建的对象,两者在内存中的地址不同;
  4. 对于两个非 new ⽣成的 Integer 对象进行比较时,如果两个变量的值在区间 [-128, 127] 之间,则⽐较结果为 true,否则为 false。Java 在编译 Integer i = 100 时,会编译成 Integer i = integer.valueOf(100),⽽ Integer 类型 的 valueOf 的源码如下所示:

    1. public static Integer valueOf(int var0) {
    2. return var0 >= -128 && var0 <= Integer.IntegerCache.high ?
    3. Integer.IntegerCache.cache[var0 + 128] : new Integer(var0);
    4. }

    从上⾯的代码中可以看出:Java 对于 [-128, 127] 之间的数会进⾏缓存,⽐如:Integer i = 127,会将 127 进⾏缓存,下次再写 Integer j = 127 的时候,就会直接从缓存中取出,⽽对于这个区间之外的数就需要 new 了。
    关于包装类的缓存:
    Boolean:全部缓存
    Byte:全部缓存
    Character:<= 127 缓存
    Short:-128 — 127 缓存
    Long:-128 — 127 缓存
    Integer:-128 — 127 缓存
    Float:没有缓存
    Doulbe:没有缓存

    14、装箱和拆箱

    自动装箱是 Java 编译器在基本数据类型和对应得包装类之间做的⼀个转化比如:把 int 转化成Integer,double 转化成 Double 等等。反之就是自动拆箱。
    原始类型:boolean、char、byte、short、int、long、float、double
    封装类型:Boolean、Character、Byte、Short、Integer、Long、Float、Double
    为啥要有包装类?
    Java语言是面向对象的语言,其设计理念是“一切皆对象”。但8种基本数据类型却出现了例外,它们不具备对象的特性。正是为了解决这个问题,Java为每个基本数据类型都定义了一个对应的引用类型,这就是包装类。
    扩展阅读
    Java之所以提供8种基本数据类型,主要是为了照顾程序员的传统习惯。这8种基本数据类型的确带来了一定的方便性,但在某些时候也会受到一些制约。比如,所有的引用类型的变量都继承于Object类,都可以当做Object类型的变量使用,但基本数据类型却不可以。如果某个方法需要Object类型的参数,但实际传入的值却是数字的话,就需要做特殊的处理了。有了包装类,这种问题就可以得以简化。

    15、如何对 Integer 和 Double 类型判断相等?

    Integer、Double不能直接进行比较,这包括:

  5. 不能用==进行直接比较,因为它们是不同的数据类型;

  6. 不能转为字符串进行比较,因为转为字符串后,浮点值带小数点,整数值不带,这样它们永远都不相等;
  7. 不能使用compareTo方法进行比较,虽然它们都有compareTo方法,但该方法只能对相同类型进行比较。

可以将Integer、Double先转为转换为相同的基本数据类型(如double),然后使用==进行比较。
示例代码

  1. Integer i = 100;
  2. Double d = 100.00;
  3. System.out.println(i.doubleValue() == d.doubleValue());

16、switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在String 上?

在 switch(expr) 中,expr 只能是⼀个「整数表达式或者枚举常量」。而整数表达式可以是 int 基本数据类型或者 Integer 包装类型
由于,byte、short、char 都可以隐式转换为 int,所以,这些类型以及这些类型的包装类型也都是可以的。
而 long 和 String 类型都不符合 switch 的语法规定,并且不能被隐式的转换为 int 类型,所以,它们不能作用于 switch 语句中。

JDK1.7 版本之后 switch 就可以作在 String 上了。

17、Object 的常用方法有哪些?

clone 用于创建并返回当前对象的⼀份拷贝;
getClass 用于返回当前运行时对象的 Class;
toString 返回对象的字符串表示形式;
finalize 实例被垃圾回收器回收时触发的方法;
equals 用于比较两个对象的内存地址是否相等,一般需要重写;
hashCode 用于返回对象的哈希值;
notify 唤醒⼀个在此对象监视器上等待的线程。如果有多个线程在等待只会唤醒一个。
notifyAll 作用跟 notify() 一样,只不过会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
wait 让当前对象等待;
……. …….

18、final、finally、finalize 的区别?

final:用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖、被其修饰的类不可继承;

  • final 变量:被修饰的变量不可变,不可变分为引用不可变和对象不可变 ,final 指的是引用不可,final 修饰的变量必须初始化,通常称被修饰的变量为常量 。
  • final 方法:被修饰的方法不允许任何子类重写,子类可以使用该方法。
  • final 类:被修饰的类不能被继承,所有方法不能被重写。

finally:异常处理语句结构的⼀部分,表示总是执行;

  • finally 作为异常处理的一部分,它只能在 try/catch 语句中,并且附带一个语句块表示这段语句最终一定被执行(无论是否抛出异常),经常被用在需要释放资源的情况下, System.exit(0) 可以阻断finally 执行。

finallize:Object类的⼀个方法,在垃圾回收时会调用被回收对象的finalize。

  • 一个对象的 finalize 方法只会被调用一次,finalize 被调用不一定会立即回收该对象,所以有可能调用 finalize后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会再次调用 finalize了,进而产生问题,因此不推荐使用 finalize 方法。

    19、== 和 equals 的区别?

  • ==:对比的是栈中得值,如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等。

  • equals 方法:用来比较两个对象的内容是否相等。

Object:
image.png
String:
image.png
Java基础 - 图4
上述代码可以看出,String类中被复写的equals()方法其实是比较两个字符串的内容。
注意:equals 方法不能用于比较基本数据类型的变量。如果没有对 equals 方法进行重写,则比较的是引用类型的变量所指向的对象的地址(很多类重写了 equals ⽅法,比如 String、Integer 等把它变成了值比较,所以⼀般情况下 equals 比较的是值是否相等)。
image.png

20、两个对象的 hashCode() 相同,则 equals() 也⼀定为 true 吗?

两个对象的 hashCode() 相同,equals() 不⼀定为 true。
因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不⼀定能得出键值对相等,可能出现散列冲突的情况

21、hashCode() 与 equals() 之间的关系

HashCode介绍:hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,Java中的任何类都包含有hashCode() 函数。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码(可以快速找到所需要的对象)

21、为什么重写 equals() 就一定要重写 hashCode() 方法?

这个问题应该是有个前提,就是你需要用到 HashMap、HashSet 等 Java 集合,用不到哈希表的话,其实仅仅重写 equals() 方法也可以。而工作中的场景是常常用到 Java 集合,所以 Java 官方建议重写 equals() 就⼀定要重写 hashCode() 方法。
对于对象集合的判重,如果⼀个集合含有 10000 个对象实例,仅仅使用equals() 方法的话,那么对于⼀个对象判重就需要比较 10000 次,随着集合规模的增⼤,时间开销是很大的。但是同时使用哈希表的话,就能快速定位到对象的大概存储位置,并且在定位到大概存储位置后,后续比较过程中,如果两个对象的 hashCode 不相同,也不再需要调用 equals() ⽅法,从而大大减少了 equals() 比较次数。
所以从程序实现原理上来讲的话,既需要 equals() 方法,也需要 hashCode() 方法。那么既然重写了 equals(),那么也要重写 hashCode() 方法,以保证两者之间的配合关系。
hashCode()与equals()的相关规定

  1. 如果两个对象相等,则 hashCode ⼀定也是相同的;
  2. 两个对象相等,对两个对象分别调用 equals 方法都返回 true;
  3. 两个对象有相同的 hashCode 值,它们也不⼀定是相等的;
  4. 因此,equals 方法被覆盖(重写)过,则 hashCode 方法也必须被覆盖;
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该 class 的两个对象⽆论如何都不会相等(即使这两个对象指向相同的数据)。

    22、& 和 && 的区别?

    Java 中 && 和 & 都是表示与的逻辑运算符,都表示逻辑运输符 and,当两边的表达式都为 true 的时候,整个运算 结果才为 true,否则为 false。
    &&:有短路功能,当第⼀个表达式的值为 false 的时候,则不再计算第二个表达式;
    &:不管第⼀个表达式结果是否为 true,第二个都会执行。
    除此之外,& 还可以⽤作位运算符:当 & 两边的表达式不是 Boolean 类型的时候,& 表示按位操作。

    23、Java 中的参数传递时传值呢?还是传引用?

    Java 的参数是以值传递的形式传入方法中,而不是引用传递。

  6. 当传递方法参数类型为基本数据类型(数字以及布尔值)时

    1. 一个方法是不可能修改⼀个基本数据类型的参数
  7. 当传递方法参数类型为引用数据类型时,一个方法将修改一个引用数据类型的参数所指向对象的值。

    1. 即使 Java 函数在传递引用数据类型时,也只是拷贝了引用的值罢了,之所以能修改引用数据是因为它们同时指向了一个对象,但这仍然是按值调用而不是引用调用。

      24、Java 中的 Math.round(-1.5) 等于多少?

      等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。
      System.out.println(Math.round(11.5));   // 12
      System.out.println(Math.round(-11.5));  // -11
      

      25、两个二进制数的异或结果是什么?

      两个二进制数异或结果是这两个二进制数差的绝对值。表达式如下:a^b = |a-b|。
      两个⼆进制 a 与 b 异或,即 a 和 b 两个数按位进⾏运算。如果对应的位相同,则为 0(相当于对应的算术相减), 如果不同即为 1(相当于对应的算术相加)。由于⼆进制每个位只有两种状态,要么是 0,要么是 1,则按位异或 操作可表达为按位相减取值相对值,再按位累加。

      26、如何实现对象的克隆?(深克隆)

  8. 实现 Cloneable 接口并重写 Object 类中的 clone() 方法;

  9. 实现 Serializable 接⼝,通过对象的序列化和反序列化实现克隆,可以实现真正的深克隆。

    27、深克隆和浅克隆的区别?

  10. 浅克隆:拷贝对象和原始对象的引用类型引用同⼀个对象浅克隆只是复制了对象的引用地址,两个对象指向同⼀个内存地址,所以修改其中任意的值,另⼀个值都会随之变化

  11. 深克隆:拷贝对象和原始对象的引用类型引用不同对象深拷贝是将对象及值复制过来,两个对象修改其中任意的值另⼀个值不会改变,这就是深拷贝(例:JSON.parse() 和 JSON.stringify(),但是此⽅法⽆法复制函数类型)。

补充
深克隆的实现就是在引用类型所在的类实现 Cloneable 接口,并使用 public 访问修饰符重写 clone 方法。
Java 中定义的 clone 没有深浅之分,都是统⼀的调⽤ Object 的 clone ⽅法。

28、什么是 Java 的序列化,如何实现 Java 的序列化?

对象序列化是⼀个用于将对象状态转换为字节流的过程可以将其保存到磁盘文件中或通过网络发送到任何其他程序。从字节流创建对象的相反的过程称为反序列化。而创建的字节流是与平台无关的,在⼀个平台上序列化的对象可以在不同的平台上反序列化。序列化是为了解决在对象流进行读写操作时所引发的问题。

29、什么情况下需要序列化?

  1. 当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
  2. 当你想用套接字在网络上传送对象的时候;
  3. 当你想通过 RMI 传输对象的时候。

    30、什么是字节码采用字节码的好处是什么

    Java之所以可以“一次编译,到处运行”

  4. 因为JVM针对各种操作系统、平台都进行了定制;

  5. 因为无论在什么平台,都可以编译生成固定格式的字节码(.class文件)供JVM使用。因此,也可以看出字节码对于Java生态的重要性。

之所以被称之为字节码,是因为字节码文件由十六进制值组成,而JVM以两个十六进制值为一组,即以字节为单位进行读取。在Java中一般是用 javac 命令编译源代码为字节码文件,一个 .java 文件从编译到运行的示例如图所示。
Snipaste_2022-01-06_09-29-53.png
好处Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

31、Oracle JDK OpenJDK 的区别是什么?

  1. Oracle JDK 版本将每三年发布一次,而 OpenJDK 版本每三个月发布一次;
  2. OpenJDK 是一个参考模型并且是完全开源的,而 Oracle JDK 是OpenJDK 的一个实现,并不是完全开源的;
  3. Oracle JDK 比 OpenJDK 更稳定。OpenJDK 和 Oracle JDK 的代码几乎相同,但 Oracle JDK 有更多 的类和一些错误修复。因此,如果您想开发企业/商业软件,建议选择 Oracle JDK,因为它经过了彻底的测试和稳定。某些情况下,有些人提到在使用 OpenJDK 可能会遇到了许多应用程序崩溃的问题,但是,只需切换到 Oracle JDK 就可以解决问题;
  4. 在响应性和 JVM 性能方面,Oracle JDK 与 OpenJDK 相比提供了更好的性能;
  5. Oracle JDK 不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来获取最新版本;
  6. Oracle JDK 根据二进制代码许可协议获得许可,而 OpenJDK 根据 GPLv2 许可获得许可。

    32、 Java有哪些数据类型?

    Java 语言的数据类型分为两种:基本数据类型和引用数据类型。
    Snipaste_2022-01-06_09-48-12.png
类型名称 关键字 占用内存 取值范围
字节型 byte 1字节(8位) -128~127
短整型 short 2字节(16位) -2^15 ~ 2^15-1
整形 int 4字节(32位) -2^31 ~ 2^31-1
长整型 long 8字节(64位) -2^63 ~ 2^63-1
单精度浮点型 float 4字节(32位) -3.410^38 ~ 3.410^38。
双精度浮点型 double 8字节(64位) -1.810^308 ~ 1.810^308。
字符型 char 2字节(16字节) \u0000 ~ \uffff
布尔型 boolean 1字节(8位) true or false

33、访问修饰符publicprivateprotected、以及不写(默认)时的区别?

Java语言为我们提供了三种访问修饰符,即private、protected、public,在使用这些修饰符修饰目标时,一共可以形成四种访问权限,即 private、defalut、protected、public,注意在不加任何修饰符时(默认)为defalut访问权限。
在修饰成员变量/成员方法时,该成员的四种访问权限的含义如下:

  • private:该成员可以被该类内部成员访问;
  • defalut:该成员可以被该类内部成员访问,也可以被同一包下其他的类访问;
  • protected:该成员可以被该类内部成员访问,也可以被同一包下其他的类访问,还可以被它的子访问;
  • public:该成员可以被任意包下,任意类的成员进行访问。

在修饰类时,该类只有两种访问权限,对应的访问权限的含义如下:

  • defalut:该类可以被同一包下其他的类访问;
  • public:该类可以被任意包下,任意的类所访问。 | 修饰符 | **类 | 同一个包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 | | —- | —- | —- | —- | —- | —- | | public | Y | Y | Y | Y | Y | | protected | Y | Y | Y | N | N | | default | Y | Y | Y | N | N | | private | Y | N | N | N | N |

34、break ,continue ,return 的区别及作用?

  • break 跳出总上一层循环,不再执行循环(结束当前的循环体);
  • continue 跳出本次循环,继续执行下次循环(结束正在执行的循环,进入下一个循环条件);
  • return 程序返回,不再执行下面的代码(结束当前的方法,直接返回);

    35、为什么要用 static 关键字?

    方便在没有创建对象的情况下来进行调用(方法/变量)。
    静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间,也就是只要程序在运行,那么这块内存就会一直存在。
    这样的设计,static可以用来区分成员变量、方法是属于类本身还是属于类实例化后的对象。
    有static修饰的成员属于类本身,没有static修饰的成员属于类的实例。
    通常来说,用new创建类的对象时,数据存储空间才被分配,方法才供外界调用。但有时我们只想为特
    定域分配单一存储空间,不考虑要创建多少对象或者说根本就不创建任何对象,再就是我们想在没有创
    建对象的情况下也想调用方法。在这两种情况下,static关键字,满足了我们的需求。

    36、static 静态方法能不能引用非静态资源?

    不能,new的时候才会产生的东西,对于初始化后就存在的静态资源来说,根本不认识它。

    37、static 静态方法里面能不能引用静态资源?

    可以,因为都是类初始化的时候加载的,大家相互都认识。

    38、非静态方法里面能不能引用静态资源?

    可以,非静态方法就是实例方法,那是new之后才产生的,那么属于类的内容它都认识。

    39、 Java 静态变量、代码块、和静态方法的执行顺序是什么?

    基本上代码块分为三种:static静态代码块、构造代码块、普通代码块
    代码块执行顺序:静态代码块——> 构造代码块 ——> 普通代码块
    继承中代码块执行顺序:
  1. 父类静态块——>子类静态块
  2. 父类代码块——>父类构造器
  3. 子类代码块——>子类构造器 ```java class A { public A() {

     System.out.println("class A");
    

    }

    {

     System.out.println("I'm A class");
    

    }

    static {

     System.out.println("class A static");
    

    } }

public class B extends A { public B() { System.out.println(“class B”); }

{
    System.out.println("I'm B class");
}

static {
    System.out.println("class B static");
}

public static void main(String[] args) {
    new B();
}

}

![image.png](https://cdn.nlark.com/yuque/0/2022/png/12437668/1641440619175-51dbe246-cb10-420e-984b-848ebbab4947.png#clientId=uf0d7f0b4-c48d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=163&id=u842c7b1a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=208&originWidth=268&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10868&status=done&style=none&taskId=uc169506d-bd73-4927-a5b6-d3037830caa&title=&width=210)   ![image.png](https://cdn.nlark.com/yuque/0/2022/png/12437668/1641440653214-538b8136-5624-4c38-b189-4bda2b035421.png#clientId=uf0d7f0b4-c48d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=164&id=uf378d875&margin=%5Bobject%20Object%5D&name=image.png&originHeight=203&originWidth=245&originalType=binary&ratio=1&rotation=0&showTitle=false&size=9243&status=done&style=none&taskId=u95882f3a-efde-439d-b3dd-1da13256fe5&title=&width=198.5)
<a name="aFyjr"></a>
## 40、什么是不可变对象**?**好处是什么**?**
**不可变对象指对象一旦被创建,状态就不能再改变,任何修改都会创建一个新的对象,如 String、Integer及其它包装类。**对象所有的状态及属性在其生命周期内都不会发生任何变化。<br />**不可变对象最大的好处是线程安全。**
<a name="shWuT"></a>
## 41、能否创建一个包含可变对象的不可变对象**?**
当然可以,比如
```java
final Person[] persons = new Persion[]{};

persons 是不可变对象的引用,但其数组中的Person实例却是可变的。这种情况下需要特别谨慎,不要共享可变对象的引用。这种情况下,如果数据需要变化时,就返回原对象的一个拷贝。

  1. 所有成员变量必须是private;
  2. 最好同时用final修饰(非必须);
  3. 不提供能够修改原有对象状态的方法;
    • 最常见的方式是不提供setter方法;
    • 如果提供修改方法,需要新创建一个对象,并在新创建的对象上进行修改;
  4. 通过构造器初始化所有成员变量,引用类型的成员变量必须进行深拷贝(deep copy);
  5. getter方法不能对外泄露this引用以及成员变量的引用;
  6. 最好不允许类被继承(非必须);

    42、值传递和引用传递的区别的什么?

    值传递指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就
    互不相关了。
    引用传递指的是在方法调用时,传递的参数是按引用进行传递,其实传递的是引用的地址,也就是变
    量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是
    同一个内存空间)。

    43、float 型 float f = 3.4 是否正确?编译能否通过?

    不正确
    原因:精度不准确,应该用强制类型转换,如下所示:
    float f = (float) 3.4;
    float f = 3.4f;
    
    在 Java 里面,没小数点的默认是 int ,有小数点的默认是 double;
    编译器可以自动向上转型,如 int 转成 long 系统自动转换没有问题,因为后者精度更高。