一天十道Java面试题----第一天(面向对象-------》ArrayList和LinkedList)

简介: 这篇文章是关于Java面试的笔记,涵盖了面向对象、JDK/JRE/JVM的区别、`==`和`equals`、`final`关键字、`String`、`StringBuffer`和`StringBuilder`的区别、重载与重写、接口与抽象类、`List`与`Set`、`hashcode`与`equals`以及`ArrayList`和`LinkedList`的对比等十个主题。

这里是参考B站上的大佬做的面试题笔记。大家也可以去看视频讲解!!!

文章目录

  • 1、面向对象
  • 2、JDK、JRE、JVM区别和联系
  • 3、==和equals
  • 4、final
  • 5、String 、StringBuffer、StringBuilder区别及使用场景
  • 6、重载和重写的区别
  • 7、接口和抽象类
  • 8、List和Set
  • 9、hashcode和equals
  • 10、ArrayList和Linkedlist

1、面向对象

1.1、 什么是面向对象?

对比面向过程、是两种不同的处理问题的角度
面向过程更注重事情的没一个步骤及顺序,面向对象更注重事情有哪些参与者(对象),及各自需要做什么。

例如:洗衣机洗衣服

  • 面向过程会将任务拆解成一系列的步骤(函数),1、打开洗衣机---->2、放衣服------>3、放洗衣粉---->4、清洗------>5、烘干
  • 面向对象会拆出人和洗衣机两个对象:人:打开洗衣机,放衣服,放洗衣粉。洗衣机:清洗、烘干

从以上例子可以看出:面向过程比较直观高效,而面向对象更易于复用,扩展和维护。

1.2 、面向对象

封装

  • 封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,内部细节对外部调用透明,外部调用无需修改或者关心内部实现。

  • 1、javabean的属性私有,提供get/set对外访问,因为属性的赋值或者获取逻辑只能由javabean本身决定,而不能由外部胡乱修改。

  • 2、orm框架:操作数据库,我们不需要关心链接时如何建立的,sql时如何执行的,只需要引入mybatis,调方法即可。

继承

  • 继承基类的方法,并做出自己的改变或扩展
  • 子类共性的方法或者属性直接使用父类的,而不需要自己再定义,只需扩展自己个性化的

多态

  • 基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。
  • 继承,方法重写,父类引用指向子类对象
  • 父类类型 变量名 = new 子类对象;
  • 变量名.方法名();

无法调用子类特有的功能

2、JDK、JRE、JVM区别和联系

JDK:

  • java Develpment Kit java 开发工具

JRE:

  • java Runtime Environment java 运行时环境

JVM:

  • java Virtual Machine java 虚拟机

在这里插入图片描述

在这里插入图片描述

3、==和equals

  • 对比的时栈中的值,基本数据类型是变量值,引用类型是堆中内存对象的地址
  • equals:object中默认也是采用比较,通常会重写
  • String类中被复写的equals()方法其实是比较两个字符串的内容

举例

    @Test
    void test(){
        String str1 = "hello";
        String str2 = new String("hello");
        String str3 = str2;//引用传递
        System.out.println("123");
        System.out.println("(str1 == str2):"+(str1 == str2));//false
        System.out.println("(str1 == str3):"+(str1 == str3));//false
        System.out.println("(str2 == str3):"+(str2 == str3));//true
        System.out.println("str1.equals(str2):"+str1.equals(str2));//true
        System.out.println("str1.equals(str3):"+str1.equals(str3));//true
        System.out.println("str2.equals(str3):"+str2.equals(str3));//true
    }

在这里插入图片描述

4、final

4.1、简述final作用
最终的

  • 修饰类:表示类不可被继承
  • 修饰方法:表示方法不可被子类覆盖,但是可以重载
  • 修饰变量:表示变量一旦被赋值就不可以更改它的值。

(1) 、 修饰成员变量

  • 如果final修饰的类变量,只能在静态初始化块中指定初始值或声明该类变量时指定初始值
  • 如果final修饰的是成员变量,可以在非静态初始化块,声明该变量或者构造器中执行初始值。

(2) 、修饰局部变量

系统不会为局部变量进行初始化,局部变量必须由程序员显示初始化,因此使用final修饰局部变量时,即可以在定义时指定默认值(后面的代码不能对变量再赋值),也可以不指定默认值,而在后面的代码中对final变量赋初值(仅一次)

(3) 、修饰基本类型数据和引用类型数据

  • 如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改
  • 如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象,但是引用的值是可以改变的

4.2 、为什么局部内部类和匿名内部类只能访问局部final变量?

首先需要知道的一点是:内部类和外部类是处于同一个级别的,内部类不会因为定义在方法中就会随着方法的执行完毕就被销毁。

这里就会产生问题:当外部类的方法结束时,局部变量就会被销毁,但是内部类对象可能还存在(只有没有人再引用它时,才会死亡)。这里就出现了一个矛盾:内部类对象访问了一个不存在的变量。为了解决这个问题,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后,内部类仍可以访问它,实际访问的是局部变量的copy,这样好像就延长了局部变量的生命周期。

将局部变量复制为内部类的成员变量时,必须保证这两个变量是一样的,也就是如果我们再内部类中修改了成员变量,方法中的局部变量也得跟着改变,怎样解决问题呢?

就将局部变量设置为final、对它初始化之后,我就不让你再去修改这个变量,就保证了内部类的成员变量和方法的局部变量的一致性,这实际上也是一种妥协,使得局部变量与内部类内建立的拷贝保持一致性。

5、String 、StringBuffer、StringBuilder区别及使用场景

  • String是final修饰的、不可变、每次操作都会产生新的String对象
  • StringBuffer和StringBuilder都是在原对象上操作
  • StringBuffer是线程安全的,StringBuilder线程不安去的
  • StringBuffer方法都是synchronized修饰的

性能:StringBuilder > StringBuffer > String

场景:经常需要改变字符串内容时使用后面两个
优先使用StringBuilder,多线程使用共享变量时使用StringBuffer

6、重载和重写的区别

  • 重载:发生在同一个类中,方法名必须相同,参数类型不同,顺序不同,方法的返回值和访问修饰符可以不同,发生在编译时期。
  • 重写:发生在父子类中,方法名,参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类。访问修饰符范围大于等于父类;如果父类方法访问修饰符为private则子类就不能重写该方法。

7、接口和抽象类

  • 抽象类可以存在普通成员函数,而接口中只能存在public abstract方法
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final 类型的
  • 抽象类只能继承一个,接口可以实现多个。

接口的设计目的,是对类的行为进行约束(更准确的说是一种“有”约束,因为接口不能规定类不可以有什么行为),也就是提供一种机制,可以强制要求不同的类具有相同的行为,它只约束了行为的有无,但不对如何实现行为进行限制。

而抽象类的设计目的,是代码复用。当不同的类具有某些相同的行为(记为行为集合),且其中一部分行为的实现方式一致时(A的非真子集,记为B)可以让这些类都派生与一个抽象类,在这个抽象类中实现了B,避免让所有的子类来实现B,这就达到了代码复用的目的。而A减去B的部分,留给各个子类自己实现,正是因为A-B在这里没有实现,所以抽象类不允许实例化出来(否则当调用到A-B时,无法执行)。

抽象类是对类本质的抽象,表达的是is-a的关系,比如:BMW is a car 。抽象类包含并实现子类的通用特性,将子类存在差异化的特性进行抽象,交由子类去实现。

而接口是对行为的抽象,表达的是like a的关系,比如:bird like a aircraft(像飞行器一样飞),但其本质上 is a bird 。接口的核心是定义行为,至于实现主体是谁,是如何实现,接口并不关心。

使用场景:当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口

抽象类的能力要远超过接口,但是,定义抽象类的代价高,因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类,在这个类中,你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述,而且你可以在一个类中同时实现多个接口,在设计阶段会降低难度

8、List和Set

  • List:有序、按对象进入的顺序保存对象,可重复,允许多个Null元素对象,可以使用iterator取出所有元素,在逐一遍历,还可以使用get(int index)获取指定下的元素。
  • Set:无序、不可重复、最多允许有一个Null元素对象,取元素时只能用iterator接口取得所有的元素,在逐一遍历各个元素。
**铁汁们、铁汁们、铁汁们、都看到这里了、动动可爱的小手、点个赞呗、鼓励一下。哈哈哈**

9、hashcode和equals

hashcode介绍

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

为什么要有hashcode

以“HashSet如何检查重复”为例子来说明为什么要有hashcode:

对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,看该位置是否有值,如果没有、HashSet会假设对象没有重复出现。但是如果发现有值,这时会调用equals()方法来检查两个对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样就大大减少了equals的次数,相应就大大提高了执行速度。

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

10、ArrayList和Linkedlist

ArrayList:

  • 基于动态数组,连续内存存储,适合下标访问(随机访问),扩容机制:因为数组长度固定,超出长度存数据时需要新建数组,然后将老数组的数据拷贝到新数组,如果不是尾部插入数据还会涉及到元素的移动(往后复制一份,插入新元素),使用尾插法并指定初始容量可以极大提升性能甚至超过LinkedList(需要创建大量的index对象)

LinkedList:

  • 基于链表,可以存储在分散的内存中,适合做数据插入及删除操作,不适合查询;需要逐一遍历,遍历LinkedList必须使用iterator不能使用for循环,因为每次for循环体内通过get(i)取得某一元素时都需要对list重新遍历,性能消耗极大。
    另外不要试图使用index()等返回元素索引,并利用其进行遍历,使用indexof对list进行了遍历,当结果为空时会遍历整个列表
相关文章
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
15 2
|
8天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
13天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
9天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
33 4
|
10天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
50 4
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
67 2
|
1月前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
28 0
|
3月前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
3月前
|
Java
【Java基础面试三十七】、说一说Java的异常机制
这篇文章介绍了Java异常机制的三个主要方面:异常处理(使用try、catch、finally语句)、抛出异常(使用throw和throws关键字)、以及异常跟踪栈(异常传播和程序终止时的栈信息输出)。