Java 基础

JDK, JRE, JVM 区别

  1. JDK, Java Development Kit, 针对程序员的产品

  2. JRE, Java Runtime Environment, Java 运行环境的集合

  3. JVM, Java 虚拟机,运行Java字节码文件, 跨平台核心

JDK> JRE >JVM

Java 有哪些数据类型

基本数据类型: 数值型(byte, short, int, long, float, double), 字符型 char, 布尔型 boolean

引用数据类型: 类 class, 接口 interface, 数组[]

基本数据类型和引用数据类型的内存分配有何区别

基本数据类型 被放到 JVM 的 栈 中,引用数据类型放到堆中

访问修饰符 public, private, protected

修饰符
当前类
同一包内
其他包

public

protected

×

private

×

×

面向对象三大特性

封装:

  • 我们不希望 类的成员变量被直接访问,而是通过变量的 setter 和 getter 函数进行修改和访问, 避免误操作修改成员变量的可能性。

继承:

  • 一个类可以被另一个类继承。被继承的类称为 父类,继承父类的类称为子类。 子类一旦继承父类,也就继承了

  • Java 中不允许多继承, 也就是一个类只能继承一个父类。

多态:

  • 父类中的成员函数可能在子类中有多种表现形式。比如我们起那么提到的 Animal 类 有一个 eat() 函数, 但是他的子类具体 吃 什么是多张多样的, 子类的 eat() 函数表现形式多种多样。

重载 (Overload) 和 重写 (Override) 的区别是什么?

  • 重写发生在子类与父类之间, 外壳不变,核心重写。重写方法返回值和形参都不能改变,访问修饰符无所谓

  • 重载是在一个类里面,方法名字相同, 而参数不同, 返回类型无所谓。

接口是什么?

接口是一种标准, 所有实现这个接口的类都必须重写这个类中的方法,看做实现接口的标准。类似于所有这个家用电器的充电器电压都是220V , 无论电器的种类,价格,都遵循这个标准。Java 不支持多继承,但是支持实现多个接口。

类的加载顺序

遵循1-3顺序即可

  1. 静态代码块优先

  2. 父类优先

  3. 非静态代码块优先于构造函数

== 和 equals 区别是什么

  • 如果 == 比较的是基本数据类型,那么比较的是两个基本数据类型的值是否相等

  • 如果 == 比较的是引用数据类型,那么比较的是两个对象是否指向同一块内存区域

  • equals 主要用于两个对象之间, 检测一个对象的意义是否等于另一个对象,通常需要在类中重写 equals方法进行自定义比较

equals 和 hashCode 的区别

  • equals 主要用于两个对象之间, 检测一个对象的意义是否等于另一个对象,通常需要在类中重写 equals方法进行自定义比较

  • hashCode() 返回一个int, 代表对象的内部地址

  • 若两个对象equals成立,则hashCode 一定成立

  • 若两个对象equals不成立,hashCode可能成立(因为可能有hash冲突)

  • 若两个对象hashCode成立,则equals 可能成立(因为可能有hash冲突)

  • 若两个对象hashCode不成立,则equals 一定不成立

什么是hashCode

hashCode() 的作用是获取哈希码。它实际上是返回一个int整数。这个哈希码的作用是确定该对象在hashMap 或是 hashSet中的索引位置。hashCode() 定义Java所有类的祖宗类 Object 当中,这意味着Java中的任何类都包含有hashCode()函数。

为什么要有hashCode?

一句话, 减少 equals 次数,提高执行速度

当把对象加入hashMap 或是 hashSet 中,通过计算hashCode来判断对象插入的索引位置。若发现有相同的hashCode对象,则需要调用equals方法来判断两个对象是否相等,若不想等,则正常插入对象。否则不再插入对象,

String,StringBuffer, StringBuilder 的区别是什么?

String
StringBuffer
StringBuilder

执行速度

最差(放在常量池中, final修饰)

其次

最高

线程安全

安全

安全

不安全

使用场景

少量字符串操作

多线程环境下大量操作

单线程环境下大量操作

String为什么要设计成不可变的

  1. 便于实现字符串常量池。在Java中,由于会大量的使用String常量,如果每一次声明一个String都创建一个String对象,那将会造成极大的空间资源的浪费。Java提出了String pool的概念,在堆中开辟一块存储空间String pool,当初始化一个String变量时,如果该字符串已经存在了,就不会去创建一个新的字符串变量,而是会返回已经存在了的字符串的引用。

  2. 线程安全。在并发场景下,多个线程同时读一个资源,是安全的,不会引发竞争,但对资源进行写操作时是不安全的,不可变对象不能被写,所以保证了多线程的安全。

  3. 加快访问速度。因为String是不可变的,所以尽最大可能保证了hashCode的唯一性。这就是为什么Map喜欢讲String 对象作为Key的原因。

什么是反射?

反射是一种机制,能够在程序运行时,动态的创建对象,获取类的所有信息, 提高了程序的灵活性。

反射有哪几种重要的API

Class 类核心方法:

  • Class.forName(String name), 静态方法, 用于获取关于指定类的 Class 对象

  • classObj.newInstance(), 通过默认构造方法,创建新的对象

  • classObj.getConstuctor(), 获得指定的public 修饰的构造方法的 Constructor

  • classObj.getMethod(), 获得指定的public 修饰的方法的 Method 对象

  • classObj.getField(), 获得指定的public 修饰的成员变量 Field 对象

什么是泛型?

泛型就是将类型参数化,其在编译时才确定具体的参数。

为什么使用泛型?

  1. 提高了代码的复用性

  2. 早期没有泛型的时候,都是将参数写成Object 类型,然后进行强制转换。而现在在编译时就能找出数据不匹配的问题。

Java 异常体系

Java 异常体系分为两部分, Erro 和 Exception, 两者都实现了 Throwable 接口。

Exception 需要程序员try catch 或者 throw 出去。而runtimeexception是在运行时的exception,程序员并不一定知道,得等运行时才会知道

Error: 内存溢出,系统崩溃,虚拟机错误,栈溢出,操作系统级别的

Java IO 中 有几种类型的流

按照输入输出来分: 有输入流和输出流

按照内容来分:字节流和字符流

两两组合,一共四种流

说一下JVM内存组成

JVM 内存分为两部分,共享区和私有区

共享区:被所有线程共享

  • 堆: 最大的一块,唯一目的存放对象实例,对于那些没有引用的对象,会被进行垃圾回收

  • 方法区: 虚拟机加载的类的信息, 常量,静态变量

私有区: 线程独享的

  • 程序计数器: 指向下一条执行指令的行号,分支,跳转

  • 虚拟机栈: 每一个方法执行的时候都会创建一个栈帧,用来存储该方法的局部变量,操作数栈,动态链接,方法返回地址

  • 本地方法栈: 本地方法栈与虚拟机栈的作用是一样的,区别在于虚拟机栈为虚拟机执行java方法服务,而本地方法栈为虚拟机执行native方法服务,native方法为本地方法,不是用java语言写的有可能是c或者c++写的

简述Java 垃圾回收(GC)

GC(garbage Collection) 用于回收不再使用的内存

GC 负责3项任务: 分配内容, 确保引用, 回收内存

GC回收的依据是对象有没有被引用,若没有则回收

垃圾回收算法

  1. 引用计数法,最简单,效率最低。JVM堆中被引用的对象有个计数器,为0被回收

  2. 跟踪回收算法.,构建一张图,图访问不到的对象被回收

  3. 压缩回收算法,扫描一遍全部对象,将活动的对象挪到一块集中的区域,将不活动的对象回收

  4. 复制回收算法, 将JVM堆平均分成两个部分,当一个部分用完时扫描这个部分,将所有活动的对象复制到另一部分,随后垃圾清理。

  5. 按代回收算法,在复制回收算法上对对象进行分类。对于那些经常使用的类扫描频率低一些,不经常使用的扫描频率高一些。

简述 Java 内存泄露

内存泄露指的是程序不在使用的对象或变量还在内存中占有空间。

内存泄露场景

  • 用 static 修饰变量,被放到 JVM 方法区中,很少被回收

  • 各种连接忘记关闭,数据库连接,网络连接,文件连接

  • 监听器,用于监听其他对象的行为

  • 不合理的作用域。如果一个变量定义范围 > 使用范围

请说明对象的浅复制和深复制

  • 浅复制:只对对象及其内部的变量进行复制,对象内引用的其他对象不进行复制。直接调用 clone()方法即可

  • 深复制: 不仅对 对象 及其内部的变量进行复制,对象内引用的其他对象也进行复制。需要通过序列化进行操作

Last updated