Java面试基础部分(初级篇)

1.1、面向对象的特征

抽象、封装、继承、多态

面向对象的封装性:将对象封装成一个高度自治和相对封闭的个体,对象的属性由对象的方法来读取和改变。

抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处并且会忽略与当前主题和目标无关的那些方面,将注意力集中到域当前目标有关的方面。

在定义和实现一个类的时候,可以在一个已经存在的类的基础上来进行,把这个已经存在的类所定义的内容作为自己的内容,并且可以加入若干新的内容,或修改原来的方法,使之更适合特殊的需求,这就是继承。

多态是指程序中所定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中的实现方法,必须在程序运行期间才能决定。

1.2、基本数据类型字节数

byte:8;short:16;int:32;long:64;float:34;double:64;char:16;boolean:1,默认为false

1.3、char 型变量中能不能存贮一个中文汉字

可以,char类型是16位,占两个字节,中文汉字是unicode编码的字符集,也占用两个字节。

1.4、==和equals的区别

(1)对于==,比较的是值是否相等

如果作用于基本数据类型的变量,则直接比较其存储的 值是否相等。

如果作用于引用类型的变量,则比较的是所指向的对象的地址是否相等。

(2)对于equals方法,比较的是是否是同一个对象

首先,equals()方法不能作用于基本数据类型的变量。

另外,equals()方法存在于Object类中,而Object类是所有类的直接或间接父类,所以说所有类中的equals()方法都继承自Object类,在没有重写equals()方法的类中,调用equals()方法其实和使用==的效果一样,也是比较的是引用类型的变量所指向的对象的地址,不过,Java提供的类中,有些类都重写了equals()方法,重写后的equals()方法一般都是比较两个对象的值,比如String类。

1.5、&和&&的区别

&运算符有两种用法:(1)按位与;(2)逻辑与

&&运算符是短路与运算,&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算

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

在Java 5以前,switch(expr)中,expr只能是byte、short、char、int。从Java 5开始,Java中引入了枚举类型,expr也可以是enum类型,从Java 7开始,expr还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

1.7、用最有效率的方法计算2乘以8?

2 << 3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)

1.8、重写和重载的区别

重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常。

重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载。

1.9、构造方法是否可以被重写

构造器不能被继承,因此不能被重写,但可以被重载

1.10、hashcode相同的两个对象是否equals为true?

不一定

String str1 = "通话";
String str2 = "重地";
System.out.println(String.format("str1:%d | str2:%d", str1.hashCode(),str2.hashCode()));
System.out.println(str1.equals(str2));

执行结果:

str1:1179395 | str2:1179395

1.11、抽象类和接口有什么异同?

抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。

1.12、String类是否可以继承?

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

1.13、String s = new String(“abc”);创建了几个字符串对象?

两个对象,一个是静态区的"abc",一个是用new创建在堆上的对象。

1.14、String、StringBuffer、StringBuilder的区别

String和StringBuffer/StringBuilder,它们可以储存和操作字符串。其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改。StringBuilder是Java 5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer要高。

1.15、值传递和引用传递的区别

对于基本数据类型,都是值传递,值传递传递的都是该变量的一个副本,改变副本不影响原变量。

对于引用数据类型,都是引用传递,引用传递传递的是该变量的引用地址,因此改变传递的该变量会影响原变量。

1.16、接口是否可继承接口?抽象类是否可实现接口?抽象类是否可继承具体类?

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

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

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

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

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

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

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

1.19、ArrayList和LinkedList区别

ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。

对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

1.20、ArrayList扩容机制

初始化长度为10,一句话总结:当传入的元素超出当前数组容量时,会创建一个更大容量的数组(原容量的1.5倍),利用Arrays.conpyof()方法将当前的元素移动至新的书中。

1.21、ArrayList是线程安全的吗,线程安全的集合有如何实现?

不是线程安全的。

①使用Vector替代。

②利用Collections.synchronizedList为集合加锁

// 用Collections.synchronizedList构建一个线程安全的ArrayList
List<String> list = Collections.synchronizedList(new ArrayList<>()); 

③使用CopyOnWriteArrayList(写时复制)替代。

1.22、Collection和Collections的区别

Collection是一个接口,它是Set、List等容器的父接口。

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

1.23、List、Map、Set三个接口存取元素时,各有什么特点

List以特定索引来存取元素,可以有重复元素。

Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。

Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一。

Set和Map容器都有基于哈希存储和排序树的两种实现版本,基于哈希存储的版本理论存取时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的键(key)构成排序树从而达到排序和去重的效果。

1.24、HashMap、HashTable、CurrentHashMap的区别

①HashTable
底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
初始size为11,扩容:newsize = olesize2+1
计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
②HashMap
底层数组+链表实现,可以存储null键和null值,线程不安全
初始size为16,扩容:newsize = oldsize2,size一定为2的n次幂
扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
计算index方法:index = hash & (tab.length – 1)

③ConcurrentHashMap

底层采用分段的数组+链表实现,线程安全
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容

1.25、常用设计模式

**工厂模式:**工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。
**代理模式:**给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理。
**适配器模式:**把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。
**模板方法模式:**提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法(多态实现),从而实现不同的业务逻辑。

1.26、单例模式的实现

饿汉式:

public class Singleton {
    private Singleton(){}
    private static Singleton instance = new Singleton();
    public static Singleton getInstance(){
        return instance;
    }
}

懒汉式:

public class Singleton {
    private static Singleton instance = null;
    private Singleton() {}
    public static synchronized Singleton getInstance(){
        if (instance == null) instance = new Singleton();
        return instance;
    }
}

1.27、Error和Exception有什么区别?

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

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

1.28、列出一些你常见的运行时异常

ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下标越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)

1.29、final、finally、finalize的区别

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

1.30、Java中如何实现序列化

让一个类实现Serializable接口,该接口是一个标识性接口,标注该类对象是可被序列化的,然后使用一个输出流来构造一个对象输出流并通过writeObject(Object)方法就可以将实现对象写出(即保存其状态);如果需要反序列化则可以用一个输入流建立对象输入流,然后通过readObject方法从流中读取对象。

1.31、Java中有几种类型的流

字节流和字符流。

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

1.32、Java中如何支持正则

Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式操作。

1.33、UML是什么?项目中有哪些常用的图?

UML是统一建模语言(Unified Modeling Language)的缩写,它发表于1997年,综合了当时已经存在的面向对象的建模语言、方法和过程,是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持。使用UML可以帮助沟通与交流,辅助应用设计和文档的生成,还能够阐释系统的结构和行为。

常用的用例图(use case diagram)、类图(class diagram)、时序图(sequence diagram)、协作图(collaboration diagram)、状态图(statechart diagram)、活动图(activity diagram)、构件图(component diagram)、部署图(deployment diagram)等。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值