一、基础篇
1 、面向对象和面向过程的区别
面向过程:是分析解决问题的步骤,然后用函数把这些步骤一步一步地实现,然后在使用的时候一 一调用则可。性能较高,所以单片机、嵌入式开发等一般采用[面向过程]开发.
面向对象:是把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤, 而是为了描述某个事物在解决整个问题的过程中所发生的行为。面向对象有封装、继承、多态的特 性,所以易维护、易复用、易扩展。可以设计出低耦合的系统。 但是性能上来说,比面向过程要低。
2、简单说说封装、继承与多态
封装:
- 概念:封装是[面向对象编程]中的一种基本思想。它将对象的数据(属性)和操作数据的方法(行为)捆绑在一起,形成一个独立的对象(类)。同时,封装可以隐藏对象的内部实现细节,只对外提供有限的接口供其他对象访问。
继承:
- 概念:继承是一种允许新类(子类)继承现有类(父类)的属性和方法的机制。子类可以继承父类的公共属性和方法,并且可以添加自己的新属性和方法,也可以重写父类的方法来实现特定的功能。
多态:
- 概念:多态是指允许不同的对象对同一消息做出响应,具体调用哪个对象的方法在运行时根据对象的实际类型动态确定。多态分为编译时多态(方法重载)和运行时多态(方法覆盖)。
- 举例:还是以动物类为例。动物类有一个叫的方法(
void call()
)。狗类和猫类都继承自动物类,并且都覆盖了叫的方法。狗类的叫方法是汪汪叫,猫类的叫方法是喵喵叫。当有一个动物类型的引用指向狗对象时,调用animal.call()
就会发出汪汪的叫声;当这个引用指向猫对象时,调用animal.call()
就会发出喵喵的叫声。这就是运行时多态,具体调用哪个类的叫方法是在运行时根据对象的实际类型(狗或猫)动态确定的。
3 、标识符的命名规则
**标识符的含义: ** 是指在程序中,我们自己定义的内容,譬如,类的名字,方法名称以及变量名称等 等,都是标识符。
**命名规则:(硬性要求) ** 标识符可以包含英文字母,0-9的数字,$以及_ 标识符不能以数字开头 标 识符不是关键字
**命名规范:(非硬性要求) ** 类名规范:首字符大写,后面每个单词首字母大写(大驼峰式)。 变量
名规范:首字母小写,后面每个单词首字母大写(小驼峰式)。 方法名规范:同变量名。
4 、 Java 自动装箱与拆箱
装箱就是自动将基本数据类型转换为包装器类型( int-->Integer);调用方法: Integer的 valueOf(int) 方法
拆箱就是自动将包装器类型转换为基本数据类型( Integer-->int)。调用方法: Integer的 intValue方法
5 、 方法重载和方法重写的区别
重写 ( Override)
从字面上看,重写就是重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。 子 类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名, 参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
重载( Overload )
在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不 同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是 否相同来判断重载。
6、 equals与 == 的区别
== 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是 否是指相同一个对象。比较的是真正意义上的指针操作。
equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所 以适用于所有对象,如果没有对该方法进行重写的话,调用的仍然是Object类中的方法,而Object 中的equals方法返回的却是==的判断。
7 、 Hashcode 的作用
java的集合有两类,一类是List,还有一类是Set。前者有序可重复,后者无序不重复。当我们在set 中插入的时候怎么判断是否已经存在该元素呢,可以通过equals方法。但是如果元素太多,用这样 的方法就会比较满。
于是有人发明了哈希算法来提高集合中查找元素的效率。这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储的那个区域。
hashCode方法可以这样理解:它返回的就是根据对象的内存地址换算出的一个值。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
8 、 ****String 、 StringBuffer 和 StringBuilder 的区别是什 么 ?
String是只读字符串,它并不是基本数据类型,而是一个对象。 从底层源码来看是一个final类型的 字符数组,所引用的字符串不能被改变,一经定义,无法再增删改。每次对String的操作都会生成 新的String对象。
StringBuilder 和 StringBuffer:都是可变的(mutable)。它们可以被多次修改,而不会创建新的对象.StringBuffer:是线程安全的。它提供了同步方法,确保在多线程环境下对字符串的修改是安全的。但是,这种同步机制会带来性能开销。StringBuilder:是线程不安全的。它没有提供同步方法,因此在多线程环境下使用时需要手动同步。由于没有同步开销,StringBuilder
在单线程环境下的性能优于StringBuffer
。
操作少量字符数据用 String;单线程操作大量数据用 StringBuilder;多线程操作大量数据用 StringBuffer。
9 、 ArrayList 和 linkedList 的区别
ArrayList:
基于动态数组实现。底层是一个数组,当数组满了之后,会自动扩容,通常扩容为原数组的 1.5 倍(具体扩容策略在不同版本的 JDK 中可能有所不同)。
ArrayList<Integer> list = new ArrayList<>();
list.add(1); // 底层会创建一个数组,并将元素添加到数组中
list.add(2);
AI写代码
LinkedList:
基于双向链表实现。每个元素是一个节点,每个节点包含数据部分和指向前后节点的指针。
LinkedList<Integer> list = new LinkedList<>();
list.add(1); // 底层会创建一个节点,并将元素添加到节点中
list.add(2);
AI写代码
10 、 HashMap 和 HashTable **的区别 **********
1、两者父类不同
HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类。不过它们都实现了同时 实现了map、Cloneable(可复制)、 Serializable(可序列化)这三个接口。
2、对外提供的接口不同
Hashtable比HashMap多提供了elments() 和contains() 两个方法。 elments() 方法继承自 Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的value的枚举。
contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实 上,contansValue() 就只是调用了一下contains() 方法。
3、对 null的支持不同
Hashtable:key和value都不能为null。
HashMap :key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性;可以有多个 key值对应的value为null。
4、安全性不同
HashMap是线程不安全的,在多线程并发的环境下,可能会产生死锁等问题,因此需要开发人员自 己处理多线程的安全问题。
Hashtable是线程安全的,它的每个方法上都有synchronized 关键字,因此可直接用于多线程中。
虽然HashMap是线程不安全的,但是它的效率远远高于Hashtable,这样设计是合理的,因为大部 分的使用场景都是单线程。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。
ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为 ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
5、初始容量大小和每次扩充容量大小不同
6、计算 hash值的方法不同
11 、 Collection 包结构,与 Collections **的区别 **********
Collection是集合类的上级接口,子接口有 Set、 List、 LinkedList、ArrayList、Vector、Stack、 Set; 是集合类的一个帮助类, 它包含有各种有关集合操作的静态多态方法,用于实现对各种集合的搜索、排序、线程安全化等操作。此类不能实例化,就像一个工具类,服务于Java的 Collection框架。
12 、深拷贝和浅拷贝的区别是什么 ?
浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指 向原来的对象.换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象.
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值.而那些引用其他对象的变量将指向 被复制过的新对象.而不再是原有的那些被引用的对象.换言之.深拷贝把要复制的对象所引用的 对象都复制了一遍.
13 、 fi nal 有哪些用法 ?
final也是很多面试喜欢问的地方,但我觉得这个问题很无聊,通常能回答下以下5点就不错了:
被final修饰的类不可以被继承
被final修饰的方法不可以被重写
被final修饰的变量不可以被改变.如果修饰引用,那么表示引用不可变,引用指向的内容可变.
被final修饰的方法,JVM会尝试将其内联,以提高运行效率
被final修饰的常量,在编译阶段会存入常量池中.
除此之外,编译器对final域要遵守的两个重排序规则更好:在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序 初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序.
14 、 ****static 都有哪些用法 ?
所有的人都知道static关键字这两个基本的用法:静态变量和静态方法.也就是被static所修饰的变量/ 方法都属于类的静态资源,类实例所共享.
除了静态变量和静态方法之外,static也用于静态块,多用于初始化操作:
public calss PreCache{static{//执行相关操作}} |
---|
此外static也多用于修饰内部类,此时称之为静态内部类.
最后一种用法就是静态导包,即 import static .import static是在JDK 1.5之后引入的新特性,可以用来指定导入某个类中的静态资源,并且不需要使用类名,可以直接使用资源名。
15 、 try catch finally , try 里有 return , fi nally 还执行么?
执行,并且finally的执行早于try里面的return
结论:
1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的 值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数 返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
16、多态的作用
多态的实现要有继承、重写,父类引用指向子类对象。它的好处是可以消除类型之间的耦合关系,增加类的可扩充性和灵活性。
多态允许你通过统一的接口来处理不同类型的对象,这样在添加新的类型时,不需要修改现有的代码,只需要实现相同的接口或继承相同的父类即可。这使得代码的扩展性大大增强。
17、什么是反射?
****
反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象, 都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所 有信息。
I 这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
应用场景有:要操作权限不够的类属性和方法时、实现自定义注解时、动态加载第三方jar包时、按需加载类,节省编译和初始化时间;
获取class对象的方法有:class.forName(类路径),类.class(),对象的getClass()
18、Java创建对象得五种方式?
(1)new关键字 (2)Class.newInstance (3)Constructor.newInstance
(4)Clone方法 (5)反序列化
19 、 简述线程、程序、进程的基本概念。 以及他们之间关系是什 么 ?
线程与进程相似,但线程是一个比进程更小的执行单位。 一个进程在其执行的过程中可以产生多个 线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代 码。
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序 即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算 机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如 CPU 时间,内存空 间,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而 各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系 统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同 时执行一个以上的程序段。