【面试】Java基础知识

目录

Java概述

面向对象和面向过程的区别

JVM JRE JDK

Java三大特性

基础语法

Java的八种基础数据类型,每个占多少字节?

Switch是否能作用在byte上,能否作用在long上,能否作用在String上?

Math.round(11.5)等于多少?Math.round(-11.5)等于多少?

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

访问修饰符

关键字

面向对象

面向对象和面向过程的区别

面向对象的五大基础原则

Java中接口interface和抽象类abstract的区别?

为什么重写equals还要重写hashcode?

值传递

IO流

Java中IO流分为几种?

BIO,NIO,AIO有什么区别?

反射

什么是反射机制?

反射机制的优缺点

反射机制的应用场景

Java获取反射的三种方法

常用API

String相关

基本类型Int和包装类型Integer有什么区别?

Object类?

Java中的异常

Error

Exception

异常的处理


Java概述

面向对象和面向过程的区别

面向过程:是分析解决问题的步骤,然后用函数把这些步骤一步一步地实现,然后在使用的时候一一调用则可。性能较高,所以单片机、嵌入式开发等一般采用面向过程开发

面向对象:是把构成问题的事务分解成各个对象,而建立对象的目的也不是为了完成一个个步骤,而是为了描述某个事物在解决整个问题的过程中所发生的行为。面向对象有封装、继承、多态的特性,所以易维护、易复用、易扩展。可以设计出低耦合的系统。 但是性能上来说,比面向过程要低。

 

JVM JRE JDK

JVM:Java虚拟机,能够跨平台运行

JRE:(Java运行环境)包含JVM,外加一些Java核心类库。想运行一个Java程序,只需要安装JRE即可

JDK:包含JRE和一些Java运行工具,和Java基础类库。包含了Java开发工具,也包括了JRE。

 

Java三大特性

封装

封装指的是属性私有化,根据需要提供setter和getter方法来访问属性。即隐藏具体属性和实现细节,仅对外开放接口,控制程序中属性的访问级别。

封装目的:增强安全性和简化编程,使用者不必在意具体实现细节,而只是通过外部接口即可访问类的成员。

继承

继承是指将多个相同的属性和方法提取出来,新建一个父类。

Java中一个类只能继承一个父类,且只能继承访问权限非private的属性和方法。 子类可以重写父类中的方法,命名与父类中同名的属性。

继承目的:代码复用。

多态

多态可以分为两种:设计时多态和运行时多态。

设计时多态:即重载,是指Java允许方法名相同而参数不同(返回值可以相同也可以不相同)。发生在同一个类中。函数方法名必须相同,看参数列表即可,无关返回值。

运行时多态:即重写, 1.发生在父类与子类之间 2.方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同 3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private) 4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常

 

多态目的:增加代码的灵活度。

使用多态时,父类在在调用方法时,优先调用子类的方法。如果子类没有重写父类的方法,则再调用父类的方法。

 

基础语法

Java的八种基础数据类型,每个占多少字节?

类型

位数

字节

作为成员变量默认值

byte

8

1

0

short

16

2

0

int

32

4

0

long

64

8

0L

float

32

4

0.0F

double

64

8

0.0D

char

16

2

"\u0000"

boolean

8

1

false

 

Switch是否能作用在byte上,能否作用在long上,能否作用在String上?

Switch(expr),expr的类型

  • Java5:byte、short、char、int
  • Java7:String

不支持long类型

 

Math.round(11.5)等于多少?Math.round(-11.5)等于多少?

Math.round(11.5)=12

Math.round(-11.5)=-11

四舍五入的原理在参数上加0.5,然后向下取整。

 

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

对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。

 

而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。

 

访问修饰符

 

关键字

final有什么用?

用于修饰类、属性和方法;

  • 被final修饰的类不可以被继承
  • 被final修饰的方法不可以被重写
  • 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的。

 

final finally finalize区别

  • final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写,修饰变量表示该变量是一个常量不能被重新赋值。
  • finally一般作用于try-finall代码块中。在处理异常的时候,通常把一定要执行的代码方法放在finally代码块中,表示不管是否出现该异常,该代码都会执行,一般用来存放一些关闭资源的代码。
  • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc()方法的时候,由垃圾回收器调用finalize(),回收垃圾。

this 关键字的用法

this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。

this的用法在Java中大体可以分为3种:

  • 1.普通的直接引用,this相当于是指向当前对象本身。
  • 2.形参与成员名字崇明,用this来区分
  • 3.引用本类的构造函数

super关键字的用法

super可以理解为指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。

super也有三种用法:

  • 直接引用:super相当于指向当前对象的父类的引用,这样就可以用super.xxx()来引用父类的成员
  • 子类中的成员变量或方法和父类中的成员变量或方法同名时,用super加以区分
  • 引用父类的构造函数:调用父类中的某一个构造函数

 

static存在的主要意义

static的主要意义在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法!

static关键字可以形成静态代码块以优化程序性能。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

 

static的独特之处

  1. 被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享。
  2. 在该类第一次被加载的时候,就会加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化。
  3. static变量值是在类加载的时候分配空间,以后创建类对象的时候不会重新分配。但可以重新赋值
  4. 被static修饰的遍历或者方法是优先于对象存在的,也就是说一个类加载完毕之后,即便没有创建对象,也可以去访问。

 

流程控制语句

  • break:跳出总上一层循环,不再执行循环(结束当前的循环体)
  • continue:跳出本次循环,继续执行下次循环(结束正在执行的循环,进入下一个循环条件)
  • return:程序返回,不再执行下面的代码(结束当前的方法,直接返回)

 

在java中,如何跳出多嵌套循环

可以在外面的循环语句定义一个标号,然后再里层循环体的代码中使用带有标号的break语句,即可跳出外层循环。

public static void main(String[] args) { ok: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { System.out.println("i=" + i + ",j=" + j); if (j == 5) { break ok; } } } }

 

面向对象

面向对象和面向过程的区别

面向过程

优点:性能比面向底线高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux、Unix等一般采用面向过程开发

缺点:没有面向对象易维护、易复用、易扩展

 

面向对象

有点:易维护、易复用、易扩展,由于面向对象的封装、继承、多态的特性,可以设计出低耦合系统,使系统更加灵活、更加易于维护

缺点:性能比面向过程低

 

面向过程是具体化的,流程化的,解决一个问题需要一步步分析,一步步实现。

面向对象是模型化的,你只需要抽象一个类,这是一个封闭的盒子。你只需要知道它有什么功能,然后用它就行了,不关心功能是如何实现的。

 

面向对象的五大基础原则

  1. 单一职责原则:类的功能要单一,不能包罗万象,跟杂货铺似的
  2. 开放封闭原则:对于扩展是开放的,对于修改是封闭的
  3. 里式替换原则:子类可以替换父类在任何父类能够出现的地方。比如说你可以代替你爸爸去奶奶家干活
  4. 依赖倒置原则:高层次的模块不应该愈来愈低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。例如:出国后你要说是中国人,而不是说你是哪个村的。中国人是抽象的,下面具体的哪个省市县村是具体的,你依赖的抽象是中国人,而不是你是某个村的。
  5. 接口分离原则:设计时多个与特定客户类有关的接口比采用一个通用的接口要好。比如手机里有看视频、玩游戏、听歌,把这几个功能拆分不同的接口,比在一个接口里要好得多。

 

Java中接口interface和抽象类abstract的区别?

抽象类和接口的对比

抽象类是用来捕捉子类的通用特性的,接口是抽象方法的集合。

从设计层面来说,抽象类是对类的抽象,是一种模板设计。接口是行为的抽象,是一种行为的规范。

 

相同点

  • 接口和抽象类都不能实例化
  • 都位于继承的顶端,用于被其他实现或继承
  • 都包含抽象方法, 其子类都必须覆盖写这些抽象方法

不同点

  • 接口使用哦interface关键字声明;抽象类使用abstract关键字声明
  • 接口子类使用implements实现接口;抽象子类使用extends来继承抽象类
  • 接口没有构造器;抽象有构造器
  • 接口默认public修饰,且不允许定义为privae和protected;抽象类可以是任意访问修饰符
  • 一个类可以实现多个接口;一个类只能继承一个抽象类
  • 接口的字段默认是static和final的;抽象类的字段声明是任意的

 

 

什么是抽象类

用abstract修饰的类叫做抽象类,其中用abstract修饰的方法是抽象方法。抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类。抽象类不能实例化,抽象方法不能有方法体。

抽象类生来是被继承的,它的抽象方法必须在子类中被重写。

抽象类隐藏了一个规范问题:也就是“是不是”的问题,一个抽象类animal有eat和sleep方法,它的子类dog和cat都要继承extends其中的方法。

什么是接口

接口和抽象类比较相似。它是对外提供的一些功能的申明。使用interface关键字修饰。

接口的成员变量默认Wiestatic final,所有方法都是public abstract的。抽象类是用extends去继承,接口使用implements去实现。

接口和抽象类的区别

抽象类描述的是“是不是”的问题,而接口描述的是“有没有”的问题。

一个类可以实现多个接口,但是只能继承一个抽象类。接口还可以间接实现多重继承。

应用场景

在项目中,接口被用在常用的功能上,便于日后的维护和添加删除,而抽象类更倾向于充当公共类角色,不适用于日后重新对代码修改。

其它

Java8以后,接口可以直接定义default和static方法了。default是解决接口升级问题,static解决默认方法中的代码重复问题。java9后可以有private方法,只能自己使用。抽象类可以有protect和private方法。

 

为什么重写equals还要重写hashcode?

这两个方法全部都是object类定义的方法,只要继承了object类的类,默认继承这两个方法。

equals()相当于“==”默认是比较这两个引用对象的实际存储的内存地址是否相同,Object的hashCode()默认是对两个对象存储地址值的哈希。

当equals重写之后,它为true时两个对象的内存地址不一定一样,如果这个时候不重写hashCode()方法,那么这两个对象的哈希值肯定不一样。

当把这个对象应用在散列表(如hashMap,hashTbale,hashSet)的key值时,是先比较hashCode()方法,因为通过哈希值比较效率更高,哈希值不同,两个对象肯定不是同一个对象,但是相同的时候有可能是产生哈希冲突,所以必须再通过equals()方法比较两者地址值。如果只重写equals方法,不重写hashCode()方法。但此时不相等就不继续比较equals,认为是两个不同的key。这样就违背了hashMap的业务逻辑,出现了相同的key。

 

举个例子:这里有两台手机iphone11,根据原始判断它们不可能是==的,也就是调用equals()方法时为true,这是两台手机。但是重写equals方法后,放宽了从内存地址比较的要求,因为这两个都是iPhone ,还都是11,所以equals判断是相等的。当我们把这两台手机作为key,存入hashMap中的时候,先调用的hashCode()方法,hashCode的逻辑因为手机实际的内存地址是不同的,所以判断为两个对象。但是!实际上,在我们的判断逻辑里,这两个手机是相同的,不可以作为两个key存入hashMap!是违背了hashMap的业务逻辑的!

Float类和Double类都重写对于的equals方法,在比较之前都会判断是否同属于Float对象或Double对象,如果不是直接返回false,如果是再继续比较对应的数值大小。

 

值传递

Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。

 

IO流

Java中IO流分为几种?

  • 按照流的流向分,可以分为输入流和输出流;
  • 按照操作单元划分,可以划分为字节流和字符流;
  • 按照流的角色划分为节点流和处理流

Java IO流共涉及到40多个类,都是从4个抽象类基类中派生出来的。

  • InputStream/Reader:所有的输入流的基类,前者是字节输入流,后者是字符输入流
  • OutputStream/Writer:所有的输出流的基类,前者是字节输出流,后者是字符输出流。

 

BIO,NIO,AIO有什么区别?

简答

  • BIO:Block IO 同步阻塞式IO,是我们平常使用的传统IO,特点是模式简单使用方便,并发处理能力低。
  • NIO:Non IO 同步非阻塞IO,是传统IO的升级,客户端和服务器通过Channel通讯,实现了多路复用。
  • AIO:Asynchronous IO是NIO的升级,也叫NIO2,实现了异步非阻塞IO,异步IO的操作基于事件和回调机制

 

反射

什么是反射机制?

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

静态编译和动态编译

  • 静态编译:在编译时确定类型,绑定对象
  • 动态编译:在运行时确定类型,绑定对象

 

反射机制的优缺点

  • 优点:运行期类型的判断,动态加载类,提高代码灵活度
  • 缺点:性能瓶颈:反射相当于一系列解释操作,通知JVM要做的事情,性能比直接的Java代码要慢的多。

 

反射机制的应用场景

  • JDBC连接数据库时使用ClassForName()
  • Spring中的xml配置中

 

Java获取反射的三种方法

  • 通过new对象实习反射
  • 通过路径实现发射机制
  • 通过类名实现反射机制

 

 

常用API

String相关

字符型常量和字符串常量的区别

  1. 形式上:字符常量是单引号引起来字符,字符串常量是双引号引起来的若干个字符
  2. 含义上:字符常量相当于一个整型值(ASCII值),可以参加表达式运算,字符串常量代表一个地址值。
  3. 占内存大小,字符常量只占一个字节,字符串常量占若干个字节。

 

什么是字符串常量池?

字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串。在创建字符串时JVM会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

 

String是基本数据类型吗?

不是。基础数据类型:byte short int long double float char boolean;除了基础数据类型,都是引用类型。

 

String的特性

  • 不变性:对它的任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于一个对象被多个线程共享边频繁访问的时候,可以保证数据的一致性。
  • 常量池优化:String对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用。
  • final:使用final来定义String类,表示String类不能被继承,提高了系统的安全性。

 

String str="i"与 String str=new String(“i”)一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

 

在使用 HashMap 的时候,用 String 做 key 有什么好处?

HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。

 

String和StringBuffer、StringBuilder区别是什么?

可变性

String类中使用字符输出保存字符串,private final char value[],所以string对象时不可变的。StringBuilder和StringBuffer都继承自AbstractStringbuilder类,底层也是用char[] value实现的,但这两种对象时可变的。

 

线程安全性

String中的对象是不可变的。也可以理解为常量,线程安全。

StringBuilder和StringBuffer的公共父类,定义了一些字符串的基本操作。如expandCapacity、append、insert、index()等公共方法。StringBuffer是线程安全的,StringBuilder是效率最高的,但是非线程安全。

 

性能

每次String类型改变,都会生成一个新的String对象,然后将该指针指向新的String对象。StringBuffer每次都会对StringBuffer对象本身进行操作,相同情况下StringBuilder相比使用StringBuffer能获得10%-15%的性能提升。

 

应用场景

对于操作少量的数据 = String

单线程操作字符串缓冲区下操作大量数据 = StringBuilder

多线程操作字符串缓冲区下操作大量数据 = StringBuffer

 

基本类型Int和包装类型Integer有什么区别?

  1. 包装类型默认值为null,基本类型不可以。int默认值为0
    1. 包装类型可以用于POJO中,基本类型不可以。举个例子:数据库查询结果为Null,如果使用基本类型,需要自动拆箱,这时候会报空指针异常。
  2. 包装类型可用于泛型,基本类型不可以。
    1. 因为泛型咋编译的时候会进行类型擦除,只保留原始类型,原型只能是Object及其子类。
  3. 基本类型比包装类型更高效
    1. 基本类型在栈中存储具体的数值,包装类型则存储的是堆中的引用。
  4. 两个包装类型值相同,但不相等
    1. “==”判断的是两个地址是否相等,所以结果是false
    2. equals()方法得到的是true,因为比较的是两个int值是否相等。
  5. 自动装箱和自动拆箱
    1. 基本类型转换成包装类型叫装箱,使用Integer.valueof()
    2. 包装类型转换为基本类型叫拆箱,使用Integer.intValue()
// 1)基本类型和包装类型
int a = 100; Integer b = 100;
System.out.println(a == b); // true, b会自动拆箱

// 2)两个包装类型
Integer c = 100; Integer d = 100;
System.out.println(c == d); // true,依照上面第四条结果应该为false,但这里涉及到缓冲池。

// 3)两个基本类型
c = 200; d = 200;
System.out.println(c == d); // false

当一个int类型的数据在 -128~127 之间(即一个字节)的时候,当把它包装成一个Integer类型时,会把这个数据放在一个缓冲池中,在下次把同一个数据包装成Integer类型时,就直接去缓冲池中拿,这就是设计模式中的“享元模式”。

因此,第二段代码为true,是从缓冲池中拿的两个数;第三段代码由于不在-128~127范围内,new出了两个Integer对象,所以false。

Float和Double没有缓冲池
Boolean和Byte 全部缓存
Short Int Long 缓存-128~127
Character <=127

 

 

Object类?

类Object是每个类的超类。Objects类也不例外,是Object类的子类。

  • clone 创建并返回此对象的副本
  • equals 表示其他对象是否与此对象相等
  • hashCode 返回该对象的哈希吗值
  • toString 返回该对象的字符串表示
  • wait 在其他线程调用此对象的notify()或者notifyAll()方法前,线程等待。释放锁
  • notify 唤醒在对象监视器上等待的单个线程
  • notifyAll 唤醒在此对象监视器上等待的所有线程。
  • getClass 获取Object的运行时类
  • finalize() 垃圾回收器调用此方法

 

Java中的异常

所有的异常都是由Throwable继承而来,在下一层立即分解为两个分支:Error和Exception

Error

Error描述的是Java运行时系统的内部错误或者资源耗尽错误,应用程序不应该抛出这种错误。除了通知用户外,尽量使程序安全落地。比如OOM、ThreadDeath等。编译器不会对错误进行检查

Exception

Exception又分为两种结构,运行时异常RuntimeException和被检查的异常CheckedException。

运行时异常RuntimeException

Java编译器不会检查它。由程序错误导致的异常属于RuntimeException,有错误的类型转换、数组访问越界、空指针异常

被检查异常CheckedException

Java编译器会检查它。程序本身没有问题,由于像IO错误这类问题引发的异常属于其他异常。常见场景有,试图在文件尾部读取数据、试图打开一个不存在文件、SQLException

 

一个方法必须声明所有可能抛出的被检查异常。因为非受查异常要么是不可控的,即Error异常;要么是应该避免发生的RuntimeException。RuntimeException应该考虑的是修正自己的代码逻辑保证不出问题,而不是把关注点放在发生错误的可能性上。

 

异常的处理

try...catch...finally

把可能发生异常的代码块放在try语句块中,如果发生了在catch子句中声明的异常,就会进入catch子句中进行异常处理。

 

finally通常用于资源的关闭,try...catch语句块中即便有return语句,也要等到finally语句中执行完毕,再return

什么时候finally不执行

  1. 程序所在线程死亡
  2. finally语句块中有异常
  3. Daemon线程中的finally有可能不被执行

Throws

异常的另一种处理方式是什么都不做,把它传递给调用者,如果出现了错误,就让调用者自己去处理。throws说明符写在方法名后,可以跟多种异常类型,逗号隔开。throw写在方法体中,抛出异常实例,由方法体中的语句处理。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值