您的当前位置:首页正文

【Java面试题】之 OOP

2024-11-23 来源:个人技术集锦

原文:

1、什么是面向过程

面向过程是一种自上而下的编程模式,它将问题拆分为一个个步骤,每个步骤用函数实现,依次调用即可

2、什么是面向对象

面向对象是一种将事务高度抽象化的编程模式,它也是将问题分解为一个个步骤,它会对每个步骤进行相应的抽象,形成一个个对象,通过不同对象之间的调用,组合解决问题

3、面向对象与面向过程的区别

面向过程:占用资源低,执行速度相对快
面向对象:占用资源高,执行速度相对慢,但是面向对象可以使工程更加模块化,实现更低的耦合和更高的内聚

4、面向对象的三大基本特征

封装、继承、多态

5、你对封装是怎么理解的

就是将客观事物封装成抽象的类,可以只让可信的类或者对象进行访问,对不可信的隐藏。

6、你再说说继承

继承是指一个类可以继承另一个类的所有功能,并在无需重新编写原来类的情况下对其进行扩展,这种派生方式体现了传递性,除了继承,还有一种体现传递性的方式叫做实现。

两者的区别:
● 继承:使用父类的所有属性和方法,无需对其额外编码
● 实现:只能使用接口定义的全局变量和方法的名称,并且实现类必须提供方法的实现

7、什么是多态

所谓多态就是指一个类实例的相同方法在不同情形有不同的表现形式,使具有不同内部结构的对象可以共享相同的外部接口。

8、如何实现多态

● 有类继承或者接口实现
● 子类要重写父类的方法
● 父类的引用指向子类的对象

编译看左边,运行看右边

9、什么是 B/S 架构?什么是 C/S 架构

10、JDK、JRE、JVM 有什么区别?

JDK:「Java Development Kit」
● Java 开发工具包,提供了 Java 的开发环境和运行环境,包含编译 Java 源文件的编译器 Javac,还有调试和分析的工具。

JRE:「Java Runtime Environment」
● Java 运行环境,包含 Java 虚拟机和一些基础类库

JVM:「Java Virtual Machine」
● Java 虚拟机,提供了执行字节码文件的能力

11、Java 的基本数据类型以及包装类有哪些?

数值型
● 整型:byte、short、int、long
● 浮点型:float、double
字符型
● char
布尔型
● boolean

包装类
● Byte、Short、Integer、Long、Float、Double、Character、Boolean

12、Java 常见的数据结构有哪些?

  1. 数组「Array」
  2. 栈「Stack」
  3. 链表「Linked List」
  4. 图「Graph」
  5. 哈希表「Hash」
  6. 队列「Queue」
  7. 树「Tree」
  8. 堆「Heap」

13、== 和 equals 的区别

equals
● 是 java.lang.Object 的方法,这个方法返回的是 == 的判断,只不过有的类把这个方法重写了,所以才会比较内容是否相等,比如:String

Object的equeals方法:

14、类与对象的关系?

类是对象的抽象,对象是类的具体
类是对象的模板,对象是类的实例

15、instanceof 关键字

用来测试一个对象是否为一个类的实例,这个实例可以为一个对象或者一个接口

编译器会实时检查对象能否转换为类的实例
● 能确定实例类型的话,如果不能转换则直接编译不通过
● 不能确定实例类型的话,具体看运行时

注意:如果判断基本数据类型是是否属于对应包装类的话,比如:1 instanceof Integer,结果肯定是编译不通过

16、什么是隐式转换、显式转换

● 隐式转换就是自动类型转换,就是把一个小类型的数据赋值给大类型的数据,装箱;
● 显式转换就是强制类型转换,把一个大类型的数据强制赋值给小类型的数据,拆箱;

17、char 类型能不能转成 int 类型?能不能转成 String 类型,能不能转成 double 类型

● char 在 java 中也是比较特殊的类型,它的 int 值从 0 开始,一共有 2 的 16 次(65536)方个数据;
● char<int<long<float<double
● char 类型可以隐式转成 int 、double 类型,但是不能隐式转换成 String;
● char 类型转成 byte、short 类型的时候,需要强转。

18、什么是装箱、拆箱

  1. 装箱就是将基本数据类型转换为包装类型(int–>Integer)
    a. 调用:Integer.valueOf(int) 方法
    b. jdk 1.5 之前,必须Integer integer = new Integer(5);
    c. jdk 1.5 之后,实现了自动装箱,直接这样就可以,Integer integer = 5;
  2. 拆箱就是将包装类型转换为基本数据类型(Integer–> int)
    a. 调用:Integer.intValue() 方法
    b. jdk 1.5 之后,实现了自动拆箱,int i = integer;

19、哪些地方会自动拆装箱

  1. 将基本数据类型放入集合类

  2. 包装类型与基本类型比较大小

  3. 包装类型的运算

  4. 三目运算符的使用

  5. 函数参数与返回值

20、final 在 java 中的作用,有哪些用法

  1. 被 final 修饰的类不可以被继承
  2. 被 final 修饰的方法不可以被重写,JVM 会尝试将其内联,以提高运行效率
  3. 被 final 修饰的变量不可以被改变,JVM 在编译阶段会存入常量池中,如果修饰引用,表示引用不可变,但引用指向的内容可变

21、一个 java 类中包含哪些内容?

属性、方法、内部类、构造方法、代码块

22、为什么不能用浮点型表示金额?

由于计算机中保存的小数其实是十进制小数的近似值,并不是准确值,所以最好使用 BigDecimal 或者 Long(单位为分)来表示金额

23、Java 中有哪些访问修饰符,以及它们的区别

● public:表明该成员变量或者方法是对所有类、对象都是可见的,所有类或者对象都可以直接访问
● private:表明该成员变量或者方法是私有的,只有类自身对其具有访问权限,除此之外其他类或者对象都没有访问权限,包括子类
● protected:表明该成员变量或者方法对类自身、一个包中的其他类、子类是可见的,其他包下的类不可访问
● default:类的成员不写访问修饰符时默认为 default,表明该成员变量或者方法只对类自身、一个包中的其他类是可见的,子类、其他包下的类不可访问

24、float f=3.4; 是否正确?

不正确,3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于向下转型 会造成精度损失,因此需要强制类型转换 float f = (float) 3.4; 或者写成 float f = 3.4F;。

25、什么是单精度、双精度

● 单精度浮点数在计算机存储器中占用 4 个字节(32 bits),利用「浮点(浮动小数点)」的方法,可以表示一个范围很大的数值。
● 双精度浮点数(double)则使用 8 个字节(64 bits) 来存储一个浮点数。

26、String、StringBuffer、StringBuilder 的区别

String
● String 是只读字符串,它并不是基本数据类型,而是一个对象。从底层源码来看是一个 final 类型的字符数组,所引用的字符串不能被改变,一经定义,无法再增删改。
● 每次对 String 的操作都会生成新的 String 对象
● 每次 + 操作,会隐式在堆上 new 一个跟原字符串相同的 StringBuilder 对象,再调用 append 方法拼接 + 后面的字符。

StringBuffer、StringBuilder
● StringBuffer 与 StringBuilder 都继承了 AbstractStringBulder 类,而 AbtractStringBuilder 又实现了 CharSequence 接口,两个类都是用来进行字符串操作的。
● 在做字符串拼接修改删除替换时,效率比 String 更高。
● StringBuffer 是线程安全的,Stringbuilder 是非线程安全的。
● 因为 StringBuffer 的方法大多都加了 synchronized 关键字,所以 Stringbuilder 比 Stringbuffer效率更高

27、i++ 与 ++i 的区别

● i++:先赋值,后计算
● ++i:先计算,后赋值

28、数组有几种实例化方式

● 静态实例化:创建数组的同时指定数组中的元素
● 动态实例化:实例化数组的时候,只指定数组长度,数组中所有元素都是数组类型的默认值

29、实例化数组后,能不能改变数组长度?

不能,数组一旦实例化,它的长度就是固定的

30、假设数组内有5个元素,如果对数组进行反序,该如何做?

创建一个新数组,从后到前循环遍历每个元素,将取出的元素按顺序放入新数组中
或者,使用一个临时变量,首尾两两交换

31、Java 中各种数据的默认值

● byte、short、int、long 的默认值都是 0
● boolean 的默认值是 false
● char 的默认值是 \u0000
● float、double 的默认值是 0.0
● 对象类型的默认值是 null

32、Java 常用包有那些?

● Java.lang
● Java.io
● Java.sql
● Java.util
● Java.awt
● Java.net
● Java.math
juc

33、Object 类常用方法有那些?

● equals(Object obj)
● hashCode()
● toString()
● wait()
● notify()
● clone()
● getClass()

34、Java 中有没有指针?

有,但是隐藏了,开发人员无法直接操作指针,由 jvm 来操作指针

35、Java 是值传递还是引用传递?

在 Java 中,其实是通过「值传递」实现的参数传递,只不过对于 Java 对象的传递,传递的内容是对象的引用。

为了让大家都能理解你说的,你就说 Java 中只有值传递,只不过传递的内容是对象的引用。这也是没毛病的。但是,绝对不能认为 Java 中有引用传递。

36、为什么是值传递

编程语言中需要进行方法间的参数传递,这个传递的策略叫做求值策略。

在程序设计中,求值策略有很多种,比较常见的就是「值传递」和「引用传递」。还有一种值传递的特例是「共享对象传递」。

「值传递」和「引用传递」最大的区别是传递的过程中有没有复制出一个副本来,如果是传递副本,那就是值传递,否则就是引用传递。

37、形参与实参

形式参数:是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
实际参数:在调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数称为「实际参数」

37、构造方法能不能显式调用?

构造方法不能当成普通方法调用,只有在创建对象的时候它才会被系统调用

38、什么是重载

重载指的是就是函数或者方法有同样的名称,但是参数列表不相同的情况,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。

39、什么是重写

重写指的是在 Java 的子类与父类中有两个名称、参数列表都相同的方法的情况。由于他们具有相同的方法签名,所以子类中的新方法将覆盖父类中原有的方法,这叫重写。

40、重写的条件

● 参数列表、返回类型必须与被重写方法的相同;
● 访问级别的限制性:不能比被重写方法的强,但可以比被重写方法的弱;

● 重写方法不能抛出新的检查异常,也不能抛出比被重写方法更广泛的检查异常,但是能够抛出更少或更有限的异常
● 不能重写被标识为 final 的方法;
● 如果不能继承一个方法(如private修饰的),则不能重写这个方法。

41、重载的条件

● 被重载的方法必须改变参数列表;
● 被重载的方法可以改变返回类型、访问修饰符、可以声明新的或更广的检查异常;
● 方法能够在同一个类中或者在一个子类中被重载。

42、重载与重写的区别

  1. 重载是一个编译期概念、重写是一个运行期概念。
  2. 重载遵循所谓「编译期绑定」,即在编译时根据参数变量的类型判断应该调用哪个方法。
  3. 重写遵循所谓「运行期绑定」,即在运行的时候,根据引用变量所指向的实际对象的类型来调用方法
  4. 因为在编译期已经确定调用哪个方法,所以重载并不是多态。而重写是多态。重载只是一种语言特性,是一种语法规则,与多态无关,与面向对象也无关。(注:严格来说,重载是编译时多态,即静态多态。但是,Java 中提到的多态,在不特别说明的情况下都指动态多态)

43、构造方法能不能重写?能不能重载?

不能重写,但是能重载

44、静态内部类与(成员)内部类的区别?

  • 静态内部类
    ● 静态内部类相对于外部类是独立存在的,
    ● 静态内部类可以访问外部类所有的静态变量和方法,即使是 private 的也一样,
    ● 静态内部类无法直接访问外部类的实例变量、方法,如果要访问的话,必须要 new 一个外部类的对象,使用 new 出来的对象访问。
    ● 静态内部类和一般类一致,可以定义静态变量、方法,构造方法等。
    ● 其他的类要访问静态内部类的属性或者调用静态内部类的方法,需要使用「外部类.静态内部类」的方式
    ● Java 集合类 HashMap 内部就有一个静态内部类 Entry。Entry 是 HashMap 存放元素的抽象,HashMap 内部维护 Entry 数组用来存放元素,但是 Entry 对使用者是透明的。像这种和外部类关系密切,且不依赖外部类实例的,都可以使用静态内部类。

  • 普通内部类
    ● 普通内部类作为外部类一个成员而存在,在普通内部类中可以直接访问外部类属性,调用外部类的方法。
    ● 如果外部类要访问内部类的属性或者调用内部类的方法,必须要创建一个内部类的对象,使用该对象访问属性或者调用方法。
    ● 如果其他的类要访问普通内部类的属性或者调用普通内部类的方法,必须要在外部类中创建一个普通内部类的对象作为一个属性,才可以通过该属性调用普通内部类的方法或者访问普通内部类的属性

45、static 关键字有什么作用?

static 可以修饰内部类、方法、变量、代码块
● static 修饰的类是「静态内部类」
● static 修饰的方法是「静态方法」,表示该方法属于当前类,而不是属于某个对象,静态方法不能被重写,可以直接使用类名来调用。在 静态方法中不能使用 this 或者 super 关键字。
● static 修饰的变量是「静态变量」或者叫「类变量」,静态变量被所有实例所共享,不会依赖于对象。静态变量在内存中只有一份拷贝,在 JVM 加载类的时候,只为静态变量分配一次内存。
● static 修饰的代码块叫「静态代码块」,通常用来做程序优化。静态代码块中的代码在整个类加载的时候只会执行一次。静态代码块可以有多个,如果有多个,按照先后顺序依次执行。
● static 还可以静态导包,这是 jdk 1.5 之后的新特性,举例:import static java.lang.Math.*;,假如要使用 Math 这个类里面的 sin() 方法,此时就不需要用 Math.,可以直接调用 sin();

46、Math 类有哪些常用方法

● pow():幂运算(最终调用native方法)

● sqrt():平方根

● round():四舍五入

● abs():求绝对值

● random():生成一个 0-1 的随机数,包括 0 不包括 1

min()

max()

47、String类的常用方法有哪些?

● charAt():返回指定索引处的字符
● indexOf():返回指定字符的索引
● replace():字符串替换
● trim():去除字符串两端空白
● split():分割字符串,返回一个分割后的字符串数组
● getBytes():返回字符串的byte类型数组
● length():返回字符串长度
● toLowerCase():将字符串转成小写字母
● toUpperCase():将字符串转成大写字符
● substring():截取字符串
● format():格式化字符串
● equals():字符串比较
toCharArray():转化为字符数组
intern():如果字符常量池有该字符串则直接返回,否则放入常量池并返回

48、Java 是单继承还是多继承

只能继承一个类,但是可以实现多个接口

49、super 与 this 表示什么?

● super 表示当前类的父类对象
● this 表示当前类的对象

50、普通类与抽象类有什么区别?

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

51、什么是接口?为什么需要接口?

接口就是某个事物对外提供的一些功能的声明,是一种特殊的 java 类,接口弥补了 java 单继承的缺点

52、接口有什么特点

● 接口中的变量只能是 public static final 修饰的常量
● 接口中所有方法都是抽象方法
● 接口没有构造方法
● 接口不能直接实例化
● 一个类可以实现多个接口

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

抽象类

  1. 抽象方法,只有行为的概念,没有具体的行为实现。
  2. 使用 abstract 关键字修饰,没有方法体。子类必须重写这些抽象方法。
  3. 抽象类只能被继承,一个类只能继承一个抽象类。
  4. 抽象类的成员支持全部的权限修饰符
  5. 抽象类可以定义构造器、抽象方法、非抽象方法

接口

  1. 全部的方法都是抽象方法,属性都是常量
  2. 不能实例化
  3. 接口变量可以引用具体实现类的实例
  4. 接口只能被实现,一个具体类实现接口,必须实现全部的抽象方法
  5. 接口之间可以多实现
  6. 一个具体类可以实现多个接口,实现多继承现象
  7. 接口中定义的成员只能定义为 public
  8. jdk 1.8 之后,接口里面可以有实现的方法,要在方法的声明上加上 default 或者 static

54、为什么要有 hashCode

Java 中有两类集合,List 和 Set,List 有序可重复,Set 无序不可重复,当我们要往 Set 中插入数据的时候,它是怎么判断要插入的数据是否重复呢,可以使用 equals() 方法,但是如果元素太多,执行效率就会比较慢。

于是有人发明了哈希算法来提高集合中查找元素的效率。这种方式会将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储的那个区域。

这样一来,当集合要添加新的元素时,先调用这个元素的 hashCode()方法,一下子就能定位到它应该存放的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;

、有没有可能两个不相等的对象有相同的 hashCode
有可能,在产生 hash 冲突时,两个不相等的对象就会有相同的 hashcode 值

一般有以下几种方式来处理:

  1. 拉链法(链地址法)
    ● 将哈希表的每个单元作为链表的头结点,所有哈希地址为 i 的元素构成一个同义词链表。即发生冲突时就把该关键字链在以该单元为头结点的链表的尾部。
  2. 开放定址法
    ● 一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,总能找到空的散列地址,并将记录存入
  3. 再哈希法
    ● 当哈希地址发生冲突时,用其他的函数计算另一个哈希函数地址,直到不再产生冲突。

55、Java 的四种引用,强弱软虚

强引用
● 是平常中使用最多的引用,强引用在程序内存不足「OOM」的时候也不会被回收

软引用
● 软引用在程序内存不足时,会被回收,
● 可用场景: 创建缓存的时候,创建的对象放进缓存中,当内存不足时,JVM 就会回收早先创建的对象。

弱引用
● 弱引用就是只要 JVM 垃圾回收器发现了它,就会将之回收,
● 可用场景:Java 源码中的 java.util.WeakHashMap 中的 key 就是使用弱引用,
● 我的理解:一旦我不需要某个引用,JVM 会自动帮我处理它,这样我就不需要做其它操作。

虚引用
● 虚引用的回收机制跟弱引用差不多,但是它被回收之前,会被放入 ReferenceQueue 中。其它引用都是被 JVM 回收后才被传入 ReferenceQueue 中的。由于这个机制,虚引用大多被用于引用销毁前的处理工作。
● 虚引用创建的时候,必须带有 ReferenceQueue
● 可用场景: 对象销毁前的一些操作,比如说资源释放(Object.finalize() 虽然也可以做这类动作,但是这个方式不安全并且效率还低)

上面所说的这几类引用,都是指对象本身的引用,而不是指 Reference 的四个子类的引用

56、Java创建对象有几种方式?(4)

  1. new 创建新对象
  2. 通过反射机制
  3. 采用 clone 机制
  4. 通过序列化机制

57、浅拷贝和深拷贝的区别是什么?

浅拷贝
对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝

深拷贝
对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容

58、a = a + b 与 a += b 有什么区别吗?

+= 操作符会进行隐式自动类型转换,此处 a += b 隐式的将加操作的结果类型强制转换为持有结果的类型,而a = a + b 则不会自动进行类型转换

59、short s1 = 1; s1 = s1 + 1; 是否有错?

有错,short 类型在进行运算时会自动提升为 int 类型,也就是说 s1 + 1 的运算结果是 int 类型,而 s1 是 short,此时编译器会报错

解决:将 s1 = s1 + 1; 改成 s1 += 1; 即可

例如,在Idea中:

60、final、finally、finalize 有什么区别?

性质不同

  1. final 为关键字;
  2. finally 为区块标志,用于 try 语句中;
  3. finalize() 为方法;

作用

  1. final 是用于标识常量的关键字,final 标识的关键字存储在常量池中
  2. finally{} 用于标识代码块,与 try{} 进行配合,不论 try 中的代码执行完或没有执行完(这里指有异常),finally{} 中的代码一定会运行
  3. finalize()方法在 Object 中进行了定义,用于在对象“消失”时,由 JVM 调用,用于对象进行垃圾回收,类似于 C++ 中的「析构函数」;用户自定义时,用于释放对象占用的资源(比如进行 I/O 操作);

61、JDBC 操作的步骤(5)

  1. 加载数据库驱动类
  2. 打开数据库连接
  3. 执行 SQL 语句
  4. 处理返回结果
  5. 关闭资源

62、在使用 JDBC 的时候,如何防止出现 SQL 注入的问题。

使用 PreparedStatement 类,而不是使用 Statement 类

63、怎么在JDBC内调用一个存储过程

使用 CallableStatement

64、是否了解连接池,使用连接池有什么好处?

数据库连接是非常消耗资源的,影响到程序的性能指标。

连接池是用来分配、管理、释放数据库连接的,可以使应用程序重复使用同一个数据库连接,而不是每次都创建一个新的数据库连接。通过释放空闲时间较长的数据库连接,避免数据库因为创建太多的连接而造成的连接遗漏问题,提高了程序性能。

65、你所了解的数据源技术有那些?使用数据源有什么好处?

Druid、Dbcp、c3p0等,用的最多还是 Druid、c3p0,因为 Druid 更加稳定,安全;通过配置文件的形式来维护数据库信息,而不是通过硬编码。当连接的数据库信息发生改变时,不需要再更改程序代码就可以实现数据库信息的更新。

66、& 和 && 的区别

● & 是位运算符。
● && 是布尔逻辑运算符,在进行逻辑判断时用

● & 处理的前面为 false,后面的内容仍需处理,
● && 处理的前面为 false,则不再处理后面的内容。

67、数组有没有 length() 这个方法? String有没有 length()这个方法

● 数组没有 length() 这个方法,有 length 的属性。
● String 有 length() 这个方法

68、用最有效率的方法算出 2 乘以 8 等于 几

2 << 3

69、排序都有哪几种方法?请列举


70、char 型变量中能不能存贮一个中文汉字,为什么?

char 类型可以存储一个中文汉字,因为 Java 中使用的编码是 Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个 char 类型占 2 个字节(16 比特),所以放一个中文是没问题的。

71、Java 中会存在内存泄漏吗,请简单描述

在实际开发中 ,可能会存在某些对象已经不再使用了,但是依旧被某些地方所引用的对象,这些对象不会被 GC 回收 ,因此会导致内存泄露的发生 。

72、抽象(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被 synchronized 修饰?(都不能)

都不能。抽象方法需要子类重写,而静态方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如 C 代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized 和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。

73、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?

不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化。

74、如何实现对象克隆?

以前使用的是,BeanUtils.copyProperties();,但后来了解到它是通过反射来获取对象并赋值,这样效率较低,然后就换成了 Mapstruct,它会在编译项目时,根据定义好的接口,自动创建一个接口的实现类,这个实现类里面会根据接口中方法的形参以及返回值,生成对应的实现方法

75、接口是否可继承接口?抽象类是否可实现接口?抽象类是否可继承具体类?(都可以)

接口可以继承接口 , 而且支持多重继承 。
抽象类可以实现接口,抽象类可继承具体类,也可以继承抽象类

76、匿名内部类是否可以继承其它类?是否可以实现接口?(都可以)

可以继承其他类或实现其他接口

77、Integer缓存机制

如下代码运行结果是?

		Integer i1 = new Integer(1);
        Integer i2 = new Integer(1);
        int i3 = 1;

        System.out.println("=====");
        System.out.println(i1 == i2);
        System.out.println(i1 == i3);

        Integer i4 = 2;
        Integer i5 = 2;
        int i6 = 2;
        System.out.println("=====");
        System.out.println(i4 == i5);
        System.out.println(i4 == i6);

        Integer i7 = 128;
        Integer i8 = 128;
        int i9 = 128;
        System.out.println("=====");
        System.out.println(i7 == i8);
        System.out.println(i7 == i9);

结果:

显示全文