一、基础
1、JVM、JRE、JDK有什么区别?
- JVM = Java虚拟机,跑Java程序的。
- JRE = JVM + 核心类库,什么是核心类库:比如基本数据类型、函数、线程、异常处理类等等。
- JDK = JRE + 编译、打包工具等。
如果要跑Java程序要用JRE,如果要开发Java程序用JDK。
2、switch 是能作用在哪里?
byte b1 = 1; //可以
short s1 = 2; //可以
int i1 = 4; //可以
long l1 = 8; //不可以
float f1 = 4.0f; //不可以
double d1 = 8.0; //不可以
boolean flag = true; //不可以
char c1 = 'c'; //可以
String st1 = "测试"; //可以
EnumTest failure = EnumTest.FAILURE; //可以
switch (XXXX){
...
}
例子说明:
- byte、short、int、char(Java5之前就可以),Enum对象可以(Java5以后可以),String字符串可以(Java7以后可以)
- long、float、double、boolean都不行
3、Math.round(11.5) 等于多少?
参数 + 0.5 取小就对了。
double d1 = 10.7;
double d2 = 10.3;
double d3 = -9.4;
double d4 = -11.6;
System.out.println(Math.round(d1)); //11
System.out.println(Math.round(d2)); //10
System.out.println(Math.round(d3)); //-9
System.out.println(Math.round(d4)); //-12
4、short s1 = 1; s1 = s1 + 1;有错吗? short s1 = 1; s1 += 1;有错吗?
知道两点即可:
- 普通的数字认定为
int类型 - +=可以自动转换类型
那么s1 = s1 + 1,是short类型 + int类型,结果是int类型,肯定不对;
而 += 在运算完之后进行类型转换,所以可以。
5、访问修饰符 public,private,protected,以及不写(默认)时的区别?
可以这样理解:代码 看作 钱。
- public:公用的钱--->慈善基金,大家都可以用
- protected:受法律保护的钱--->遗产,遗产是自己、妻子、儿子的,也就是本类、同包、子类都能用
- default:默认的钱--->家庭财产,一般也就是夫妻共用的钱,同包才能用,
default也叫包访问权限 - private:私有的钱--->小金库,媳妇也不愿意给用
6、&和&&的区别?
- &指的是按位与,进行运算用的,只有当两个二进制位都为1,才为1,其他情况为0。
System.out.println(5 & 3); //1
5用二进制 101 表示,3用二进制 011 表示(简化版本,其余位的0没写),101和011按位对照,只有最后1位都是1,那么最后结果就是001,换算回来也就是1。
- &也可以指逻辑与,用于判断的时候。
if (5 == 5 & 5 > 3){
System.out.println("5等于5,且大于3");
}else{
System.out.println("说的不对");
}
- &&指的是短路与,就是上面多个条件判断,只有都是true才为true,如果是短路与,如果第一个为false了,后面就不判断了,首先&&的性能要好一点点,但是判断后面如果有计算的话,肯定就没办法执行了。
int num = 10;
if (num == 9 & ++num == 10){
}
System.out.println(num); //11
int num = 10;
if (num == 9 && ++num == 10){
}
System.out.println(num); //10
7、final关键字的作用?
总之都是最终的意思,也就是不能修改:
- 类上,不能继承 --->不让改了继承也没什么用了
- 方法上,不能覆盖--->同理,方法也不让你改了
- 变量上,不能修改--->变量的引用不能改了,值可以改,但必须初始化,系统不给你赋默认值,要不用在企业上随手写个final,你忘了赋值又不好修改,造成损失了,到时候Oracle公司不背这个锅。
8、final、finally、finalize的区别?
final刚才说了
finally用在try...catch...finally中,保证不管是不是异常情况下,我希望走完的代码都能走完,比如一些资源类的东西。
finally在return下可不可以执行。
可以的:
public static void main(String[] args) {
try{
System.out.println("Hello World");
return;
}catch (RuntimeException e){
e.printStackTrace();
}finally {
System.out.println("能不能执行呢?");
}
}
//控制台输出
Hello World
能不能执行呢?
怎么才不执行呢?
在使用了System.exit(0);代码以后就不执行了。
public static void main(String[] args) {
try{
System.out.println("Hello World");
//退出JVM
System.exit(0);
System.out.println("这里也不知道能不能执行");
}catch (RuntimeException e){
e.printStackTrace();
}finally {
System.out.println("能不能执行呢?");
}
}
//控制台输出
Hello World
finalize关键字,看看老祖宗Object:
protected void finalize() throws Throwable { }
当垃圾回收器发现某个对象不再被引用了,系统会调用finalize方法进行回收,可以是呀Sytem.gc()去建议垃圾回收器回收。
public class Test {
public static void main(String[] args) throws Throwable {
Test test = new Test();
test = null;
System.gc();
Thread.sleep(1000);
System.out.println("退出...");
}
@Override
protected void finalize() throws Throwable {
System.out.println("收拾完啦");
}
}
//控制台输出
收拾完啦
退出...
9、this和super的用法?
this可以用来对 类的成员变量和形参同名时 做区分。
this还可以用于构造方法中。
public class Dog {
private String name;
private Integer age;
public Dog(){
}
public Dog(String name){
this();
this.name = name;
}
public Dog(String name,Integer age){
this(name);
this.age = age;
}
public static void main(String[] args) {
}
}
super是指向父类的指针。使用方式和上面类似。
10、static如何使用?
- 不创建对象,直接可以调用属性和方法。
private static String name;
public static void main(String[] args) {
System.out.println("2");
}
- 用于静态代码块,一个类中可以有多个静态代码块,并且静态代码块会按顺序执行,有的对象可能不希望有多个,那么使用static修饰,保证它只有一个,**这个对象会在类初始化的时候创建,**并且每次使用都用这个对象
static{
Dog dog = new Dog();
System.out.println("1");
}
注意:代码块、静态代码块
静态代码块是在main方法执行前执行,并且只执行一次
代码块是构造对象的时候执行,每调用一次构造方法就执行一次,不管是有参还是无参
而且一个类有多个静态代码块和代码块,它们会按照顺序执行
public class Dog {
private String name;
public Dog(String name) {
this.name = name;
System.out.println("执行有参构造方法");
}
static{
System.out.println("初始化静态代码块1");
}
static{
System.out.println("初始化静态代码块2");
}
{
System.out.println("初始化代码块1");
}
{
System.out.println("初始化代码块2");
}
public Dog() {
System.out.println("执行无参构造方法");
}
public static void main(String[] args) {
Dog dog1 = new Dog();
Dog dog2 = new Dog("xiaohua");
System.out.println("测试");
Dog dog3 = new Dog();
}
static{
System.out.println("初始化静态代码块3");
}
{
System.out.println("初始化代码块3");
}
}
//控制台输出
初始化静态代码块1
初始化静态代码块2
初始化静态代码块3
初始化代码块1
初始化代码块2
初始化代码块3
执行无参构造方法
初始化代码块1
初始化代码块2
初始化代码块3
执行有参构造方法
测试
初始化代码块1
初始化代码块2
初始化代码块3
执行无参构造方法
11、如何跳出当前的多重嵌套循环?
给循环起个名字,在里面用特定条件break 名字,即可在内存循环中跳出外层循环。
public class Test {
public static void main(String[] args) {
circle:
for (int i = 1;i < 20;i++){
for (int j = 1;j < 20;j++){
if (i == 10){
break circle;
}
System.out.print(i + "<=>" + j + " ");
}
System.out.println();
}
}
}
二、面向对象
12、面向对象三大特征?
特征:封装、继承、多态
- 封装:可以使用访问修饰符对对象的属性、方法进行控制,暴露一些想暴露的方法,限制一些不希望被他人操作的属性、方法。这样对象就可以操控对象来完成业务开发,不用担心会出现安全问题。
- 继承:继承相当于使用了对象的公共部分。如果每次都创建类似的新类,一来太麻烦,二来耦合度太高了。Java提供了继承机制,让我们可以创建新的类来继承以前的类、抽象类和接口。
- 多态:相当于使用了对象的特点,不同于父类的地方。任何对象都不可能一模一样,肯定会有它的差异,Java提供了父类型引用指向子类型对象的多态机制,这让我们调用代码更加灵活。编译阶段JVM只会看这个调用到的父类型是否满足要求,执行的时候才会看子类型。这样耦合度就非常小了。
13、什么是多态机制?
- 多态机制:父类型引用指向子类型对象。这种方式在编译过程中,编译器只看父类型是否有这个方法,而这个对象具体属于哪个类,调用的具体是什么方法,编译器不关心,只是在运行期间,在真正去绑定实际的类及方法。
- 如何实现的:非OOP的编程语言很多采用的是前期绑定的方式,也就是编译时就解析到这个对象的绝对地址,而OOP语言编译时只检查对象是否和方法匹配,具体属于哪个类、执行哪个方法则是在运行时才确定的。
14、面向对象的基本原则?(设计模式的原则)
| 原则 | 解释 |
|---|---|
| 开闭原则 | 对扩展开放,对修改关闭==>一个公司内部员工总是频繁调动不好,不如直接招募新人 |
| 里氏替换原则 | 子类可以替代父类在程序中出现的任何地方==>对接的时候是部长对接,而实际是底下员工操作。实际操作的时候员工肯定是要能替换部长的职责的(实现是由子类实现的) |
| 依赖倒转原则 | 依赖于抽象,不依赖于具体实现==>和其他部分、领导对接的时候,是部长去对接,不依赖于手底下员工(派一个代表) |
| 迪米特原则 | 最少知道原则,只知道跟它相关的类和对象即可,其他不需要知道==>不需要你知道的不需要知道,程序里面知道太多,依赖就很多 |
| 单一职责原则 | 每个类/接口提供单一职责==>公司也是,一个类干一个事儿,到时候处理任务也方便 |
| 接口分离原则 | 给客户端提供多个小的接口,而不是一个通用接口==>客户找到公司了,公司没有系统的部门,乱成一锅粥,不知道具体找谁,不利于扩展 |
| 组合复用原则 | 要尽量使用类的合成复用,尽量不要使用继承==>想让A部门去干一份工作,A部门干不了,B部门能干,那么先把B的员工纳入A部门就行了,没必要让A部门员工学会B部门的工作 |
15、接口和类的区别?
相同点:
- 都不能实例化对象
- 都是用来被其他类继承的
- 都含有抽象方法,都需要子类实现这些方法
不同点:
| 参数 | 抽象类 | 接口 |
|---|---|---|
| 声明 | 抽象类使用abstract关键字声明 | 接口使用interface关键字声明 |
| 实现 | 子类使用extends关键字来继承抽象类.如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现 | 子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现 |
| 构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
| 访问修饰符 | 抽象类中的方法可以是任意访问修饰符 | 接口方法默认修饰符是public。并且不允许定义为 private 或者 protected |
| 多继承 | 一个类最多只能继承一个抽象类 | 一个类可以实现多个接口 |
| 字段声明 | 抽象类的字段声明可以是任意的 | 接口的字段默认都是 static 和 final 的 |
16、内部类有哪些?
静态内部类、成员内部类、局部内部类、匿名内部类。
静态内部类
静态内部类就是在类的内部创建的静态类,内部类可以访问到外部的静态变量,但是非静态变量是访问不到的。能访问,但只能访问一点点。
public class Test {
private static String test_name = "test_name";
static class StaticInnerClass{
public String getOuterName(){
return test_name;
}
}
public static void main(String[] args) {
StaticInnerClass innerClass = new StaticInnerClass();
System.out.println(innerClass.getOuterName());
}
}
成员内部类
就是在类中创建一个不带static的内部类,而外部的静态变量、非静态变量,内部类都可以访问的到。
public class Test1 {
private static String static_name = "static_name";
private String non_static_name = "non_static_name";
class InnerClass{
public String getStaticName(){
return static_name;
}
public String getNonStaticName(){
return non_static_name;
}
}
public static void main(String[] args) {
Test1 test1 = new Test1();
InnerClass innerClass = test1.new InnerClass();
System.out.println(innerClass.getStaticName());
System.out.println(innerClass.getNonStaticName());
}
}
局部内部类
就是在类方法中创建一个类,静态方法的内部类不能访问非静态方法,非静态方法的内部类都可以访问。
public class Test2 {
private static String static_name = "static_name";
private String non_static_name = "non_static_name";
public static void testInnerClass1(){
class InnerClass{
public String getStaticName(){
return static_name;
}
}
InnerClass innerClass1 = new InnerClass();
System.out.println(innerClass1.getStaticName());
}
public void testInnerClass2(){
class InnerClass{
public String getStaticName(){
return static_name;
}
public String getNonStaticName(){
return non_static_name;
}
}
InnerClass innerClass2 = new InnerClass();
System.out.println(innerClass2.getStaticName());
System.out.println(innerClass2.getNonStaticName());
}
public static void main(String[] args) {
Test2 test2 = new Test2();
test2.testInnerClass2();
testInnerClass1();
}
}
匿名内部类
一般是指不打算重用而要实现一个接口才这么使用。而这个方式是最常见的。
public class Test3 {
public static void main(String[] args) {
new Interfaces() {
@Override
public String sayHello() {
return "Hello World";
}
};
}
}
interface Interfaces {
String sayHello();
}
17、局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?
new Mouse()的匿名内部类中,有个caught()方法,这个方法引用了getMouse()方法的局部变量。
局部变量在方法结束后就会自动回收掉了,而mouse对象则不一定,可能会在其他地方被引用,导致长时间不会被回收。
所以count局部变量可能已经被回收了,而mouse对象还在使用count参数,肯定是不行的。那么必须加上final来保证一致性。
注意在JDK1.8之后,这样写代码已经不报错了,如果想测试尝试下载jdk1.7测试。
网址:Java Platform, Standard Edition 7 Reference Implementations
public class Cat {
public void getMouse(){
int count = 20;
new Mouse() {
@Override
public void caught() {
System.out.println(count + "只老鼠被抓到了");
}
};
}
}
interface Mouse{
void caught();
}
18、重载和重写的区别?
- 重载:一般是同一个类中的各个方法,要求同名 + 不同形参(方法标识,方法标识要求唯一),访问修饰符和返回值不做要求。不同形参是指,形参数量、顺序、类型不同就算。
- 重写一般是指有继承关系的两个类,子类覆盖了父类的方法,这里面要求方法返回值、方法名、形参都一样,而且子类不能比父类更封闭,子类型抛异常不能比父类抛的更多。也就是儿子应该更能干一点,不能比爸爸更宅、不能比爸爸问题更多。
19、== 和 equals 的区别是什么?
==相当于是比较两个对象是否相等,也就是它们的内存地址是否相等。而equals其实和它是一样的,但是equals方法可以重写,重写以后就可以比较它们的值了。
三、包、IO、类、异常
20、Java中有哪些常用的包?
- java.lang:系统的基础类
- java.io:用于io处理的包
- java.net:网络相关的包
- java.util:系统辅助类,特别是集合的包
- java.sql:用于数据库操作的包
21、java 中 IO 流分为几种?
- 按照流向:输入流、输出流
- 按照操作单元:字节流、字符流
22、BIO,NIO,AIO 有什么区别?
- BIO:Block IO,也叫同步阻塞式IO,就是最普通的IO,处理并发效率比较低。
- NIO:NO IO,也叫同步非阻塞式IO,客户端和服务器使用channel通信,实现多路复用
- AIO:Asychronous IO,也叫异步非阻塞式IO,异步IO基于事件和回调机制。
23、Files的常用方法都有哪些?
Files的常用方法如下:
增:
- createDocument():创建文件夹
- createFile():创建文件
- copy():复制文件
删:
- delete():删除
改:
- move():移动文件
- write():写入文件
查:
- exists():查看文件是否存在
- size():查看文件数量
- read():读取文件
24、异常的分类?
- 异常Exception:代码级别的问题,可以被捕获并进行相应的处理。
- 错误Error:JVM级别的严重错误,出现Error会让程序进入不可恢复的状态。
- 运行时异常,也叫做非受检异常(unCheckedException),有的运行时异常可以不做处理,比较普遍,所以可以暂不处理。
- NullPointerException 空指针异常
- ArithmeticException 数学运算异常
- ArrayIndexOutOfBoundsException 数组下标越界异常
- ClassCastException 类型转换异常
- NumberFormatException 数字格式不正确异常
- 等等
- 编译时异常,受检异常(CheckedException),必须要在编译前处理的异常。
- SQLException:操作数据库的异常
- IOException:文件操作出现的异常
- FileNotFoundException:文件未找到异常,一般用于IO流
- ClassNotFoundException:类未找到异常
- IllegalArgumentException:参数异常
25、什么是字符串常量池?
字符串常量池位于堆中,一般用于储存字符串常量。当创建字符串时,会先检查是否在字符串常量池中已经有这个字符串了。如果存在就用这个的引用,如果不存在就创建,这样可以大大提高字符串的使用效率。
26、String是不可变的吗?
是的因为String的底层用了final修饰。
/** The value is used for character storage. */
private final char value[];
27、如何将字符串反转?
通过StringBuilder和StringBuffer的reverse()方法。
public static void main(String[] args) {
StringBuffer str = new StringBuffer("helloworld");
StringBuffer reverse = str.reverse();
System.out.println(reverse);
}
28、数组有没有 length()方法?String 有没有 length()方法?
数组没有length方法,只有length属性。
String有length方法
public static void main(String[] args) {
String str = new String("abcdefg");
int length = str.length();
System.out.println(length);
int[] arr = new int[]{1,2,3,4,5,6};
System.out.println(arr.length);
}
29、String 类的常用方法都有那些?
String类的方法:
| 方法名 | 描述 |
|---|---|
| indexOf() | 返回指定字符的索引 |
| charAt() | 返回指定索引处的字符 |
| replace() | 字符串替换 |
| trim() | 去除字符串两端空白 |
| split() | 分割字符串,返回一个分割后的字符串数组 |
| getBytes() | 返回字符串的 byte 类型数组 |
| length() | 返回字符串长度 |
| toLowerCase() | 将字符串转成小写字母 |
| toUpperCase() | 将字符串转成大写字符 |
| substring() | 截取字符串 |
| equals() | 字符串比较 |
30、String和StringBuffer、StringBuilder的区别是什么?
String是不可变的字符串类型,创建的字符串是不可变的。
StringBuffer:StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
而StringBuffer不是线程安全的,StringBuilder是线程安全的。用synchronized修饰了,所以StringBuffer的效率比StringBuilder的效率高。