八股文 -- Java基础和集合框架
八股文 -- Java基础和集合框架
- 1. Java 基础
- JVM, JRE, JDK的关系是什么
- Switch(expr) 中的expr可以用什么类型
- 访问修饰符public, private, protected和default的区别
- final, finally, finalize的区别
- 讲一下static关键字
- 描述一下 Java OOP
- Overload和Override的区别是什么
- 构造方法能不能被重写
- 说一下抽象类
- ---- 说一下接口的作用
- 抽象类可以用final修饰吗, 可以被实例化吗
- ---- 说一说String类
- ---- String为什么要设计成不可变的
- String, StringBuilder和StringBuffer的区别
- 什么是字符串常量池
- Java中的基本类型包括哪些, 基本类型的优点是什么
- Integer和Int的区别
- 包装类是什么? 基本类型和包装类型有什么区别
- 什么是反射
- --- 为什么需要泛型, 介绍下泛型
- 什么是泛型中的限定通配符
- 讲一讲Error和Exception
- throw和throws的区别是什么
- Java常见异常有哪些
- try-catch-finally 中, 如果catch中有return, finally还会执行吗
- Java变量命名规范
- i++ 和 ++i的区别
- Object类有哪些方法
- --- 什么是hashCode以及为什么需要hashCode
- --- hashCode和equals的关系 /为什么重写equals一定要重写hashCode方法
- 说一下静态绑定和动态绑定
- 如何判断Double的0值
- Double和Float是如果在内存中储存的
- 2. Java 集合框架
1. Java 基础
JVM, JRE, JDK的关系是什么
- JVM是虚拟机, 负责运行Java程序
- JRE是Java运行环境, 包括Java虚拟机, Java类库
- JDK是Java Development Kit 包括JRE和编译器和其他工具, 比如Java Doc
Switch(expr) 中的expr可以用什么类型
- 可以是 byte, short, char, int, string, enum
访问修饰符public, private, protected和default的区别
- 访问修饰符可以修饰方法, 成员变量. 默认是default
- public 是对所有类可见
- protected是只对一个包内的本类和子类可见
- private是只对本类可见
- default是对同一包的所有类可见
final, finally, finalize的区别
- final
- 修饰变量表示变量值不能被改变
- 修饰方法表示方法不能被重写但是可以被继承
- 修饰类表示类不能被继承
- finally
- fianlly是异常处理中用的关键字
- 表示不管是否发生异常, finally里的语句一定会被执行
- 即使在finally之前有return 比如在try中或者catch中, finally里的代码还是会被执行
- 一般会把资源释放的代码放在finally里, 比如关闭文件等
- finalize: 是Object的自带方法, 和垃圾回收有关
讲一下static关键字
- static关键字可以修饰 变量, 方法, 常量, 类
静态成员变量 和 静态成员常量
- 一个类的所有实例共享静态成员变量, 直接用类名调用
- 即使没有对象实例, 静态成员也存在
//Example: 给每个雇员产生unique ID
public void setId() {
id = nextId;
nextId++;
}
harry.id = Employee.nextId;
Employee.nextId++;
静态成员方法
- 静态方法跟类的对象没有关系, 不管有没有对象实例, 静态方法都存在. 也是直接用类名调用
- 静态方法不能使用非静态成员变量, 但是可以使用静态成员变量
什么时候使用静态方法:
- 当一个方法不需要使用对象的状态, 比如成员变量和成员方法, 也就是所需的参数都是外部直接传入的, 比如:
Math.pow
- 当一个方法使用的都是静态成员变量时
静态类
- 只有内部类可以是静态的, 也只有内部类可以用static关键字修饰
- 静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似
- 它不能使用外部类的非static成员变量或者方法
- 因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象
描述一下 Java OOP
封装
- 封装是将一个概念或者物体封装成一个类. 在类中通过成员变量和成员方法描述这个概念或者物体
比如一个Car类用来描述车这个物体, 那么成员变量可能包括车轮, 排量等描述一个车的物理参数. 成员变量可以包括drive, stop等用来描述车具体的行为.
继承
- 继承的作用是提高代码的复用性, 去除冗余代码, 避免复制代码, 提升代码的拓展性. 在设计代码时, 我们可以将多个类中重复出现的成员变量和方法封装成父类, 这样子类可以通过继承的方式具有父类所有的特性, 并且可以增添只属于子类的方法和变量. 比如之前说的car这个类, 我们可以将所有车共有的基本参数比如车门, 方向盘以及共有的行为比如drive, stop设计成父类. 然后不同牌子的车可以继承car这个父类, 并加入不同品牌特有的feature等.
多态
- 个人觉得Java中多态是基于继承的概念. 然后Java中多态是通过两个方面体现的:
- override和overload: override就是子类拥有父类的方法, 并且可以对父类的方法根据子类的需要进行重写. override必须保持方法的名字, 参数列表和返回值不变, 具体实现可以变. overload是同一个类中可以有方法名一样的方法, 方法的参数和返回值可以不变. Java通过方法的参数列表判断调用哪个方法. 所以每个重载的方法都必须有一个独一无二的参数类型列表. 最常见的是构造方法overload.
- 向上转型和向下转型: 在Java中一个变量既可以是子类的类型, 也可以是父类的类型. 最常见的是在写方法时, 参数列表可以使用父类的类型, 这样可以对所有子类使用. 在参数传递时编译器会自动进行向上转型. 然后在方法的实现中可以通过instantof关键字判断变量的实际类型, 并使用强转进行向下转型, 然后进行不同的操作. 这样可以节省代码量, 去除冗余代码.
Overload和Override的区别是什么
- override和overload: override就是子类拥有父类的方法, 并且可以对父类的方法根据子类的需要进行重写. override必须保持方法的名字, 参数列表和返回值不变, 具体实现可以变.
- overload是同一个类中可以有方法名一样的方法, 方法的参数和返回值可以不变. Java通过方法的参数列表判断调用哪个方法. 所以每个重载的方法都必须有一个独一无二的参数类型列表. 最常见的是构造方法overload.
构造方法能不能被重写
- 构造方法不能被继承, 所以不能被重写
说一下抽象类
- 用abstract修饰的类为抽象类, 一般抽象类都包括至少一个或多个抽象方法. 也存在没有抽象方法的抽象类, 用abstract修饰是为了表明这是子类的基类.
- 其中抽象方法只有方法声明没有具体实现,具体是现实是由子类提供. 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法. 抽象类不能被实例化,即不能通过new生成一个抽象类的对象).
- 抽象类不能被实例化,即不能通过new生成一个抽象类的对象, 作用是为某类定义通用方法. (比如一个算几何图形面积和周长的类可以定义两个抽象方法计算面积和周长, 而具体实现通过不同图形子类定义)
- 构造方法必须声明为Protected(因为要供子类使用)
- 子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类)
---- 说一下接口的作用
抽象类可以用final修饰吗, 可以被实例化吗
- 不能, 因为用final修饰的类不能被继承,而抽象类需要子类去重写抽象类的方法
- 抽象类也不能被实例化.
---- 说一说String类
---- String为什么要设计成不可变的
String, StringBuilder和StringBuffer的区别
- String是不可变对象, 也就是对String的任何操作都会生成新的对象
- StringBuilder和StringBuffer是可变的字符串对象, 但是StringBuilder是线程不安全的, StringBuffer是线程安全的, StringBuffer对方法加入了同步锁synchronized
什么是字符串常量池
- 为了减少内存开销, 字符串常量池可以避免重复创建字符串, 当需要一个字符串时, 首先在字符串常量池中寻找字符串是否已经存在
Java中的基本类型包括哪些, 基本类型的优点是什么
Integer和Int的区别
- 每一个基本类型都对应有一个包装类, Integer就是包装类, int就是基本类型. 包装类是引用类型, 属于Object类, 所以可以使用集合容器, 并且值可以等于null.
包装类是什么? 基本类型和包装类型有什么区别
- 每一个基本类型都对应有一个包装类, 包装类是引用类型, 属于Object类, 所以可以使用集合容器, 并且值可以等于null
- valueOf 方法可以将基本类型转为包装类. doubleValue, intValue等方法可以将包装类转为基本类型.
- 也可以使用=号直接转换, Java自动调用上面两个方法, 被称为自动装箱和自动封箱
- 包装类还有一个特点是有缓存机制, 比如当第一次调用valueOf方法时, 会自动创建一个Integer数组储存-128到127的Integer对象, 这样下次遇到在缓存范围内的对象时, 就直接返回已经缓存的对象.
//关于缓存
public class ValuePassing {
public static void fun1(Integer i, Integer j) {
System.out.println("在fun1中赋值前i的地址是: " + System.identityHashCode(i));
System.out.println("在fun1中赋值后j的地址是: " + System.identityHashCode(j));
//对i和j同时赋予一样的值后(在-128-127之间),地址一样
i = 10;
j = 10;
System.out.println("-----------------------------------------------");
System.out.println("在fun1中赋值后i的地址是: " + System.identityHashCode(i));
System.out.println("在fun1中赋值后j的地址是: " + System.identityHashCode(j));
}
public static void main(String[] args) {
Integer i = 5;
Integer j = 20;
System.out.println("在main中i的地址是: " + System.identityHashCode(i));
System.out.println("在main中j的地址是: " + System.identityHashCode(j));
System.out.println("-----------------------------------------------");
fun1(i, j);
}
}
output:
在main中i的地址是: 1072591677
在main中j的地址是: 1523554304
-----------------------------------------------
在fun1中赋值前i的地址是: 1072591677
在fun1中赋值后j的地址是: 1523554304
-----------------------------------------------
在fun1中赋值后i的地址是: 1175962212
在fun1中赋值后j的地址是: 1175962212
什么是反射
- Java的每个class都会在虚拟机中生成一个.class文件. 在程序运行时, 可以通过.class文件得到一个类的所有信息, 包括属性, 方法等
- 反射可以在动态的创建对象实例, 提高代码灵活性
- Java中的反射通过Class, Field, Method, Constructor类获得
— 为什么需要泛型, 介绍下泛型
- 泛型可以解决generic programming的问题, 也就是写的代码可以适配各种类. 比如集合框架中的容器
什么是泛型中的限定通配符
- 限定通配符对类型进行了限制
- <? Extend T> 限制了泛型中的类只能是T的子类
- < ? super T> 限制了泛型中的类只能是T的父类
讲一讲Error和Exception
- Error和Exception都继承自Throwable类
- Exception
- Checked Exception: 必须使用try catch处理的exception, 包括. SQLException
- Unchecked Exception: 不用被强制的显式的抛出或者捕获. 包括Arithmetic, NullPointer, IndexOutOfBounds, Illegalargument等
- Error: 属于编译器无法检测到的错误, 比如Virtual Machine Error, Linkage Error
throw和throws的区别是什么
- throw用在方法内部, 用于抛出一种异常
- throws写在方法声明的后面, 用来标识可能抛出的方法列表. 调用该方法的方法必须包括try catch处理对应的异常, 否则需要继续使用throws抛出对应的异常.
Java常见异常有哪些
- StackoverflowError
- ClassNotFoundException
- ArthimeticException
- IndexOutOfBoundsException
- NullPointerException
try-catch-finally 中, 如果catch中有return, finally还会执行吗
- 会执行, 在return之前执行
Java变量命名规范
- 必须以字母、下划线、或者美元符$开头
- 类名第一个字母大写, 遵循驼峰原则
- 变量名, 方法名第一个字母小写, 遵循驼峰原则
i++ 和 ++i的区别
- n = i++ 是先把i的值赋给左边再对i进行递增.
- n= ++i 是先对i进行递增, 再把值赋给左边.
Object类有哪些方法
- toString(), notifyAll(), wait(), hashCode(), finalize(), clone(), equals(), getClass()