【Java面试题】基础(包含个人心得总结)(方便理解记忆)

该博客围绕Java基础展开,涵盖Java特点、面向对象与面向过程区别、基本数据类型等内容。介绍了重载和重写、equals与==的差异,还提及集合类区别、四种引用类型、泛型特点等,同时讲解了创建对象方式、深拷贝和浅拷贝区别等,为Java面试提供知识储备。

目录

一、基础

1、Java都有哪些特点

2、面向对象和面向过程的区别

3、八种基本数据类型的大小,以及他们的封装

4、标识符和命名规则

5、重载和重写的区别

6、equals与==的区别

7、Hashcode的作用

8、String、String StringBuffer 和 StringBuilder 的区别是什么?

9、ArrayList和LinkedList的区别

10、HashMap和HashTable的区别

11、List,Set,Map三者的区别?

12、Collection包结构,与Collections的区别

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

14、泛型常用特点

15、Java创建对象有几种方式?

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

17、final有哪些用法?

18、static都有哪些用法?

19、有没有可能两个不相等的对象有相同的hashcode(哈希冲突) 

20、如何解决哈希冲突?

21、Object 有哪些常用方法?方法的含义    


一、基础

1、Java都有哪些特点

  1. 简单易学:Java的语法相对简单,与C++相比更容易学习和理解。

  2. 面向对象:Java是一种面向对象的编程语言,支持封装、继承和多态等面向对象的特性。

  3. 平台无关性:Java程序可以在不同的操作系统上运行,只需在目标平台上安装Java虚拟机(JVM)即可。

  4. 安全性:Java提供了安全机制,如字节码校验和安全管理器,可以防止恶意代码的执行。

  5. 强大的标准库:Java拥有丰富的标准类库,提供了大量的API,包括输入输出、网络通信、数据库连接等功能。

  6. 自动内存管理:Java使用垃圾回收机制来管理内存,开发者无需手动释放内存,减少了内存泄漏和野指针等问题。

  7. 多线程支持:Java提供了多线程编程的支持,可以方便地实现并发操作和多任务处理。

  8. 高性能:Java通过即时编译器(Just-In-Time Compiler)将字节码转换为机器码,提高了程序的执行效率。

  9. 开放源代码:Java的核心部分是开放源代码的,可以根据需要进行修改和定制。

2、面向对象和面向过程的区别

        面向对象:面向对象编程(Object-Oriented Programming,简称OOP)是一种以对象为基础的编程方法,它将数据和操作数据的函数封装在一起,形成一个称为对象的实体。面向对象编程强调的是对象之间的交互和消息传递,通过定义类和创建对象来实现程序的设计和开发。面向对象编程具有封装、继承和多态等特性,可以更好地组织和管理代码,提高代码的可重用性和可维护性。

        面向过程:面向过程编程(Procedural Programming)是一种以过程为中心的编程方法,它将程序分解为一系列的步骤或函数,通过函数的调用来实现程序的功能。面向过程编程强调的是算法和步骤的顺序执行,通过定义函数和使用全局变量来实现程序的设计和开发。面向过程编程相对简单直观,适用于一些简单的问题和小型项目。

        总结来说,面向对象编程注重对象和类的设计,强调封装、继承和多态等特性;而面向过程编程注重算法和步骤的设计,强调函数的调用和顺序执行。两者在程序设计思想、代码组织方式和开发方式上存在明显的区别。

3、八种基本数据类型的大小,以及他们的封装

基本类型大小(字节)默认值封装类
整型byte1(byte)0Byte
short2(short)0Short
int40Integer
long80LLong
浮点型float40.0fFloat
double80.0dDouble
布尔型boolean-falseBoolean
字符型char2\u000(null)Character

注:

        1、int是基本数据类型,Integer是int的封装类,是引用类型。int默认值是0,而Integer默认值 是null,所以Integer能区分出0和null的情况。一旦java看到null,就知道这个引用还没有指向某个对象,再任何引用使用前,必须为其指定一个对象,否则会报错。

        2、基本数据类型在声明时系统会自动给它分配空间,而引用类型声明时只是分配了引用空间, 必须通过实例化开辟数据空间之后才可以赋值。数组对象也是一个引用对象,将一个数组赋值给另 一个数组时只是复制了一个引用,所以通过某一个数组所做的修改在另一个数组中也看的见。

        3、虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有 任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java 虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素 boolean元素占8位。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字 节。使用int的原因是,对于当下32位的处理器(CPU)来说,一次处理数据是32位(这里是指的 是32/64位系统,而是指CPU硬件层面),具有高效存取的特点。

4、标识符和命名规则

在Java中,标识符是用来标识变量、方法、类、包等命名元素的名称。Java的标识符命名规则如下:

        1.标识符可以由字母、数字、下划线和美元符号组成。

        2.标识符必须以字母、下划线或美元符号开头,不能以数字开头。

        3.标识符区分大小写,例如"myVariable"和"myvariable"是不同的标识符。

        4.标识符不能是Java的关键字,例如"public"、"class"等。

        5.标识符应具有描述性,以便于理解和维护代码。

以下是一些符合Java标识符命名规则的示例:

        1.合法的标识符:myVariable, _count, $price, MAX_VALUE

        2.非法的标识符:2ndNumber, public, class

5、重载和重写的区别

        重载(Overloading)是指在同一个作用域内,可以有多个同名函数,但它们的参数列表不同。通过参数的类型、个数或顺序的不同,编译器可以区分它们,并根据调用时的参数类型来选择合适的函数进行调用。重载可以提高代码的可读性和灵活性。

        重写(Override)是指子类重新定义了父类中已有的方法。子类通过继承父类的方法,并在子类中重新实现该方法,以满足子类自身的需求。重写可以实现多态性,即通过父类引用指向子类对象时,调用的是子类中重写的方法。

区别:

  1. 定义:重载是指在同一个类中定义多个同名但参数列表不同的函数,以便根据不同的参数类型或个数来调用不同的函数。重写是指子类重新定义父类中已有的方法,以实现自己的功能需求。

  2. 发生的位置:重载发生在同一个类中,而重写发生在子类中。

  3. 参数列表:重载函数的参数列表必须不同,可以是参数类型不同、参数个数不同或者参数顺序不同。重写函数的参数列表必须与父类中被重写的方法完全相同。

  4. 返回类型:重载函数的返回类型可以相同也可以不同。重写函数的返回类型必须与父类中被重写的方法相同或者是其子类。

  5. 功能实现:重载函数通过参数列表的不同来区分,可以实现不同的功能。重写函数是为了改变父类方法的行为,实现自己特定的功能。

  6. 调用方式:重载函数根据参数类型或个数的不同来决定调用哪个函数。重写函数在多态的情况下,根据对象的实际类型来决定调用哪个方法。

6、equals与==的区别

        == 操作符用于比较两个对象的引用是否相等。也就是说,它比较的是对象在内存中的地址。如果两个对象的引用指向同一个内存地址,那么它们被认为是相等的;否则,它们被认为是不相等的。

        equals 方法用于比较两个对象的内容是否相等。默认情况下,equals 方法与 == 操作符的行为相同,即比较对象的引用。但是,可以通过重写 equals 方法来改变比较的方式。在重写 equals 方法时,通常会比较对象的属性值是否相等,而不仅仅是比较引用。

        需要注意的是,对于基本数据类型(如int、char等),== 操作符比较的是它们的值是否相等。而对于引用类型(如String、自定义类等),== 操作符比较的是它们的引用是否相等。

7、Hashcode的作用

        Hashcode是Java中的一个方法,它用于计算对象的哈希码。哈希码是一个整数值,用于快速确定对象在哈希表中的位置。Hashcode的作用主要有以下几个方面:

        1. 在集合中查找和存储:哈希码可以用于快速查找和存储对象。在使用HashSet、HashMap等集合类时,通过计算对象的哈希码可以确定对象在集合中的位置,从而提高查找和存储的效率。

        2. 对象相等性判断:哈希码也可以用于判断两个对象是否相等。在Java中,如果两个对象的哈希码相等,不一定表示它们相等,但如果两个对象不相等,它们的哈希码一定不相等。因此,在重写equals方法时,通常也需要重写hashCode方法,以保证对象相等时它们的哈希码也相等。

        3. 分布式系统中的数据分片:在分布式系统中,数据通常会被分散存储在不同的节点上。通过计算对象的哈希码,可以将数据均匀地分布到不同的节点上,从而实现负载均衡和高效的数据访问。

        4. 安全性校验:哈希码也可以用于安全性校验。例如,在密码存储时,通常会将密码的哈希码存储在数据库中,而不是明文密码。当用户输入密码时,系统会计算输入密码的哈希码,并与数据库中存储的哈希码进行比较,以验证密码的正确性。

8、StringString StringBuffer StringBuilder 的区别是什?

        1. String是不可变的,而StringBuffer和StringBuilder是可变的。这意味着在对String进行操作时,每次都会创建一个新的String对象,而对StringBuffer和StringBuilder进行操作时,可以在原有对象上进行修改,避免了频繁创建对象的开销。

        2. String是线程安全的,而StringBuffer是线程安全的,而StringBuilder是非线程安全的。这是因为String的不可变性使得它可以被多个线程共享而不会出现问题,而StringBuffer和StringBuilder的可变性使得它们需要考虑线程安全的问题。

        3. String拼接字符串时效率较低,而StringBuffer和StringBuilder拼接字符串时效率较高。由于String的不可变性,每次拼接字符串都会创建一个新的String对象,导致内存开销较大。而StringBuffer和StringBuilder通过修改原有对象来拼接字符串,避免了创建新对象的开销。

        综上所述,如果需要频繁对字符串进行修改操作,并且在多线程环境下使用,应该使用StringBuffer;如果在单线程环境下使用,并且对性能要求较高,可以使用StringBuilder;如果不需要修改字符串,并且需要保证线程安全,可以使用String。

9、ArrayList和LinkedList的区别

        ArrayList和LinkedList是中两种常见的集合,它们都实现了List接口,但在内部实现和性能方面有一些区别。

       注 :List是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式,它继承Collection

1. 内部实现:
        ArrayList:基于数组实现的动态数组,它可以自动扩容和缩容。当元素数量超过当前容量时,ArrayList会创建一个更大的数组,并将原数组中的元素复制到新数组中。
        LinkedList:基于双向链表实现的,每个节点都包含了当前元素的值以及指向前一个节点和后一个节点的引用。

2. 访问效率:
        ArrayList:访问效率较高,因为它可以通过索引直接访问元素,时间复杂度为O(1)。但在插入和删除元素时,需要移动其他元素,时间复杂度为O(n)。
        LinkedList:访问效率较低,因为它需要从头节点开始遍历链表,直到找到目标位置。但在插入和删除元素时,只需要修改节点的引用,时间复杂度为O(1)。

3. 内存占用:
        ArrayList:在内存中连续存储元素,因此占用的内存空间相对较小。
        LinkedList:在内存中不连续存储元素,每个节点都需要额外的空间存储前后节点的引用,因此占用的内存空间相对较大。

4. 适用场景:
        如果需要频繁地进行随机访问操作,例如根据索引获取元素或者修改元素的值,建议使用ArrayList
        如果需要频繁地进行插入和删除操作,例如在集合的开头或结尾插入或删除元素,建议使用LinkedList

        注:当然,这些对比都是指数据量很大或者操作很频繁。

10、HashMapHashTable的区别

 HashMap和HashTable都是用于存储键值对的数据结构,但它们之间有一些重要的区别:

1. 线程安全性:

        HashTable是线程安全的,而HashMap不是HashTable的方法都是同步的,可以在多线程环境下使用,但这也导致了性能上的一些损失。而HashMap在多线程环境下需要额外的同步措施来保证线程安全。

2. 允许空键值:

        HashMap允许键和值都为null,而HashTable不允许。如果在HashMap中插入null键或null值,它们会被正常处理。但在HashTable中,如果尝试插入null键或null值,会抛出NullPointerException。

3. 迭代器:

        HashMap的迭代器是fail-fast的,即在迭代过程中如果其他线程修改了HashMap的结构,会抛出ConcurrentModificationException异常。而HashTable的迭代器不是fail-fast的,不会抛出异常。

4. 初始容量和扩容机制:

        HashMap的初始容量和扩容机制更加灵活。可以通过构造函数指定初始容量,并且在容量不足时会自动扩容。而HashTable的初始容量固定为11,并且在容量不足时会自动扩容为原来的两倍加一。

5. 继承关系:

        HashMap继承自AbstractMap类,而HashTable继承自Dictionary类。

11、List,Set,Map三者的区别?

        List、Set和Map是Java集合框架中的三个常用接口,它们分别用于存储和操作不同类型的数据。

1. List:
           - List是一个有序的集合,可以包含重复的元素。
           - List允许通过索引访问元素,可以根据元素的位置进行增删改查操作。
           - 常见的List实现类有ArrayList和LinkedList。

2. Set:
           - Set是一个不允许包含重复元素的集合。
           - Set不保证元素的顺序,即不按照插入顺序或者排序顺序进行存储。
           - Set提供了判断元素是否存在的方法,可以用于去重。
           - 常见的Set实现类有HashSet和TreeSet。

3. Map:
           - Map是一种键值对的映射表,每个键对应一个值。
           - Map中的键是唯一的,但值可以重复。
           - Map提供了根据键获取值的方法,也可以根据键删除或更新对应的值。
           - 常见的Map实现类有HashMap和TreeMap。

总结:
        - List适用于需要按照顺序存储和访问元素的场景,允许重复元素。
        - Set适用于需要去重的场景,不保证元素的顺序。
        - Map适用于需要根据键值对进行存储和访问的场景,键是唯一的。

12、Collection包结构,与Collections的区别

        Collection是集合类的上级接口,子接口有 Set、List、LinkedList、ArrayList、Vector、Stack、

Set;

        Collections是集合类的一个帮助类, 它包含有各种有关集合操作的静态多态方法,用于实现对各种 集合的搜索、排序、线程安全化等操作。此类不能实例化,就像一个工具类,服务于Java的 Collection框架。

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

Java中有四种引用类型,它们分别是强引用软引用弱引用虚引用

        1. 强引用(Strong Reference):是最常见的引用类型,如果一个对象具有强引用,那么垃圾回收器绝不会回收它。即使内存不足时,JVM也会抛出OutOfMemoryError而不是回收这些对象。

        2. 软引用(Soft Reference):是一种相对强引用弱化一些的引用类型。如果一个对象只有软引用,那么在内存不足时,垃圾回收器可能会回收它。软引用通常用于实现内存敏感的缓存。

        3. 弱引用(Weak Reference):是比软引用更弱化的引用类型。如果一个对象只有弱引用,那么在下一次垃圾回收时,无论内存是否充足,都会被回收。弱引用通常用于实现一些特定的功能,如监视对象是否已被回收。

        4. 虚引用(Phantom Reference):是最弱化的引用类型。虚引用主要用于跟踪对象被垃圾回收的状态,无法通过虚引用访问对象的任何属性或方法。虚引用必须与引用队列(ReferenceQueue)一起使用。

        

14、泛型常用特点

        泛型是一种编程语言的特性,它允许我们编写可以适用于多种数据类型的代码。以下是泛型的常用特点:

        1. 参数化类型:泛型允许我们在定义类、接口或方法时使用参数来表示类型,这样可以在使用时指定具体的类型。例如,我们可以定义一个泛型类`List<T>`,其中的`T`可以代表任意类型。

        2. 类型安全:泛型在编译时进行类型检查,可以确保代码在运行时不会出现类型错误。这样可以减少运行时错误的可能性,并提高代码的可靠性。

        3. 代码复用:通过使用泛型,我们可以编写通用的代码,可以在不同的数据类型上进行操作,而不需要为每种数据类型编写重复的代码。这样可以提高代码的复用性和可维护性。

        4. 高效性:泛型在编译时进行类型擦除,即将泛型类型转换为其原始类型,这样可以减少运行时的开销。同时,泛型还可以提供更好的性能,因为它避免了装箱和拆箱操作。

15、Java创建对象有几种方式?

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

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

        深拷贝浅拷贝是在编程中用于复制对象的两种不同方式。

        浅拷贝:是指创建一个新对象,将原始对象的成员变量的值复制到新对象中。但是,如果原始对象的成员变量是引用类型,那么浅拷贝只会复制引用,而不会创建新的引用对象。这意味着原始对象和浅拷贝对象将共享相同的引用对象。因此,对其中一个对象进行修改可能会影响到另一个对象。

        深拷贝:则是创建一个新对象,并将原始对象的所有成员变量的值复制到新对象中,包括引用类型的成员变量。这意味着深拷贝会创建新的引用对象,而不是共享原始对象的引用。因此,对其中一个对象进行修改不会影响到另一个对象。

总结一下:
        - 浅拷贝只复制引用,共享相同的引用对象。
        - 深拷贝复制所有成员变量的值,包括引用类型,创建新的引用对象。

17、final有哪些用法?

        final关键字在Java中有以下几种用法:

        1. final修饰类:当一个类被final修饰时,表示该类不能被继承,即该类是最终类,不能有子类。

        2. final修饰方法:当一个方法被final修饰时,表示该方法不能被子类重写,即该方法是最终方法,子类不能对其进行修改。

        3. final修饰变量:当一个变量被final修饰时,表示该变量是一个常量,一旦被赋值后就不能再改变。

        4. final修饰引用类型变量:当一个引用类型变量被final修饰时,表示该变量的引用地址不能改变,但是可以修改引用对象的属性。

        5. final修饰参数:当一个参数被final修饰时,表示该参数在方法内部不能被修改。

18、static都有哪些用法?

        static关键字在Java中有以下几种用法:

        1. 静态变量:使用static修饰的变量称为静态变量,也叫类变量。静态变量属于类,而不是属于类的实例。静态变量在类加载时被初始化,并且只有一份拷贝,所有实例共享该变量的值。可以通过类名直接访问静态变量。

        2. 静态方法:使用static修饰的方法称为静态方法,也叫类方法。静态方法属于类,而不是属于类的实例。静态方法可以直接通过类名调用,无需创建类的实例。静态方法只能访问静态成员(包括静态变量和静态方法),不能访问非静态成员。

        3. 静态代码块:使用static关键字定义的代码块称为静态代码块。静态代码块在类加载时执行,并且只会执行一次。静态代码块常用于初始化静态变量或执行一些只需执行一次的操作。

        4. 静态内部类:使用static修饰的内部类称为静态内部类。静态内部类与外部类没有直接的关联,可以直接通过外部类名访问。静态内部类可以拥有自己的静态成员,但不能访问外部类的非静态成员。

        5. 静态导入:使用static关键字可以导入类的静态成员,使得在使用时可以省略类名。例如,可以使用"import static java.lang.Math.*;"来导入Math类的所有静态成员,然后直接使用Math类的静态方法和常量。

        需要注意的是,静态成员属于类级别的,不依赖于类的实例化。因此,在使用静态成员时要注意遵循相关的访问规则和限制。

19、有没有可能两个不相等的对象有相同的hashcode(哈希冲突) 

        是的,有可能两个不相等的对象具有相同的哈希码。这种情况被称为哈希冲突。哈希冲突是指不同的对象在经过哈希函数计算后得到相同的哈希码。哈希函数是将对象映射到一个整数值的函数,而哈希码是这个整数值。

        在Java中,每个对象都有一个默认的hashCode()方法实现,它返回对象的哈希码。默认情况下,hashCode()方法是根据对象的内存地址计算得到的。然而,由于哈希码的范围是有限的,而对象的数量是无限的,所以在某些情况下会出现不同对象具有相同哈希码的情况。

        为了解决哈希冲突,Java中的哈希表数据结构(如HashMap、HashSet等)使用了链表或者红黑树等数据结构来存储具有相同哈希码的对象。当发生哈希冲突时,这些数据结构会将具有相同哈希码的对象存储在同一个桶中,并通过equals()方法来判断它们是否真正相等。

        因此,尽管两个不相等的对象可能具有相同的哈希码,但它们仍然可以通过equals()方法进行区分。在使用哈希表数据结构时,equals()方法用于判断两个对象是否相等,而哈希码则用于确定对象在哈希表中的位置。

    

20、如何解决哈希冲突?

        哈希冲突是指在哈希表中,不同的键值经过哈希函数计算后得到相同的索引位置。解决哈希冲突的常用方法有以下几种:

        1. 链地址法(拉链法):将哈希表的每个位置设置为链表的头节点,当发生哈希冲突时,将冲突的元素插入到对应位置的链表中。这样可以解决冲突,并且可以存储大量的元素。

        2. 开放地址法:当发生哈希冲突时,通过一定的探测方法找到下一个可用的位置。常见的探测方法有线性探测、二次探测和双重哈希等。线性探测是指依次往后查找,直到找到一个空闲位置;二次探测是指通过二次方程计算下一个位置;双重哈希是指使用第二个哈希函数来计算下一个位置。

        3. 再哈希法:当发生哈希冲突时,使用另一个哈希函数重新计算索引位置。如果仍然发生冲突,可以继续使用其他哈希函数进行再哈希,直到找到一个空闲位置。

        4. 建立公共溢出区:将所有发生冲突的元素都放在同一个溢出区中,需要时进行查找。这种方法可以解决冲突,但是查找效率会降低。

        以上是常见的解决哈希冲突的方法,选择哪种方法取决于具体的应用场景和需求。在实际应用中,可以根据数据量、数据分布情况和性能要求等因素来选择合适的解决方法。

21、Object 有哪些常用方法?方法的含义    

        Object类是Java中所有类的根类,它定义了一些常用的方法。下面是Object类的一些常用方法及其含义:

        1. equals(Object obj):判断当前对象是否与给定对象相等。默认情况下,equals方法比较的是对象的引用是否相等,即是否指向同一个内存地址。如果需要比较对象的内容是否相等,需要在具体类中重写equals方法。

        2. hashCode():返回当前对象的哈希码值。哈希码是根据对象的内部状态计算得出的一个整数值,用于快速查找和比较对象。在重写equals方法时,通常也需要重写hashCode方法。

        3. toString():返回当前对象的字符串表示。默认情况下,toString方法返回的是对象的类名和哈希码值的组合。可以根据需要在具体类中重写toString方法,以便返回更有意义的字符串表示。

        4. getClass():返回当前对象所属的类的Class对象。Class对象包含了关于类的各种信息,可以用于获取类的名称、字段、方法等。

        5. clone():创建并返回当前对象的一个副本。默认情况下,clone方法会创建一个浅拷贝,即只复制对象的引用而不复制对象本身。如果需要实现深拷贝,需要在具体类中重写clone方法。

        6. finalize():在垃圾回收器回收对象之前调用。可以在具体类中重写finalize方法,以便在对象被销毁之前执行一些清理操作。

        以上是Object类的一些常用方法及其含义。需要注意的是,这些方法都是被所有类继承的,因此可以在任何类的对象上调用这些方法。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值