javase基础面试题

java基础

java基本数据类型

image-20220712182642626

boolean类型占8个字节; 1位

字符型数据(char)用于存储单个字符,字符以代码形式存储。字符数据类型是16位,最小值为0,最大值为

*65535**。

 

下面的程序有问题吗?

public static void main(String[] args)
{ byte b1=1; byte b2=2; byte b3=1 + 2;
byte b4=b2 + b3; System.out.println(b3);
System.out.println(b4); }

分析: b3 = 1 + 2 , 1 和 2 是常量,为固定不变的数据,在编译的时候(编译器javac),已经确定了 1+2 的结果并没 有超过byte类型的取值范围,可以赋值给变量 b3 ,因此 b3=1 + 2 是正确的。 反之, b4 = b2 + b3 , b2 和 b3 是变量,变量的值是可能变化的,在编译的时候,编译器javac不确定b2+b3的结果是什 么,因此会将结果以int类型进行处理,所以int类型不能赋值给byte类型,因此编译失败。

封箱和拆箱?

基础类型属于数据,不属于类,自然也不属于Object的子类,无法使用相关方法。装箱就是自动将基本数据类型转换为包装器类型,拆箱就是自动将包装器类型装换为基本数据类型。

eg:Integer a = Integer.valueOf(123); //装箱 int b = a.intValue(); //拆箱

String、StringBuffer 1.0、Stringbuilder有什么区别

StringBuffer:线程安全

StringBuilder:线程不安全

得分点 字符串是否可变,StringBuffer、StringBuilder线程安全问题

标准回答 Java中提供了String,***StringBuffer**两个类来封装字符串,并且提供了一系列方法来操作字符串对象。 String是一个不可变类,也就是说,一个String对象创建之后,直到这个对象销毁为止,对象中的字符序列都不能被改变。 StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer对象被创建之后,我们可以通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()、等方法来改变这个字符串对象的字符序列。当通过StringBuffer得到期待中字符序列的字符串时,就可以toString()方法将其转换为String对象。 StringBuilder类是JDK1.5中新增的类,他也代表了字符串对象。和StringBuffer类相比,它们有共同的父类AbstractStringBuilder,二者无论是构造器还是方法都基本相同,不同的一点是,StringBuilder没有考虑线程安全问题,也正因如此,StringBuilder比StringBuffer性能略高。因此,如果是在单线程下操作大量数据,应优先使用StringBuilder类;如果是在多线程下操作大量数据,应优先使用Stringbuffer类。

请你说说HashMap底层原理

在1.8之前,HashMap的底层是数组加链表,在1.8之后是数组+链表+红黑树; 它的put流程是:基于哈希算法来确定元素位置,当我们向集合存入数据时,他会计算传入的key的哈希值,并利用哈希值取绝对值再根据集合长度取余来确定元素的位置,如果这个位置已经存在其他元素了,就会发生哈希碰撞,则hashmap就会通过链表将这些元素组织起来,如果链表的长度达到8时,就会转化为红黑树,从而提高查询速度。

扩容机制:HashMap中数组的默认初始容量为16,当达到默认负载因子0.75时,会以2的指数倍进行扩容。 Hashmap是非线程安全的,在多线程环境下回产生循环死链,因此在多线程环境下建议使用ConcurrentHashMap。

请你说一下抽象类和接口的区别

 

描述特征我们一般用接口 描述概念我们一般用抽象类

接口和抽象类相同点有: - 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其它类实现和继承 - 接口和抽象类都可以有抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法 在用法上,接口和抽象类也有如下差异: - 接口里只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类则可以包含普通方法。 - 接口里只能定义静态常量,不能定义普通成员变量;抽象类里既可以定义普通成员变量,也可以定义静态常量 - 接口里不包含构造器;抽象类可以包含构造器,但抽象类的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作 - 接口里不能包含初始化块,抽象类则可以包含初始化块 - 一个类最多只能有一个父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足 总之,接口通常是定义允许多个实现的类型的最佳途径,但当演变的容易性比灵活性和功能更加重要时,应该使用抽象类来定义类型。

请你说说==与equals()的区别

== 用于基本数据类型的比较 equals()不能用于基本数据类型的比较 比较基本数据类型时,比较的是两个数值是否相等; 比较引用类型是,比较的是对象的内存地址是否相等。 equals() 没有重写时,Object默认以==来实现,即比较两个对象的内存地址是否相等; 重写以后,按照对象的内容进行比较

请你说说聚簇索引和非聚簇索引

两者主要区别是数据和索引是否分离。聚簇索引是将数据与索引存储到一起,找到索引也就找到了数据;而非聚簇索引是将数据和索引存储分离开,索引树的叶子节点存储了数据行的地址。 在InnoDB中,一个表有且仅有一个聚簇索引(因为原始数据只留一份,而数据和聚簇索引在一起),并且该索引是建立在主键上的,即使没有指定主键,也会特殊处理生成一个聚簇索引;其他索引都是辅助索引,使用辅助索引访问索引外的其他字段时都需要进行二次查找。 而在MyISAM中,所有索引都是非聚簇索引,叶子节点存储着数据的地址,对于主键索引和普通索引在存储上没有区别。 加分回答 在InnoDB存储引擎中,可以将B+树索引分为聚簇索引和辅助索引(非聚簇索引)。无论是何种索引,每个页的大小都为16KB,且不能更改。 聚簇索引是根据主键创建的一棵B+树,聚簇索引的叶子节点存放了表中的所有记录。辅助索引是根据索引键创建的一棵B+树,与聚簇索引不同的是,其叶子节点仅存放索引键值,以及该索引键值指向的主键。也就是说,如果通过辅助索引来查找数据,那么当找到辅助索引的叶子节点后,很有可能还需要根据主键值查找聚簇索引来得到数据,这种查找方式又被称为书签查找。因为辅助索引不包含行记录的所有数据,这就意味着每页可以存放更多的键值,因此其高度一般都要小于聚簇索引。

什么是反射

通过反射机制,: - 程序运行时,可以通过反射获得任意一个类的Class对象,并通过这个对象查看这个类的信息; - 程序运行时,可以通过反射创建任意一个类的实例,并访问该实例的成员; - 程序运行时,可以通过反射机制生成一个类的动态代理类或动态代理对象

反射就是在程序运行期间动态的获取对象的属性和方法的功能叫做反射。它能够在程序运行期间,对于任意一个类,都能知道它所有的方法和属性,对于任意一个对象,都能知道他的属性和方法。 获取Class对象的三种方式:getClass();xx.class;Class.forName("xxx"); 反射的优缺点: 优点:运行期间能够动态的获取类,提高代码的灵活性缺点:性能比直接的Java代码要慢很多。 应用场景:spring的xml配置模式,以及动态代理模式都用到了反射。

请你说说hashCode()和equals()的区别,为什么重写equals()就要重写hashcod()

1、hashCode():获取哈希码,equals():比较两个对象是否相等。 2、二者两个约定:如果两个对象相等,它们必须有相同的哈希码;若两个对象的哈希码相同,他们却不一定相等。也就是说,equals()比较两个对象相等时hashCode()一定相等,hashCode()相等的两个对象equqls()不一定相等。 3、加分回答:由于hashCode()与equals()具有联动关系,equals()重写时,hashCode()进行重写,使得这两个方法始终满足相关的约定。

请你说说ArrayList和LinkedList的区别

ArrayList底层是数组实现的,数组是一组连续的内存单元,读取快(使用索引),插入删除慢(需要重新计算大小或是更新索引) LinkedList底层基于双向链表,读取慢,插入删除快;链表的每一个节点保存了数据值,和指向前一个节点的指针和指向后一个节点的指针。占内存

扩展:

ArrayList的增删未必就是比LinkedList要慢。

  • 如果增删都是在末尾来操作【每次调用的都是remove()和add()】,此时ArrayList就不需要移动和复制数组来进行操作了。如果数据量有百万级的时,速度是会比LinkedList要快的

  • 如果删除操作的位置是在中间。由于LinkedList的消耗主要是在遍历上,ArrayList的消耗主要是在移动和复制上(底层调用的是arraycopy()方法,是native方法)。

    • LinkedList的遍历速度是要慢于ArrayList的复制移动速度的

    • 如果数据量有百万级的时,还是ArrayList要快。(我测试过)

有序集合

List、LinkedHashMap、LinkedHashSet、TreeMap、TreeSet是有序的,List、LinkedHashMap、LinkedHashSet、LinkedHashSet在遍历时会保持添加的顺序,TreeMap、TreeSet在遍历时会以自然顺序(Comparable接口的compareTo)输出。

List,Set,Map的区别?

  • List是一个有序的集合,里面可以存储重复的元素。

  • Set是一个不能存储相同元素的集合。

  • Map是一个通过键值对的方式存储元素的,键不能重复

 

如何在 HashMap 和 TreeMap 之间做出决定?

对于在 Map 中插入、删除和定位元素,HashMap 提供了最佳选择。但是,如果您需要按排序顺序遍历键,那么 TreeMap 是您更好的选择。根据集合的大小,将元素添加到 HashMap,然后将映射转换为 TreeMap 以进行排序键遍历可能会更快。

 

 

JDK1.8的时候为什么选择8和6作为转换点?

因为红黑树的平均查找长度是log(n),长度为8的时候,平均查找长度为3,如果继续使用链表,平均查找长度为8/2=4,显然树的效率更高一些。

链表长度如果是小于等于6,6/2=3,虽然速度也很快的,但是树和链表相互转换的时间也不会太短。还有选择6和8,中间有个差值7可以有效防止链表和树频繁转换。

哪些集合类提供对其元素的随机访问?

ArrayList、HashMap、TreeMap、Hashtable 类提供对其元素的随机访问。

JDK、JRE和JVM之间的关系

JDK是Java开发工具包,其中包括编译工具(javac.exe)打包工具(jar.exe)等,也包括JRE。

JRE,即Java运行环境,包含JVM标准实现(Jvm虚拟机)与Java核心类库

JVM,即java虚拟机,

JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。

Java Runtime Environment(JRE)是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。 JVM是Java Virtual Machine(Java虚拟机)的缩写,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序。 image-20220711203106437

线程池的创建

四种线程池的创建:

(1)newCachedThreadPool 创建一个可缓存线程池

(2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数。

(3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

(4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务。

线程的创建

分别是继承Thread类、实现Runnable接口、实现Callable接口。

线程有三个状态

就绪态,运行态,等待态。

Sleep与Wait区别?

sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。

wait是Object类的方法,对象调用wait方法导致本线程放弃对象锁,进入等待池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入锁池准备抢夺对象锁。

TreeMap

[TreeMap]实现了SortedMap接口,保证了有序性。默认的排序是根据key值进行升序排序,也可以重写comparator方法来根据value进行排序具体取决于使用的构造方法不允许有null值null键。TreeMap是线程不安全的

 

 

Java容器可分为两大类:

  • Collection

    • List

      • ArrayList

      • LinkedList

      • Vector(了解,已过时)

    • Set

      • HashSet

        • LinkedHashSet

      • TreeSet

  • Map

    • HashMap

      • LinkedHashMap

    • TreeMap

    • ConcurrentHashMap

    • (了解,,已过时)

     

    Collection和Collections的区别

    Collection是集合的上级**接口**,继承它的有Set和List接口 

    Collections是集合的**工具类**,提供了一系列的静态方法对集合的搜索、查找、同步等操作

来自重庆三峡学院软件工程专业的一名应届生,本次来到贵公司主要是想应聘贵公司的java后端工程师,本人在大三期间有过项目经验,在大学期间也自学的一些关于java的东西。在学习java的过程中我也搭建了自己的个人博客,将自己的心得和一些代码分享在上面。平时的话喜欢自己在家里玩玩游戏。没有上面其他爱好。

 

 

升级版

 

说一下垃圾回收机制?

Java 语言中一个显著的特点就是引入了垃圾回收机制,在编写程序的时候不再需要考虑内存管理。垃圾回收机制可以有效的防止内存泄露,提高内存的内存率。

垃圾回收器通常是作为一个单独的低级线程运行,不可预知的情况下对堆中已经死亡的或者长时间没有使用的对象进行清理和回收。

回收机制的算法有:标记清除算法、复制算法、标记压缩算法等等。

 

 

描述一下垃圾回收的流程?

首先有三个代,新生代、老年代、永久代。

在新生代有三个区域:一个Eden区和两个Survivor区。当一个实例被创建了,首先会被存储Eden 区中。

具体过程是这样的:

  • 一个对象实例化时,先去看Eden区有没有足够的空间。

  • 如果有,不进行垃圾回收,对象直接在Eden区存储。

  • 如果Eden区内存已满,会进行一次minor gc。

  • 然后再进行判断Eden区中的内存是否足够。

  • 如果不足,则去看存活区的内存是否足够。

  • 如果内存足够,把Eden区部分活跃对象保存在存活区,然后把对象保存在Eden区。

  • 如果内存不足,查询老年代的内存是否足够。

  • 如果老年代内存足够,将部分存活区的活跃对象存入老年代。然后把Eden区的活跃对象放入存活区,对象依旧保存在Eden区。

  • 如果老年代内存不足,会进行一次full gc,之后老年代会再进行判断 内存是否足够,如果足够 还是那些步骤。

  • 如果不足,会抛出OutOfMemoryError(内存溢出异常)。

  • GC回收的是堆内存还是栈内存?

    主要管理的是堆内存。

     

     

    Sleep与Wait区别?

    sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。

    wait是Object类的方法,对象调用wait方法导致本线程放弃对象锁,进入等待池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入锁池准备抢夺对象锁。

     

     

    #{ } 和${ }的区别?

    • #{}:这种方式是使用的预编译的方式,一个#{}就是一个占位符。相当于jdbc的占位符PrepareStatement。设置值的时候会加上引号。

    • ${}:这种方式是直接拼接的方式,不对数值做预编译。存在sql注入的现象。设置值的时候不会加上引号。 作者:Java77i ost_nctrack&gio_id=DA9855AFE506815BF71669A208318CAB-1657697653977 来源:牛客网

      MySQL锁

      MyISAM支持表锁,InnoDB支持表锁和行锁,默认行锁。

      • 表级锁:开锁小,加锁快,不会出现死锁。锁的粒度大,发生锁冲突的概率最高。并发量最低。

      • 行级锁:开销大,加锁慢,会出现死锁,锁的粒度小,容易发生冲突的概率小,并发度最高

posted @ 2022-07-13 15:50  java小寇  阅读(47)  评论(0)    收藏  举报