Fork me on GitHub

Java基础-面试

来源见水印,侵删

注:以下内容只是作为面试的准备,如果有不够详细的地方,还希望你自己在网络、书籍或其他方式自行查找。

Java基础语法

  1. 对象:对象是类的一个实例,有状态和行为
  2. 类:类是一个模板,它描述一类对象的行为和状态
  3. 方法:方法就是行为,一个类可以有很多方法
  4. 实例变量:每个对象都有独特的实例变量,对象的状态有这些实例变量决定

类–>动物
对象–>熊、虎、猫、狗
方法–>叫、吃、跑、睡
实例变量–>这里已经具体到每个个体了,例,猫的颜色、猫的年龄…

Java关键字

类别 关键字 说明
访问控制 private 私有的
protected 受保护的
public 公共的
类、方法和变量修饰符 abstract 声明抽象
class
extends 继承
final 不可改变的
implement 实现
interface 接口
native 原生方法
new 创建
static 静态
strictfp 严格
synchronized 同步(线程)
transient 短暂
volatile 易失
程序控制语句 break 跳出循环
case 定义一个值以供switch选择
continue 继续
default 默认
do 运行
else 否则
for 循环
if 如果
instanceof 实例
return 返回
switch 根据值选择执行
while 循环
错误处理 assert 断言表达式是否为真
catch 捕获异常
finally 最终
throw 抛出异常对象
throws 声明一个异常可以被抛出
try 尝试捕获异常
包相关 import 导入
package
基本类型 Boolean 布尔
byte 字节
char 字符
double 双精度浮点
float 单精度浮点
int 整形
long 长整型
short 短整型
变量引用 super 超类
this 本类
void 无返回值
保留关键字 goto 是关键字但不可使用
const 是关键字但不可使用
null

Java源程序与编译型运行区别

Java对象和类

下图很好的说明了兑现与类的关系

1
2
3
4
5
6
7
public class Dog{
static int age;//类变量(举例)
String breed;//成员变量
void barking(){
String doSomething;//局部变量
}
}
  • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
  • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
  • 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。

局部变量

  • 局部变量声明在方法、构造方法或者语句块中
  • 局部变量在方法、构造方法或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁
  • 访问修饰符不能用于局部变量
  • 局部变量只在声明它的方法、构造方法或者语句块中可见
  • 局部变量在栈中分配
  • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用

成员变量

  • 成员变量声明在一个类中,但方法、构造方法和语句块之外
  • 当一个对象被实例化之后,每个实例变量的值就跟着确定
  • 成员变量在对象创建的时候创建,在对象销毁的时候销毁
  • 成员变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取成员变量信息
  • 成员变量可以声明在使用前或使用后
  • 访问修饰符可以修饰成员变量
  • 成员变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把成员变量设为私有。通过使用访问修饰符可以使成员变量对子类可见;
  • 成员变量具有默认值

静态变量

  • 在类中以static关键字声明,但必须在方法、构造方法和语句块之外
  • 无论一个类创建了多少个对象,类只拥有变量的一份拷贝
  • 静态变量除了被声明为常量外很少使用
  • 静态变量存储在静态存储区
  • 静态变量在第一次被访问时创建,在程序结束时销毁
  • 类变量被声明为public static final类型时,类变量名称一般建议使用大写字母
  • 静态变量在第一次被访问时创建,在程序结束时销毁。

引用类型

  • 在Java中,引用类型的变量类似于c、c++中的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
  • 对象、数组都是引用变量
  • 所有引用类型的默认值都是null
  • 一个引用变量可以用来引用任何与之兼容的类型(父类、子类)

自动类型转换

低————————->高
byte,short,char->int->long->float->double

规则:

  1. 不能对Boolean型进行类型转换
  2. 不能把对象类型转换为不相关的对象
  3. 容量大的类型转换为容量小的类型必须采用强制类型转换
  4. 转换过程可能会出现溢出或损失精度(int–>byte)
  5. 浮点型–>整型是通过舍弃小数得到,而不是四舍五入

修饰符

访问修饰符

修饰符 当前类 同一个包内 子孙类 其他包 其他包子孙类
public Y Y Y Y Y
protected Y Y Y N Y/N
default Y Y N N N
private Y N N N N

位运算符

操作符 描述 例子
& 如果相对应位都是1,则结果为1,否则为0 (A&B),得到12,即0000 1100
\ 如果相对应位都是0,则结果为0,否则为1 (A \ B)得到61,即 0011 1101
^ 如果相对应位值相同,则结果为0,否则为1 (A ^ B)得到49,即 0011 0001
~ 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 (〜A)得到-61,即1100 0011
<< 按位左移运算符。左操作数按位左移右操作数指定的位数。 A << 2得到240,即 1111 0000
>> 按位右移运算符。左操作数按位右移右操作数指定的位数。 A >> 2得到15即 1111
>>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 A>>>2得到15即0000 1111

循环结构

  • while
  • do…while
  • for
  • Java5之后,foreach

分支结构

  • if
  • switch

继承

继承就是子类继承父类的特征和行为,使得子类对象具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为

继承的特性

  • 子类拥有父类非private的属性和方法
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展
  • 子类可以用自己的方式实现父类的方法
  • Java的继承是单继承,多实现
  • 提高了类之间的耦合性

关键字

extends、implements、super、this和final

super:通过super来实现对父类成员的访问,用来引用对象的父类
this:指向自己的引用

重载(overload)、重写(override)

重写(override)

重写就是子类对父类中能够访问的方法的实现过程进行重新编写,返回值和形参都不可以改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}

class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
}

public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal b = new Dog(); // Dog 对象

a.move();// 执行 Animal 类的方法

b.move();//执行 Dog 类的方法
}
}

在上面的例子中可以看到,尽管b属于Animal类型,但是它运行的是Dog类的move方法。

这是由于在编译阶段,只是检查参数的引用类型。

然而在运行时,Java虚拟机(JVM)指定对象的类型并且运行该对象的方法。

因此在上面的例子中,之所以能编译成功,是因为Animal类中存在move方法,然而运行时,运行的是特定对象的方法。

重写规则

  • 参数列表、返回类型与被重写的方法相同
  • 访问权限不能比父类中被重写的方法的访问权限更低
  • 父类的成员方法只能被它的子类重写
  • 声明为final的方法不能被重写,static不能重写但可以被再次声明
  • 构造方法不能被重写

重载(overload)

重载是在一个类里面,方法名字相同,而参数不同,返回类型可以相同也可以不相同

重载规则

  • 被重载的方法必须改变参数列表(参数个数与类型不一样)
  • 被重载的方法可以改变返回类型、访问修饰符、声明新的或更广的检查异常
  • 方法能够在同一个类中或者在一个子类中被重载
  • 无法以返回值类型作为重载的区分标准
区别点 重载方法 重写方法
参数列表 必须修改 不可修改
返回类型 可以修改 不可修改
异常 可以修改 可以减少或删除,一定不能抛出新的或者更广的异常
访问 可以修改 一定不能做更严格的限制(可以降低限制)

多态

多态是同一个行为具有多个不同表现形式或形态的能力。

优点

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性

多态存在的必要条件

继承、重写和父类引用指向子类对象

1
Parent p = new Child();

使用多态方式调动方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法

多态实现方式

  • 重写
  • 接口
  • 抽象类和抽象方法

第一种方式前面有写,后两种方式后面会慢慢涉及

抽象类和抽象方法

抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

  • 抽象类不能实例化对象
  • 抽象类必须被继承
  • 单继承多实现

抽象方法

如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。

  • 如果一个类包含抽象方法,那么该类必须是抽象类
  • 任何子类必须重写父类的抽象方法,不然就声明自身为抽象类

抽象类总结

  • 抽象类不能被实例化
  • 抽象类中不一定含有抽象方法,但是有抽象方法就必须是抽象类
  • 抽象方法只有声明,没有方法体
  • 构造方法、静态方法不能声明为抽象方法
  • 抽象类中如有抽象方法,子类必须实现,不然子类还是抽象类

封装

封装:指一种将抽象性函数接口的实现细节部份包装、隐藏起来的方法。

优点:

  • 良好的封装能减少耦合
  • 类内部的结构可以自由修改
  • 可以对成员变量进行更精准的控制
  • 隐藏信息,实现细节

接口

在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口与类的相似

  1. 一个接口可以有多个方法
  2. 接口文件保存在.java结尾的文件中,文件名使用接口名
  3. 接口的字节码文件保存在.class结尾的文件中
  4. 接口相应的字节码文件必须在与包文件相匹配的目录结构中

接口与类的不同

  1. 接口不能被实例化
  2. 接口没有构造函数
  3. 接口中所有方法必须是抽象方法
  4. 接口不含有成员变量,除了staticfinal变量
  5. 接口可以多继承、实现

接口与抽象类的不同

  1. 抽象类中的方法可以有方法体,但是接口中没有
  2. 抽象类中成员变量可以是各种类型的,接口中能是public static final
  3. 接口中不能含有静态代码块以及静态方法,而抽象类是可以有静态代码块和静态方法的
  4. 一个类只能继承一个抽象类,但可以实现多个接口

Map遍历的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.util.*;

public class Test{
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");

//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}

//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}

//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}

//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
}

泛型

泛型是JDK 5 中引入的,提供了一种编译时类型安全检查机制,该机制允许程序在编译时检测到非法的类型。

更多泛型知识请点击