Java基础面试题(1)

面向对象

1、面向对象的特征有哪些方面?

  • 抽象,将一类对象的共同特征总结出来构造类的过程
  • 继承,从已有的类得到继承信息创建新类的过程
  • 封装,把数据和操作数据的方法绑定起来
  • 多态,允许不同子类型的对象对同一消息作出不同的相应

2、String 是最基本的数据类型吗?

不是。基本类型:byte、short、int、long、float、double、char、boolean。除了基本类型,就是引用类型。枚举类型也是一种比较特殊的引用类型。

3、float f=3.4 是否正确?

不正确,3.4为double类型,正确为 float f = 3.4f

4、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?

一,需要转换类型;二,隐含强制类型转换,可以正确编译

5、int 和 Integer有什么区别?

int是基本类型,Integer是其包装类

  • 原始类型: boolean,char,byte,short,int,long,float,double

  • 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float, Double

Integer内置了-128到127之间的常量池,不会new新的对象

6、&和&&的区别?

&:按位与、逻辑与;&&短路与

7、switch 是否能作用在byte上,是否能作用在long上,是否能作用在String上?

switch可以作用的类型:byte、short、char、int、枚举类型、String。

long是不可以的

8、数组有没有 length()方法?String 有没有 length()方法?

数组没有 length()方法,有 length 的属性。String 有 length()方法。JavaScript 中, 获得字符串的长度是通过 length 属性得到的, 这一点容易和 Java 混淆。

9、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

不对,如果两个对象 x 和 y 满足 x.equals(y) == true,它们的哈希码( hash code) 应当相同。Java 对于 eqauls 方法和 hashCode 方法是这样规定的:

(1) 如果两个对象相同(equals 方法返回 true), 那么它们的 hashCode 值一定要相同;

(2) 如果两个对象的 hashCode 相同, 它们并不一定相同。

当然, 你未必要按照要求去做, 但是如果你违背了上述原则就会发现在使用容器时, 相同的对象可以出现在 Set 集合中, 同时增加新元素的效率会大大下降( 对于使用哈希存储的系统, 如果哈希码频繁的冲突将会造成存取性能急剧下降)。

equals 方法必须满足自反性、对称性、传递性、一致性

10、是否可以继承 String 类?

String 类是final类,不可以被继承

11、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

是值传递。Java 语言的方法调用只支持参数的值传递。

12、String 和StringBuilder、StringBuffer 的区别?

String为只读,StringBuilder和StringBuffer可以改变字符串的内容,StringBuilder为线程不安全的

注意:string对象在常量池中的创建,intern()的使用

13、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

重载发生在一个类中, 同名的方法如果有不同的参数列表( 参数类型不同、参数个数不同或者二者都不同) 则视为重载; 重写发生在子类与父类之间, 重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常( 里氏代换原则)。

14、char 型变量中能不能存贮一个中文汉字,为什么?

char 类型可以存储一个中文汉字, 因为 Java 中使用的编码是 Unicode

15、抽象类(abstract class)和接口(interface)有什么异同?

抽象类和接口都不能够实例化, 但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现, 否则该类仍然需要被声明为抽象类。

  • 抽象类中的成员可以是 private、默认、protected、public 的,而接口中的成员全都是 public 的。

  • 抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。

  • 接口比抽象类更加抽象, 因为抽象类中可以定义构造器, 可以有抽象方法和具体方法, 而接口中不能定义构造器而且其中的方法全部都是抽象方法。

  • 有抽象方法的类必须被声明为抽象类, 而抽象类未必要有抽象方法。

16、静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?

Static Nested Class 是被声明为静态( static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化

17、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被 synchronized修饰?

都不能。synchronized 和方法的实现细节有关, 抽象方法不涉及实现细节, 因此也是相互矛盾的。

18、阐述静态变量和实例变量的区别。

静态变量是被 static 修饰符修饰的变量, 也称为类变量, 它属于类, 不属于类的任何一个对象, 一个类不管创建多少个对象, 静态变量在内存中有且仅有一个拷贝; 实例变量必须依存于某一实例, 需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。

19、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?

不能,非静态方法的调用需要实例化对象。

20、如何实现对象克隆?

1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;

2). 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

21、接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?

接口继承接口, 而且支持多重继承。抽象类可以实现(implements)接口, 抽象类可继承具体类也可以继承抽象类。

22、一个”.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?

可以, 但一个源文件中最多只能有一个公开类( public class) 而且文件名必须和公开类的类名完全保持一致。

23、Java 中的final 关键字有哪些用法?

(1)修饰类:表示该类不能被继承;

(2)修饰方法:表示方法不能被重写;

(3)修饰变量:表示变量只能一次赋值以后值不能被修改( 常量)。

24、Java类加载机制

创建对象时构造器的调用顺序是: 先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器

25、Error 和 Exception有什么区别?

Error 表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题; 比如内存溢出,不可能指望程序能处理这样的情况;

Exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。

26、try{}里有一个 return 语句,那么紧跟在这个try 后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?

会执行,在方法返回调用前执行。

27、阐述 final、finally、finalize 的区别。

  • final:修饰符(关键字)有三种用法:如果一个类被声明为 final,意味 着它不能再派生出新的子类,即不能被继承,因此它和 abstract 是反义词。将变量声明为 final,可以保证它们在使用中不被改变,被声明为 final 的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为 final 的方法也同样只能使用,不能在子类中被重写。
  • finally:通常放在 try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要 JVM 不关闭都能执行,可以将释放外部资源的代码写在 finally 块中。
  • finalize:Object 类中定义的方法,Java 中允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写 finalize()方法可以整理系统资源或者执行其他清理工作。

集合

1、List、Set、Map是否继承自Collection接口?

List、Set 是,Map 不是。Map 是键值对映射容器,与 List 和 Set 有明显的区别, 而 Set 存储的零散的元素且不允许有重复元素( 数学中的集合也是如此), List 是线性结构的容器, 适用于按数值索引访问元素的情形。

2、阐述 ArrayList、Vector、LinkedList 的存储性能和特性。

ArrayList 和 Vector 都是使用数组方式存储数据, 此数组元素数大于实际存储的数据以便增加和插入元素, 它们都允许直接按序号索引元素, 但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢, Vector 中的方法由于添加了 synchronized 修饰, 因此 Vector 是线程安全的容器, 但性能上较 ArrayList 差, 因此已经是 Java 中的遗留容器。

LinkedList 使用双向链表实现存储( 将内存中零散的内存单元通过附加的引用关联起来, 形成一个可以按序号索引的线性结构, 这种链式存储方式与数组的连续存储方式相比, 内存的利用率更高), 按序号索引数据需要进行前向或后向遍历, 但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。

Vector 属于遗留容器( Java 早期的版本中提供的容器, 除此之外, Hashtable、Dictionary、BitSet、Stack、Properties 都是遗留容器), 已经不推荐使用, 但是由于 ArrayList 和 LinkedListed 都是非线程安全的, 如果遇到多个线程操作同一个容器的场景, 则可以通过工具类 Collections 中的 synchronizedList 方法将其转换成线程安全的容器后再使用( 这是对装饰器模式的应用, 将已有对象传入另一个类的构造器中创建新的对象来增强实现)。

3、Collection 和Collections 的区别?

Collection 是一个接口, 它是 Set、List 等容器的父接口; Collections 是个一个工具类, 提供了一系列的静态方法来辅助容器操作, 这些方法包括对容器的搜索、排序、线程安全化等等。

4、TreeMap 和TreeSet 在排序时如何比较元素?Collections 工具类中的sort()方法如何比较元素?

TreeSet 要求存放的对象所属的类必须实现 Comparable 接口, 该接口提供了比较元素的 compareTo()方法, 当插入元素时会回调该方法比较元素的大小。

TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进行排序。

Collections 工具类的 sort 方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较; 第二种不强制性的要求容器中的元素必须可比较, 但是要求传入第二个参数, 参数是Comparator 接口的子类型( 需要重写 compare 方法实现元素的比较), 相当于一个临时定义的排序规则, 其实就是通过接口注入比较元素大小的算法, 也是对回调模式的应用( Java 中对函数式编程的支持)。

5、说说List、Set、Map三者的区别?

  • list,存储一组不唯一,有序的对象
  • set,不允许重复的集合
  • map,使用键值对进行存储

6、ArrayList和LinkedList的区别?

  • 是否保证线程安全, 都不是同步的,是线程不安全的
  • 底层数据结构,ArrayList是以数组形式来保存数据,LinkedList是双向链表数据结构
  • 插入和删除元素是否会受元素位置的影响,ArrayList采用的是数组形式,会受影响,如果在数组的尾部操作,时间复杂度是O(1);如果在某个位置i进行操作,需要移动元素,时间复杂度为O(n)。LinkedList是双向链表,进行插入和删除操作时,不会受元素位置的影响,时间复杂度近似O(1)
  • 是否支持快速随机访问,ArrayList支持,LinkedList不支持
  • 内存空间占用,ArrayList主要体现在需要预留一定的内存空间,LinkedList的每个元素都要比ArrayList的空间要多

7、说说ArrayList的扩容机制

扩容可分为两种情况:

  第一种情况,当ArrayList的容量为0时,此时添加元素的话,需要扩容,三种构造方法创建的ArrayList在扩容时略有不同:

    1.无参构造,创建ArrayList后容量为0,添加第一个元素后,容量变为10,此后若需要扩容,则正常扩容。

    2.传容量构造,当参数为0时,创建ArrayList后容量为0,添加第一个元素后,容量为1,此时ArrayList是满的,下次添加元素时需正常扩容。

    3.传列表构造,当列表为空时,创建ArrayList后容量为0,添加第一个元素后,容量为1,此时ArrayList是满的,下次添加元素时需正常扩容。

  第二种情况,当ArrayList的容量大于0,并且ArrayList是满的时,此时添加元素的话,进行正常扩容,每次扩容到原来的1.5倍。

当每次添加新元素时,ArrayList都会检查是否需要扩容,如需扩容,会扩容成当前容量的1.5倍,如果溢出(负数)的话则会抛出OutOfMemoryError,如果介于Integer.MAX_VALUE和MAX_ARRAY_SIZE两者之间,则取Integer.MAX_VALUE。

8、HashMap和HashTable的区别?

  • 线程是否安全,HashMap非线程安全,HashTable线程安全,方法都加了Sychronized修饰
  • 效率,HashMap效率要比HashTable要高,(HashTable基本被淘汰了,保证线程安全用concurrentHashMap)
  • 对null key与null value的支持,HashMap可以有一个null key,可以有一个或多键的值为null,HashTable不允许键值为null,直接抛出异常
  • 初始容量大小和每次扩充容量大小不同,HashTable默认大小为11,扩充2n+1,HashMap默认为16,以2的倍数扩充
  • 底层数据结构,JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。

9、HashMap和HashSet的区别?

  • 实现接口,HashMap实现的是Map接口,HashSet实现的是Set接口
  • 存储数据,HashMap键值对,HashSet仅存储数据
  • 添加元素方式,HashMap是put操作,HashSet是add
  • hashcode计算,HashMap使用键来计算hashcode,HashSet使用对象来计算hashcode,hashcode相同的话,通过equals方法判断两个对象相等性

10、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()指的是值是否相同

11、HashMap为什么是2的幂次方

为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀。

12、Comparable和Comparator的区别

  • comparable接口出自java.lang包下,有一个compareTo(Object obj)来排序
  • comparator接口出自java.util包下,有一个compare(Object obj1, Object obj2)来排序

一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo()方法或compare()方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写compareTo()方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的 Collections.sort().

13、集合框架底层数据结构总结

  • List
    • List,Object数组
    • Vector,Object数组
    • LinkedList,双向链表
  • Set
    • HashSet,无序唯一
    • LinkedHashSet,继承HashSet,底层通过LinkedHashMap实现
    • TreeSet,有序唯一
  • Map
    • HashMap,数组+链表/红黑树
    • LinkedHashMap,继承HashMap,增加了双向链表,实现了相应的插入顺序
    • HashTable,数组+链表
    • TreeMap,红黑树,自平衡

多线程

1、Thread 类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?

sleep方法不会释放锁,wait方法会释放锁,线程挂起

2、线程的 sleep()方法和yield()方法有什么区别?

sleep方法让出cpu等资源,yield方法释放后,会根据优先级让出资源给线程

IO流

1、Java 中如何实现序列化,有什么意义?

序列化就是一种用来处理对象流的机制, 所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作, 也可将流化后的对象传输于网络之间。序列化是为了解决对象流读写操作时可能引发的问题( 如果不进行序列化可能会存在数据乱序的问题)。 要实现序列化, 需要让一个类实现 Serializable 接口, 该接口是一个标识性接口, 标注该类对象是可被序列化的, 然后使用一个输出流来构造一个对象输出流并通过 writeObject(Object)方法就可以将实现对象写出( 即保存其状态);如果需要反序列化则可以用一个输入流建立对象输入流,然后通过 readObject 方法从流中读取对象。序列化除了能够实现对象的持久化之外, 还能够用于对象的深度克隆。

2、Java 中有几种类型的流?

字节流和字符流。字节流继承于 InputStream、OutputStream, 字符流继承于 Reader、Writer。在 java.io 包中还有许多其他的流, 主要是为了提高性能和使用方便。

反射

1、获得一个类的类对象有哪些方式?

方法 1:类型.class,例如:String.class

方法 2:对象.getClass(),例如:”hello”.getClass()

方法 3:Class.forName(),例如:Class.forName(“java.lang.String”)

2、如何通过反射创建对象?

方法 1:通过类对象调用 newInstance()方法,例如:

String.class.newInstance()

方法 2:通过类对象的 getConstructor()或 getDeclaredConstructor()

方法获得构造器(Constructor)对象并调用其 newInstance()方法创建对象, 例如:String.class.getConstructor(String.class).newInstance(“Hello”);

原文地址:https://www.cnblogs.com/kadaj174/p/14839001.html