面试题整理

1.java跨平台的原理

具有平台无关性

Java是“一次编写,到处运行(Write Once,Run any Where)"的语言,因此采用Java语言编写的程序具有很好的可移植性,而保证这一点的正是Java的虚拟机机制。在引入虚拟机之后,Java语言在不同的平台上运行不需要重新编译。

Java跨平台原理

  由源文件(.java)—>字节码文件(.class)(二进制文件)-----> 解释---->Unix,Win,Linux等机器。

   1.一次编译,到处运行

2.编译器的作用:将源文件编译成class文件

3.虚拟机的作用:将字节码文件解释成对应平台机器码并执行。

4.java可以实现跨所有的平台?只有提供并且安装了相对应的虚拟机就可以跨该平台。

5.虚拟机和解释器的关系:解释器是虚拟机的一个重要的组成部分。

6.Java语言的执行要经过编译和解释两个阶段。


2.数据类型

包括基本数据类型引用数据类型

整型:

  byte   1个字节  二进制位8位  00000001  -128~127  1byte = 8bit  默认值:0

  short  2个字节  二进制位16位  是int的二分之一

  int    4个字节  二进制位32位

  long   8个字节  二进制位64位  long l1 = 10L;

  字符型: 

  char  1个字节    c = 'a';

  浮点型:

  float  4个字节    f1 = 1.1f;  //单精度

  double 8个字节  d1 = 2.2;  //双精度

  布尔型:

  boolean 1个字节  b2 = true;

3.java中标识价格BigDecimal

1.不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度。

2.Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。

4.双精度&单精度

1.单精度和双精度精确的范围不一样

2.单精度,一般在计算机中存储占用4字节,也就是32位,有效位数为7位;

3.双精度〈double〉在计算机中存储占用8字节,64位,有效位数为16位。

4.单精度在一些处理器上比双精度更快而且只占用双精度一半的空间.

5.但是当值很大或很小的时候.它将变得不精确。当你需要小数部分并且对精度的要求不高时,单精度浮点型的变量是有用的。

 

单精度是这样的格式,1位符号,8位指数,23位小数。

 

 

 

 

 

 

双精度是这样的格式,1位符号,11位指数,52位小数。 

单精度数的尾数用23位存储,加上默认的小数点前的1位1,2^(23+1) = 16777216。因为 10^7 < 16777216 < 10^8,所以说单精度浮点数的有效位数是7位。

双精度的尾数用52位存储,2^(52+1) = 9007199254740992,10^16 < 9007199254740992 < 10^17,所以双精度的有效位数是16位。

5.面向对象三大特征(封装,继承,多态)

封装。也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承。它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类"或"派生类",被继承的类称为“基类"、“父类"或“超类"。
多态。它是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。

6.装箱&拆箱

Java为每一个基本数据类型都引入了对应的包装类型,从Java 5开始引入了自动装箱/拆箱机制,把基本类型转换成包装类型的过程叫做装箱;反之,把包装类型转换成基本类型的过程叫做拆箱,使得二者可以相互转换。

1.包装类型可以为null,而基本类型不可以。

2.包装类型可用于泛型,而基本类型不可以。

3.基本类型比包装类型更高效。基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用。很显然,相比较于基本类型而言,包装类型需要占用更多的内存空间。

6.1自动装箱:将基本数据类型重新转化为对象

  自动拆箱:将对象重新转化为基本数据类型

6.2int和Integer有什么区别?

  1. Integer是int的包装类;int是基本数据类型;
  2. Integer变量必须实例化后才能使用; int变量不需要;
  3. Integer实际是对象的引用,指向此new的Integer对象;int是直接存储数据值;
  4. Integer的默认值是null; int的默认值是0。


7.子类继承父类,子类必须能够访问到父类的构造方法,protected肯定能访问到

 8.Integer缓存的实现

  1. 为了节省内存和提高性能,Integer类在内部通过使用相同的对象引用实现缓存和重用,
  2. IntegerCache是个Integer的内部类,在类加载的时候创建了256个缓存Integer对象,范围-128至127,value相同的Integer对象是同一个对象。
  3. 最小值-128在一开始就设置死了,但是127是可以通过 -XX:AutoBoxCacheMax进行修改的.

9.运算符&&||和&|的区别

  • 与运算(都是真才为真)包含&&(短路与)和&(不短路与)
  • 或运算(一真为真)||  表示短路或,|  表示不短路或

短路运算符左边的判断为false的时候,就不再去判断运算符右边的判断

 

&|是位运算符,按位与和按位或

10.==和equals的区别

  1. ==常用于相同的基本数据类型之间的比较,也可用于相同类型的对象之间的比较;
  2. equals方法主要用于两个对象之间,检测一个对象是否等于另一个对象;

 

  1. 如果==比较的是基本数据类型,那么比较的是两个基本数据类型的值是否相等;
  2. 如果==是比较的两个对象,那么比较的是两个对象的引用,也就是判断两个对象是否指向了同一块内存区域;

11.String str="abc"创建了几个对象?String str=new String("abc")创建了几个对象

一个,两个

1.创建了一个String对象 'abc'(1个)

2.我们可以把上面这行代码分成   String str   、=  、 "abc"   和   new String()  四部分来看待。

  • String str只是定义了一个名 为str的String类型的变量,因此它并没有创建对象
  • new String("abc")又能 被看成"abc"和new String()

并且 abc 字符串之前没有用过,这毫无疑问创建了两个对象

  • 一个是new  String 创建的一个新的对象
  • 一个是常量“abc”对象的内容创建出的一个新的String对象(2个)

12.String,stringbuffer和stringbuilder的区别

1)首先String、StringBuffer、StringBuilder在JDK中都被定义为final类,这意味着他们不可以被继承。

2)String最常见,与StringBuffer相比,String的性能较差,因为对String类型进行改变的时候都会重新生成一个新的String对象,这在字符串拼接操作时很明显,因此内容经常改变的字符串不应该使用String,如果不考虑多线程,则应使用StringBuilder。

3)StringBuffer生成一个对象后,在进行字符串拼接操作时,调用append方法即可不会产生新的对象,仅对对象本身进行操作,性能比String要高。另外StringBuffer是线程安全的,因此适合在多线程中使用,也正因为如此,速度跟StringBuilder相比会比较慢。

4)StringBuilder的使用方法跟StringBuffer类似,但其是非线程安全的,因此一般常用于单线程效率比StringBuffer高

13.String 类可以被继承吗?为什么?为什么String类要设计为不可被继承的

java中不可以继承String类. 因为String类有final修饰符,而final修饰的类是不能被继承的。
String 使用final修饰的主要原因:
由于专String类被final修饰不能被继承,所以就不能修改,这就避免了因继承而引起的安全隐患
由于String类在程序中使用毕竟频属繁, 设置为final可以提高执行效率

14.实现一个拷贝文件夹的方法,使用字节流还是字符流

这里我们要考虑我们的文件是字符类型的,还是字节类型的:
字符类型一般包括:word、txt、文本类型。
字节类型一般包括:图片、声音、图像等。
因为一般字符流最终都要转换成字节流,所以为考虑到通用性,要用字节流

15.数据库的分类和常见的数据库你知道那些?

根据数据库的架构和数据组织原理进行分类
1、早期根据数据库的组织数据的存储模型分类
层次数据库:基于层次的数据结构(数据分层)
网状数据库:基于网状的数据结构(数据网络)
关系数据库:基于关系模型的数据结构(二维表)
2、现在较多根据实际数据管理模型分类(存储介质)
关系型数据库:基于关系模型的数据结构(二维表)通常存储在磁盘
非关系型数据库:没有具体模型的数据结构(键值对)通常存储在内存

16.介绍一下三范式,设计表时一定要追求三范式吗?

  • 第一范式(列不可分):强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项.
  • 第二范式(不能部分依赖):要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。
  • 第三范式(不能传递依赖):任何非主属性不依赖于其它非主属性。

要满足第三范式必须先满足第二范式,要想满足第二范式必须先满足第一范式.

第三范式的好处就是:1.数据不会有冗余 2.做更新操作只需要单表操作。

但也不一定必须追求第三范式:

 比如:用户信息表(id,gid,gname) 国家城市表(gid,gname) 这里的用户信息表按照一般思维,是只存gid就行了,但是为什么还存gname呢?

优点如下:

1.国家地区表 基本上不会有变化,所以把gname存在用户信息表

2.在查询的时候不用再次关联查到地区名称了,少一次关联查询,性能提升不少。

 

 17.java中什么是序列化和反序列化?

Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程:
序列化:序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。核心作用是对象状态的保存与重建。我们都知道,Java对象是保存在JVM的内存中的,也就是说,如果JVM堆不存在了,那么对象也就跟着消失了。
而序列化提供了一种方案,可以让你在即使JVM停机的情况下也能把对象保存下来的方案。就像我们平时用的U盘一样。把Java对象序列化成可存储或传输的形式(如二进制流),比如保存在文件中。这样,当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化出对象。
反序列化:客户端从文件中或网络上获得序列化后的对象字节流,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象

18.java中不想序列化的字段怎么处理?

对于不想进行序列化的变量,使用transient关键字修饰。
transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient变量的值被设为初始值,如int型的是0,对象型的是null。transient 只能修饰变量,不能修饰类和方法。

19.深拷贝&浅拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存

深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象

20.什么 是反射?

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意一个方法和属性;

这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

21.反射常用API类

反射API用来生成JVM中的类、接口或则对象的信息。

  • Class类:反射的核心类,可以获取类的属性,方法等信息。
  • Field 类: Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
  • Method类: Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
  • Constructor类: Java.lang.reflec包中的类,表示类的构造方法。

22.反射的使用步骤

  1. 获取想要操作的类的Class对象,这是反射的核心,通过Class对象我们可以任意调用类的方法。
  2. 调用Class类中的方法,既就是反射的使用阶段。
  3. 使用反射API来操作这些信息。

23.获取Class对象的方式

1.Class.forName(“类的路径");当你知道该类的全路径名时,你可以使用该方法获取 Class类对象。

  1 Class clz = Class.forName( "java.lang.String"); 

2.类名.class。这种方法只适合在编译前就知道操作的Class。

 1 Class clz = String.class; 

3.对象名.getClass()。

1 String str = new String( "Hello");

2 Class clz = str.getclass(); 

4.如果是基本类型的包装类,可以调用包装类的Type属性来获得该包装类的Class对象。

24.List 子类的特点

ArrayList:
   底层数据结构是数组,查询快,增删慢
   线程不安全, 效率较高
Vector
   底层数据结构是数组,查询快,增删慢
   线程安全, 效率较低
LinkedList
   底层数据结构是链表,查询慢,增删快
   线程不安全,效率较高

 

25.ArrayList ,linkedList,Vector的区别

同上

26.HashSet如何查重复

当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让加入操作成功

hashCode()与equals()的相关规定:

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

==与equals的区别

  1. ==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同
  2. ==是指对内存地址进行比较 equals()是对字符串的内容进行比较
  3. ==指引用是否相同 equals()指的是值是否相同

27.HashMap和HashSet的区别

补充HashSet的实现: HashSet的底层其实就是HashMap,只不过我们HashSet是实现了Set接口并且把数据作为K值,而V值一直使用一个相同的虚值来保存。如源码所示:

由于HashMap的K值本身就不允许重复,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V,那么在HashSet中执行这一句话始终会返回一个false,导致插入失败,这样就保证了数据的不可重复性。

28.HashMap的容量(16)

HashMap作为一种数据结构,元素在put的过程中需要进行hash运算,目的是计算出该元素存放在hashMap中的具体位置hash运算的过程其实就是对目标元素的Key进行hashcode再对Map的容量进行取模,而JDK 的工程师为了提升取模的效率,使用位运算代替了取模运算,这就要求Map的容量一定得是2的幂。而作为默认容量,太大和太小都不合适,所以16就作为一个比较合适的经验值被采用了。为了保证任何情况下Map的容量都是2的幂,HashMap在两个地方都做了限制。首先是,如果用户制定了初始容量,那么HashMap会计算出比该数大的第一个2的幂作为初始容量。另外,在扩容的时候,也是进行成倍的扩容,即4变成8,8变成16。

除了初始化的时候会指定HashMap的容量,在进行扩容的时候,其容量也可能会改变。HashMap有扩容机制,就是当达到扩容条件时会进行扩容。HashMap的扩容条件就是当HashMap中的元素个数(size)超过临界值(threshold)时就会自动扩容。在HashMap中,threshold = loadFactor * capacity。loadFactor是装载因子,表示HashMap满的程度,默认值为0.75f,设置成0.75有一个好处,那就是0.75正好是3/4,而capacity又是2的幂。所以,两个数的乘积都是整数。对于一个默认的HashMap来说,默认情况下,当其size大于12(16*0.75)时就会触发扩容。

posted @ 2022-02-16 21:20  Nickeyhu  阅读(45)  评论(0编辑  收藏  举报