java基础一

标识符和关键字

标识符是用来表示变量、函数、类等命名实体的名称。它由一系列字符组成,可以包含字母、数字和下划线,并且必须以字母或下划线开头。

关键字是具有特殊意义的单词。这些单词被保留,不能用作标识符来命名变量、函数或类等。

java关键字有哪些

有访问修饰符关键字,如public,private等

有定义类、接口的关键字,如class,interface

还有用于控制程序流程和用于声明不同的数据类型的关键字

还有用于修饰类、方法、属性和变量的关键字等如final,static等

数据类型

java的几种基本数据类型了解吗

Java 中有 8 种基本数据类型,分别为:

  • 6 种数字类型:
    • 4 种整数型:byteshortintlong
    • 2 种浮点型:floatdouble
  • 1 种字符类型:char
  • 1 种布尔型:boolean

基本类型和包装类型的区别

基本类型是 Java 中的八种原始数据类型,它们直接存储数据的值, 而包装类型是基本类型的对象。

  • **基本类型的局部变量 存放在 栈 中,直接存储数据值。而未被static修饰的基本类型的成员变量 存放在 堆 中,作为对象的一部分。包装类型是对象,存放在 堆 中, 并且包装类型在使用时会涉及到对象的创建和销毁。 **
  • 包装类型适合需要对象的场景,比如集合类、反射等;基本类型适合更高效的运算和数据存储。 并且,包装类型可用于泛型,而基本类型不可以
  • 默认值:包装类型不赋值就默认为 null ,而基本类型有默认值且不可以是 null
  • 比较方式:对于基本数据类型来说,==** 比较的是值。对于包装数据类型来说,== 比较的是对象的内存地址**。

为什么说是几乎所有对象实例都存在于堆中呢?(=> 还有对象存于栈中)

这是因为 HotSpot 虚拟机引入了 JIT(即时编译) 优化之后,会对对象进行逃逸分析,确定一个对象是否会在其被分配的方法之外被引用(即“逃逸”),即帮助JVM确定一个对象的作用域是否仅限于当前线程和方法调用,如果发现某一个对象并没有逃逸到方法外部,那么就可能通过标量替换逃逸分析确定一个对象不会逃逸时,JVM可能会将这个对象分解成一组标量字段,并将这些字段直接在栈上分配,而不是作为一个整体对象在堆上分配。来实现栈上分配,而避免堆上分配内存

⚠️ 注意:基本数据类型存放在栈中是一个常见的误区! 基本数据类型的存储位置取决于它们的作用域和声明方式。如果它们是局部变量,那么它们会存放在栈中;如果它们是成员变量,那么它们会存放在堆/方法区/元空间中。

包装类型的缓存机制了解吗

包装类型的缓存机制是指Java虚拟机为了优化性能和节省内存,会对一定范围内的包装类型对象进行缓存。当需要这些数值的包装类型对象时,JVM会直接从缓存池中返回已经存在的对象,而不是每次都创建一个新的对象。

比如Byte,Short,Integer,Long 这 4 种包装类通常缓存了从-128到127之间的数值。,Character 缓存了 [0, 127] 范围的字符 Boolean 直接返回 True or False, 而 FloatDouble 没有缓存机制,因为它们的数值范围大,缓存效果不明显。

自动装箱与拆箱了解吗?原理是什么?

自动装箱是 Java 自动将基本类型转换为包装类对象的过程;拆箱是将包装类对象转换为基本类型。

装箱其实就是调用了 包装类的valueOf()方法,比如 Integer.valueOf() 。拆箱其实就是调用了 <font style="color:#3c3c43;">xxxValue()</font>方法,比如 intValue() 。

为什么浮点数运算的时候会有精度丢失的风险?

计算机中的浮点数是使用二进制表示的, 无法精确表示所有的小数 ,这就导致了计算时的误差。例如,0.1 在二进制中是一个无限循环的小数,计算机会以有限的位数存储它,从而被截断,产生了微小的误差。而且在浮点数运算过程中,某些结果需要进行舍入。也会导致精度丢失的风险。

如何解决浮点数运算的精度丢失问题?

可以使用BigDecimal 类进行浮点数的运算,BigDecimal 提供了任意精度的浮点数运算,可以避免浮点数的精度丢失问题。

还可以通过将所有的浮点数转换为整数来避免精度丢失。通常做法是将小数转化为整数,然后进行运算,最后再转换回小数。

变量

成员变量和局部变量的区别

  • 语法形式:从语法形式上看,成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
  • 存储方式:从变量的存储方式来看, 成员变量中的静态变量,存储在堆内存中实例变量存储于方法区中,而局部变量则存在于栈内存
  • 生存时间:从变量的生命周期来看, 成员变量随着对象的创建而分配内存,随着对象的销毁而释放内存。 而局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡。
  • 默认值:从变量是否有默认值来看,成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值(一种情况例外:被 final 修饰的成员变量也必须显式地赋值),而局部变量必须在使用前初始化,JVM 不会为局部变量分配默认值。

为什么成员变量有默认值?

  1. 默认值避免了未初始化的成员变量存储随机值,从而确保程序运行时的稳定性。
  2. 对于成员变量,它们的初始化可能是在运行时进行的(例如通过构造函数或其他方法),编译器无法在编译时判断是否被初始化。因此,如果不自动赋予默认值,编译器就无法判断这些成员变量是否已被初始化,这可能会导致错误或者不一致的行为。为了避免这种问题,JVM 采用了自动赋予默认值的策略。

静态变量有什么作用?

  • 静态变量也就是被 static 关键字修饰的变量。 它属于类而不是类的实例。静态变量在类加载时初始化,并且在类的所有实例中共享。 也就是说,不管创建多少个类的实例,静态变量只有一份存储空间。
  • 静态变量不依赖于类的实例化,它属于类本身。可以直接通过类名来访问静态变量,而不需要创建类的实例。

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

  • 形式 : 字符型常量是一个单一的字符,使用单引号 (') 包裹 。字符串常量是一个字符的序列,使用双引号 (") 包裹。
  • 存储方式不同 : 字符型常量在内存中作为 char 类型存储,每个字符占用 2 个字节。字符串常量的数据类型是 String ,它是一个对象类型 ,实际上是一个字符数组, 可以用来表示多个字符。

方法

静态方法为什么不能调用非静态成员?

静态方法是属于类的,而不是类的实例。在类加载时就可以被调用,无需创建对象。

非静态成员是属于对象的。它们在类的实例化时才会被分配内存,意味着非静态成员是属于某个对象实例的。

当类的静态方法被调用时,对象实例还没有被创建。因此,静态方法调用时,并不能直接访问与某个实例相关的非静态成员,如实例变量和实例方法。

静态方法和实例方法有何不同?

  • 静态方法属于本身,而不是类的实例。 可以通过类名直接调用,不需要创建类的实例。
  • 实例方法属于对象实例,必须在创建对象之后才能使用,且需要通过类的实例来调用,
  • 静态方法只允许访问静态成员,不允许访问实例成员,而实例方法不存在这个限制。
  • 静态方法的生命周期与类的生命周期相关,它在类加载时加载,直到类卸载时销毁。
  • 实例方法的生命周期与对象的生命周期相关,只有当对象被创建时,实例方法才会存在,并在对象销毁时随之销毁。

重载和重写有什么区别?

  • 重载(Overloading)指的是在同一个类中,或者父类和子类之间,方法名相同,但参数列表不同的方法。这是编译时多态的一种体现。
  • 重写(Overriding)指的是在子类中重新定义父类的方法,方法名、参数列表必须完全相同。这是运行时多态的一种体现。
  • 重载的访问修饰符没有限制,可以不同。
  • 而子类重写父类方法时,子类的方法的访问权限不能低于父类方法。且父类方法访问修饰符为 private/final/static 时,则子类就不能重写该方法
  • 重载时返回类型可以不同,而重写时返回类型必须与父类相同或是父类的子类。
  • 构造方法可以重载,但不能被重写。

什么是可变长参数?

可变长参数(Varargs)是 Java 中的一种语法特性,允许在方法中传递不定数量的参数。使用可变长参数时,调用者可以传递任意数量的参数,甚至不传递任何参数。编译器会自动将这些参数转换为数组。

且可变长参数必须是方法参数列表中的最后一个参数

遇到方法重载的情况怎么办呢?会优先匹配固定参数还是可变参数的方法呢?

答案是会优先匹配固定参数的方法,因为固定参数的方法匹配度更高。

另外,Java 的可变参数编译后实际会被转换成一个数组,我们看编译后生成的 class文件就可以看出来了。


java基础一
https://xichicheng.github.io/2024/11/21/java-基础一/
作者
陈兮迟
发布于
2024年11月21日
许可协议