- Java基础面试问题总结
- 前言
- 1.聊一聊java?谈谈你的理解?
- 2.JDK,JRE,JVM的区别?
- 3.基本的数据类型有哪些?占多少内存?
- 4.类型之间怎么转换?有哪些要求?
- 5.说一说break,continue,return的区别?
- 6.== 与equals的区别?
- 7.聊一聊面向对象,什么是对象?
- 8.说一说this与super的区别?
- 9.重写与重载的区别?
- 10.聊一聊final与static修饰符
- 11.异常有哪些类型?怎么处理异常?
- 12.什么是多态?
- 13.什么是向上转型?向下转型?
- 14.抽象类与接口的区别?
- 15.字符串类型有哪些,有什么区别?
- 16.什么是正则表达式?怎么使用?
- 17.什么是自动装箱与自动拆箱?
- 18.浮点数运算不精确问题怎么解决?
- 19.io流有哪些?简述一下?
- 20.什么是序列化与反序列化?
- 21.什么是集合?有哪些类型?
- 22.ArrayList与linkedList有哪些区别?
- 23.hashMap的底层原理与储存过程?
- 24.说一说hashSet与treeSet?
- 25.进程与线程?
- 26.线程的五态模型?
- 27.多线程的创建方式有哪两种,两者有什么区别?
- 28.同步锁是什么?悲观锁和乐观锁有什么区别?
- 29.聊一聊单例模式?
- 30.注解是什么?有哪些类型的注解?
- 31.聊一聊反射技术?
本部分主要为个人在java基础学习阶段,对于java基础知识的一部分问题总结,包括基础知识的面试题等一些问题。对此整理为总结笔记,便于后期复习java基础知识与后续面试准备,如有个别错误可私信,之后会及时修正补充。
1.聊一聊java?谈谈你的理解?Java是一门面向对象编程语言,不仅吸收了C语言的各种优点,还摒弃了C里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。
简单来说:Java是一种可以撰写跨平台应用程序的、面向对象的程序设计语言。简单说,Java就是一种语言,不过是一种针对jvm的语言,Java编译后是字节码,而jvm会把这些字节码解释成机器码,然后做出相应的动作。
2.JDK,JRE,JVM的区别?JDK java的开发工具包,提供Java的开发环境和运行环境,包含JRE和java源码编译器javac,以及java调试分析工具
JRE java的运行环境,运行java文档
JVM java虚拟机,运行java中.class文档的工具,提供运行环境
基本数据类型有八种:
整数型 byte-1字节 short-2字节 int-4字节 long-8字节
浮点型 float-4字节-单精度 double-8字节-双精度
字符型 char-2字节
布尔型 boolean-1位
小转大,直接转 – 隐式转换
大转小,强制转 – 显式转换,格式:byte b = (byte) a;
浮变整,小数没 – 浮点型转整形是直接舍弃所有的小数部分的,不会四舍五入
类型能否转换,取决于类型的取值范围,而不是字节数,字节数只能做大概的参考
注:boolean类型不参与类型转换
break用于直接强行跳出当前循环,不再执行剩余代码。当循环中遇到break语句时,忽略循环中任何其他语句和循环条件测试,程序控制在循环体后面的语句重新开始。所以当多层循环嵌套,并且break语句出现在嵌套循环中的内层循环时,它将仅仅只是终止了内层循环的执行,而不影响外层循环的执行。
continue 用于停止当次循环,回到循环起始处,进入下一次循环 *** 作。continue 语句之后的语句将不再执行,用于跳过循环体的一部分语句,也就是不执行这部分语句,而不是跳出整个循环执行下一条语句,这就是continue与break的主要区别。简单来说,continue只是中断一次循环的执行而已。
return语句是一个跳转语句,用来表示从一个方法返回(返回一个值或其他复杂类型),可以使用程序控制返回到调用该方法的地方。当执行Main方法时,return语句可以使程序执行返回到Java运行系统。
对于多重循环的跳出 *** 作,可以在多重循环的外面定义一个标识,然后在循环体里使用带有标识的break语句,这样即可跳出多重循环。
6.== 与equals的区别?== 对于基本类型比较的是值,对于引用类型比较的是地址值。
equals 本质上底层源码也是 ==,默认情况下equals比较的是引用地址值,进行重写之后可进行值得比较。
如 String Integer底层就对equals进行了重写,比较的是数值是否相等。
首先面向对象是一种思想,在面向对象出现以前主要是以c语言为首的面向过程,面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现。
所谓的对象就是现实中所存在的各种各样的事物,都可以将其各自的属性特点进行抽象封装成一个对象,所以也就有万物皆对象这一说法。
面向对象的三大特征是封装、继承和多态
1、封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高代码的复用性和安全性。
2、继承
提高代码复用性;继承是多态的前提。
3、多态
父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。
this代表对本类同名对象的引用/super代表的是对父类同名对象的引用
本类成员变量与局部变量重名,this.变量名
本类成员变量与父类成员变量重名,super.变量名
this(); 调用本类无参构造 this(参数)调用本类的含参构造
super();调用父类无参构造,super(参数)调用父类对应含参构造
注:super的使用基于继承的前提,没有父子关系继承就没有super
This与super的使用都需要在构造方法的第一行
子类重写了父类的方法之后,需要使用super.方法名(参数列表)来调用
重载:在一个类中的现象:同一个类中,存在方法名相同,参数列表不同的方法。
重载意义:是为了外界调用时的方便,不管传入什么样的参数,都可以匹配到对应同名的方法。
重写:指建立了继承关系以后,子类对父类的方法不满意,可以重写,遵循两同两小一大原则。
重写的意义:在不修改源代码的情况下,进行功能的修改与拓展(OCP原则:面向修改时关闭,面向拓展时开放)
final表示最终,用来修饰的类为最终类,不可被继承;用来修饰的方法为最终实现,不可重写;用来修饰的常量,值不可被修改,常量定义时必须赋值。
static所修饰的资源称为静态资源,可以修饰变量,方法,代码块。静态资源属于类资源,随类的加载而加载,优先于对象进行加载;静态资源被全局对象共享;静态只能调用静态。
Java异常的顶层父类为Throwable,并实现了Serializable接口。由Throwable派生出来的异常有两种,分别为Error类与Exception。Error,即错误,代表JVM本身的错误,处理程序运行环境方面的异常,不能通过代码处理。比如OutOfMemoryError,AWTError等。Exception:即异常,程序运行时发生,可以被java异常处理机制使用。比如IOException,SQLEXception,RuntimeException等等。
异常的处理方式有两种,使用try…catch捕获或throws抛出。
try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。
finally – finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
throw – 用于抛出异常。
throws – 用在方法签名中,用于声明该方法可能抛出的异常。主方法上也可以使用throws抛出。如果在主方法上使用了throws抛出,就表示在主方法里面可以不用强制性进行异常处理,如果出现了异常,就交给JVM进行默认处理,则此时会导致程序中断执行。
同一 *** 作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:就是用父类的引用指向子类的对象。多态的前提是继承、有方法的重写;在多态中,编译看左边,运行看右边。多态减轻了代码的维护性,提高了代码的扩展性。
13.什么是向上转型?向下转型?向上转型就是用父类的引用变量去引用子类的实例,这是允许的。当向上转型之后,父类引用变量可以访问子类中属于父类的属性和方法,但是不能访问子类独有的属性和方法。
并不是所有的对象都可以向下转型,只有当这个对象原本就是子类对象通过向上转型得到的时候才能够成功转型。向下转型之后可以重新访问子类的属性和方法。
类的修饰符不同:抽象类使用abstract修饰,接口使用interface修饰
类内部方法不同:抽象类中可以有不是抽象的方法,接口中的方法必须是抽象的
实现方式不同:抽象类的子类使用extends来继承,接口使用implements来实现
构造函数不同:抽象类可以有构造方法,接口不能有
main方法不同:抽象类中可以写main方法并可以运行,接口不能有
实现数量不同:单继承,多实现. 类只能继承一个抽象类,可以实现多个接口
访问修饰符不同:抽象类中的方法可以是任意修饰符,接口中的方法默认使用public修饰
字符串类型有String、StringBuffer、StringBuild
String声明的是不可变的对象,每次 *** 做都会生成新的对象,然后将指针指向新的对象。而StringBuffer、StringBuild都可以在原来的基础上使用append()进行拼接,提高了效率。StringBuffer 因为源码中添加了同步synchronized,在线程上是安全的,没有StringBuild高效,适用于多线程环境。StringBuild,在线程上不安全,更为高效,适用于单线程环境。
正则表达式(Regular expression)是用于描述一组字符串特征的模式,用来匹配特定的字符串。通过特殊字符+普通字符来进行模式描述,从而达到文本匹配目的工具。
使用时通过regex来定义字符串的规则。
自动装箱 ----- 基本类型的值 → 包装类的实例
自动拆箱 ----- 基本类型的值 ← 包装类的实例
将8大基本类型转化为包装类型之后,便于使用。
自动装箱和自动拆箱的实现过程:
装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。
使用BigDecimal来解决浮点数不精确问题,将浮点数转为bigDecimal类型的数据,进而在利用bigDecimal的add,subtract,multiply,divide等进行加减乘除运算。
19.io流有哪些?简述一下?按功能分:输入流(input)、输出流(output)
按类型分:字节流、字符流
1.字节流输入 InputStream抽象类 字节输入流的所有类的超类/抽象类 FileInputStream子类 ( *** 作文件的字节输入流) 直接插在文件上读取文件 BufferedInputStream子类(缓冲字节输入流) BufferedInputStream(InputStream in) BufferedInputStream(new FileInputStream(String pathname)) 2.字节流输出 OutputStream抽象类 FileOutputStream 子类 FileOutputStream(String name) BufferedOutputStream 子类 BufferedOutputStream(OutputStream out) 1.字符流输入 Reader抽象类 FileReader--子类 ( *** 作文件的字符输入流) FileReader(String fileName) BufferedReader--子类 (缓冲字符输入流) BufferedReader(Reader in) BufferedReader(new FileReader(String fileName)) 2.字符流输出 Writer抽象类 FileWriter--子类 FileWriter(String fileName) BufferedWriter--子类 BufferedWriter(Writer out)20.什么是序列化与反序列化?
序列化:ObjectOutputStream 程序中的对象输出到文件中
方法: out.writerObject();
反序列化:ObjectInputStream 序列化后文件读入程序
方法: in.readObject();
集合就是一个放数据的容器,准确的说是放数据对象引用的容器;集合类存放的都是对象的引用,而不是对象的本身;集合类型主要有3种:set(集)、list(列表)和map(映射)。List中有ArrayList与linkedList,set集中有HashSet与ThreeSet,Map中有HashMap和ThreeMap。
22.ArrayList与linkedList有哪些区别?- ArrayList的实现是基于数组来实现的,linkedList的基于双向链表来实现。这两个数据结构的逻辑关系是不一样,当然物理存储的方式也会是不一样。
- linkedList比ArrayList更占内存,因为linkedList的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
- 对于随机访问,ArrayList要优于linkedList。
- 对于插入和删除 *** 作,linkedList优于ArrayList(理论上),实际并非如此(实际上ArrayList不论是插入还是删除效率,在元素数量趋多时,都是要优于linkedList的),因这其中涉及数组与链表在元素 *** 作方式、时间与空间上的复杂度计算问题,所以具体问题须具体分析和佐证。
- HashMap的结构是数组+链表 或者 数组+红黑树 的形式
- HashMap底层的Entry[ ]数组,初始容量为16,加载因子是0.75f,扩容按约为2倍扩容
- 当存放数据时,会根据hash(key)%n算法来计算数据的存放位置,n就是数组的长度,其实也就是集合的容量
- 当计算到的位置之前没有存过数据的时候,会直接存放数据
- 当计算的位置,有数据时,会发生hash冲突/hash碰撞
- 解决的办法就是采用链表的结构,在数组中指定位置处以后元素之后插入新的元素
- 也就是说数组中的元素都是最早加入的节点
- 如果链表的长度>8时,链表会转为红黑树,当链表的长度<6时,会重新恢复成链表
set是一个不包含重复数据的无序的Collection集合
HashSet : 底层是哈希表,包装了HashMap,相当于向HashSet中存入数据时,会把数据作为K,存入内部的HashMap中。当然K仍然不许重复。
TreeSet : 底层是TreeMap,也是红黑树的形式,便于查找数据
进程:运行中的程序,动态的。进程具有独立性、动态性、并发性
线程(Thread):是OS能够进行运行调度的最小单位,每个线程在共享同一个进程中的内存的同时,又有自己独立的内存空间。
1.新建状态(New) : 当线程对象创建后就进入了新建状态.如:Thread t = new MyThread();
2.就绪状态(Runnable):当调用线程对象的start()方法,线程即为进入就绪状态.
处于就绪(可运行)状态的线程,只是说明线程已经做好准备,随时等待CPU调度执行,并不是执行了t.start()此线程立即就会执行
3.运行状态(Running):当CPU调度了处于就绪状态的线程时,此线程才是真正的执行,即进入到运行状态
就绪状态是进入运行状态的唯一入口,也就是线程想要进入运行状态状态执行,先得处于就绪状态
4.阻塞状态(Blocked):处于运状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入就绪状态才有机会被CPU选中再次执行.
根据阻塞状态产生的原因不同,阻塞状态又可以细分成三种:
等待阻塞:运行状态中的线程执行wait()方法,本线程进入到等待阻塞状态
同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用),它会进入同步阻塞状态
其他阻塞:调用线程的sleep()或者join()或发出了I/O请求时,线程会进入到阻塞状态.当sleep()状态超时.join()等待线程终止或者超时或者I/O处理完毕时线程重新转入就绪状态
5.死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期
27.多线程的创建方式有哪两种,两者有什么区别?第一种创建方式是通过继承Thread类,优点: 编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。缺点: 自定义的线程类已继承了Thread类,所以后续无法再继承其他的类。
第二种创建方式是实现Runnable接口,优点: 自定义的线程类只是实现了Runnable接口或Callable接口,后续还可以继承其他类,在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码、还有数据分开(解耦),形成清晰的模型,较好地体现了面向对象的思想。缺点: 编程稍微复杂,如想访问当前线程,则需使用Thread.currentThread()方法。
同步锁是为了保证线程占用资源时数据的安全,所添加的一种防止其他线程抢占正在使用资源的一种方式。
悲观锁:总是假设最坏的情况,即每次去拿数据都认为会被其他线程修改,因此在每次拿数据时都会上锁,其他线程想要拿这个数据时就会阻塞直到它拿到锁。传统的关系型数据库中的诸如行锁、表锁等,Java中的同步关键词synchronized的实现都是悲观锁。
乐观锁:总是假设最好的情况,即每次去拿数据的时候都认为其他线程不会修改,常常使用版本号和CAS算法实现。例如MySQL中多版本并发机制(MVCC)就是用版本号进行控制避免了加锁,提高程序性能。乐观锁在读多于写的情况下可以提高程序性能。
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。单例类只能有一个实例;单例类必须自己创建自己的唯一实例;单例类必须给所有其他对象提供这一实例。
单例模式主要有懒汉式和饿汉式两种。
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。同时也因此会随着实例化占用一定内存,但相应的调用也会非常迅速。
懒汉式是延迟加载实例化的对象,只有在第一次调用的时候才会实例化对象,懒汉式是非线程安全的。并发情况下可能会出现多个实例化对象。
注解就是给某个注解标注的类或者方法一种特定行为的描述。
注解有JDK自带的注解,元注解,自定义注解等。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)