Java程序员面试宝典1 ---Java基础部分(该博文为原创,转载请注明出处)

时间:2023-03-09 00:48:30
Java程序员面试宝典1 ---Java基础部分(该博文为原创,转载请注明出处)

(该博文为原创,转载请注明出处   http://www.cnblogs.com/luyijoy/  by白手伊凡)

1.    基本概念

1)         Java为解释性语言,运行过程:程序源代码经过Java编译器编译成字节码,然后用JVM解释执行

2)         Java语言提供垃圾回收机制(GC),不需要程序显式地管理内存分配,引入finalize()方法会在回收前首先调用

3)         main是JVM程序识别的入口方法,public、static可互换顺序,main()方法可用final、synchronized来修饰

4)         Java程序初始化代码块顺序:父类静态变量 > 父类静态代码块 > 子类静态变量 > 子类静态代码块 > 父类非静态变量 > 父类非静态代码块 > 父类构造函数 > 子类非静态非静态变量 > 子类非静态代码块 > 子类构造函数

5)         Java变量类型:成员变量、静态变量、局部变量

6)         成员变量作用域

作用域与可见性

当前类

同package

子类

其他package

public

protected

default

private

7)         Java中常用标识接口Cloneable和Serializable,该类接口内没有任何方法声明仅作标识作用

8)         clone()方法,浅复制与深复制:

浅复制仅考虑复制对象的值,不必考虑引用对象

深复制不仅复制了对象的值,而且复制了引用对象

9)         反射机制允许程序运行时自我检查同时能够对内存成员进行操作。获取class类的三种方法:class.forName();类名.class;实例.getClass()

10)     Java创建对象的方式四种:new语句实例化对象;反射机制创建;clone()方法复制创建;反序列化创建

2.    面向对象技术

1)         面向对象特性:抽象、封装、继承、多态

2)         Java语言支持单继承

3)         多态实现方式:方法的重载和方法的覆盖

4)         抽象类和接口的异同:

相同点:

都不能被实例化。

接口的实现类和抽象的子类都只有实现了接口或抽象类中的方法后才能实现实例化。

差异:

接口只能定义其方法不能实现,抽象类可以定义与实现。

接口需要implement实现,抽象类需要extends继承

接口成员变量默认public static final其成员方法为public、abstract,抽象类成员变量默认default可自定义,抽象方法不能用private、synchronized、native修饰。

5)         内部类包括四种:静态内部类、成员内部类、局部内部类、匿名内部类

6)         使用getClass().getName()获取父类类名

7)         this指向当前实例对象

class People{

String name;

public People(String name){

//这里的this.name表示成员变量,name表示形式参数

this.name=name;

}

}

3.    关键字

1)         命名规则:标识符为大小写字母、数字、下划线及$,且第一个字符必须是字母、下划线或$。

2)         break、continue及return

3)         final、finally及finalize

final:声明属性、方法和类

finally:异常处理中使用

fianlize:是Object类的一个方法,垃圾回收机制中使用

4)         assert断言,软件调试方法,表达方式:assert expression1和assert experssion1:experssion2,其中experssion1为boolean型,experssion2为基本类型或对象

5)         static作用:分配存储空间、直接调用方法

使用方式:成员变量、成员方法、代码块、内部类

6)         单例模式:

class Singleton{

private static Singleton instance=null;

private Singleton(){}

public static Singleton getInstance(){

if(instance==null){

instance=new Singleton();

}

return instance;

}

}

7)         switch(expr)中expr可以是int或Integer及能被隐式转换为int类型的枚举常量或整数表达式

8)         volatile是类型修饰符,它被设计用来修饰被不同线程访问和修改的变量。被volatile定义的变量,系统每次使用它时都直接从对于的内存中提取,不使用缓存。使用volatile修饰成员变量后,所以线程在任何时候所看到的变量值都是相同的。(尽量不要使用)

9)         instanceof用来判断引用类型的变量所指对象是否是一个类的实例。常用表达方式:result=object instanceof class。

10)     strictfp指精确浮点,用来确保浮点数运算的准确性,如public strictfp class Test

4.    基本类型与运算

1)         八种原始数据类型/基本数据类型:byte,short,int,long,double,float,char,boolea在栈上分配内存,其他类型都是引用类型仅存储内存地址不分配内存空间。(void也属于基本类型,但无法操作)1字节=8bit

类型

int

short

long

byte

float

double

char

boolean

大小

4

2

8

1

4

8

2

1

2)         不可变类型:所有的基本数据类型及String

3)         Java传递方式:值传递和引用传递

4)         不同数据类型转换:自动转换(低级->高级)和强制类型转换

优先级byte < short < char < int < long < float <double

5)         运算符优先级

6)         Math方法中:round是四舍五入,ceil是向上取整,floor是向下取整

7)         >>有符号右移,>>>无符号右移(有符号正数高位补0,负数补1;无符号高位补0)

<<有符号左移,左移n位表示原来的值乘以2的n次方,m<<4表示m*16(低位补0)

8)         Java中使用Unicode编码,每个字符占两字节。String中英文1个字符,中文2个字符

5.    字符串与数组

1)         String存储机制,JVM中存在字符串连接池,其中保存许多String对象并且可以共享使用。例如:

String  s1=”abc”;  //在常量区里面存放一个”abc”字符串

String  s2=”abc”;  //s2引用常量区中的对象,因此不会创建新的对象

String  s3=new String(“abc”); //在堆中创建新的对象

String  s4=new String(“abc”); //在堆中又创建了一个新的对象

其中new String(“abc”);若常量区有”abc”则只创建new String()堆对象,否则创建两个对象

2)         “==”运算符用例比较两个变量的值是否相等

equals()是Object提供的方法,比较引用。它可以被覆盖,所以可通过覆盖的方法比较数据内容。

hasCode()方法从Object类中继承过来,该方法返回对象在内存中地址转换成int值,若没有重写hasCode()方法,任何对象的hasCode()都是不等的。

3)         Character用于单字符操作,String字符串不可变类,StringBuffer字符串可变类,StringBuilser()字符串可变类。其中StringBuffer和StringBuillder()都是字符串缓冲区,StringBuilder线程不安全,单线程效率高。

执行效率:StringBuilder > StringBuffer > String

小型数据量采用String,单线程考虑StringBuilder,多线程大量数据采用StringBuffer。

String s1=”abc”;   String s1=new String(“abc”);

StringBuffer s1=new StringBuffer(“abc”);

4)         length()方法计算字符串长度,length属性用来获取数组长度,size()方法针对泛型集合查看泛型中有多少个元素

6.    异常处理

1)         finally块在Java语言异常处理中一定会被执行,finally块代码一定在return之前执行。但,当程序进入try语句块之前就出现异常时,程序会直接结束从而不执行finally块;当程序在try块中强制退出时也不会执行finally块中的代码。强制退出:System.exit(0);

2)         Java将异常当做对象处理,并定义一个基类(java.lang.Throwable)作为所以异常的父类。异常分为Error(错误)和Exception(异常)两类。

违反语义的异常分为Java类库内置语义检查如:IndexOutOfBoundsException、NullPointerException;开发人员扩展语义检查,创建自己的异常类,*选择合适用throw抛出。

3)         Error表示程序运行期间出现不可恢复的错误,属于JVM级严重错误,程序终止执行,如OutOfMemoryError、ThreadDeath

Exception可恢复异常,编译器可捕获,包含检查异常(IO异常、SQL异常,发生在编译阶段,编译器强制捕获并处理)和运行时异常(编译器没有强制捕获并处理,异常由JVM来处理,NullPointException空指针异常、ClassCastException类型转换异常、ArrayIndexOutOfBoundsException数组越界异常、ArrayStoreException数组存储异常、BufferOverflowException缓冲区溢出异常、ArithmeticException算术异常)。

7.    输入输出流

1)         流可分为字符流和字节流,字节流以字节(8bit)为单位包含InputStream和OutputStream,字符流以字符为单位(16bit)包括Reader和Writer。

Java IO采用Decorator装饰者设计模式

2)         Socket套接字,可以用来实现不同虚拟机或不同计算机之间的通信,Socket分为两种:面向连接的Socket通信协议(TCP,传输控制协议)、面向无连接的Socket通信协议(UDP,用户数据报协议),任何一个Socket都是由IP地址和端口号唯一确定的。

Socket生命周期:打开Socket、使用Socket收发数据和关闭Socket。

在Java中,使用ServerSocket作为服务器端,Socket作为客户端来实现网络通信。

3)         Java NIO是面向缓冲的非阻塞IO适用于I/O读写。NIO通过Selector、Channel和Buffer来实现。NIO非阻塞的实现采用了Reactor反应器设计模式,(该模式与Observer观察者模式类似,但Observer只能处理一个事件源,Reactor能处理多个事件源)

Channel被看做一个双向的非阻塞通道,通道两边可进行数据读写操作;Selector实现用一个线程来管理多个通道,类似观察者;Buffer用来保存数据。

NIO在网络编程中相比Socket提高了效率

4)         Java持久化模式:序列化、外部序列化

序列化是一种将对象以一连串的字节描述的过程,用于解决在对对象流进行读写操作时所引发的问题。序列化可将对象的状态写在流里进行网络传输,或者保存到文件、数据库等系统里,并在需要时把该流读取出来重新构造一个相同的对象。序列化要实现Serializable接口,该接口位于java.lang包中,里面不包含任何方法。(反序列化:将流转化为对象)

外部序列化:EXternalizable接口中的读写方法必须由开发人员实现。

相比较序列化更灵活,编程难度较大

8.    Java平台与内存管理

1)         .java文件被javac指令编译为.class后缀的字节码文件,再由JVM执行。Java程序被编译后生成了一个“中间码”,不同硬件平台上按照不同JVM,由JVM负责把“中间码”翻译成硬件平台能执行的代码。解释执行过程:代码装入、代码校验、代码执行

2)         类的加载方式:隐式和显式。隐式采用new的方式,显式调用class.forName()方法加载到JVM中。

3)         垃圾回收GC,它回收程序中不再使用的内存。常用垃圾回收算法:引用计数算法、追踪回收算法、压缩回收算法、复制回收算法、按代回收算法。

在Java中开发人员不能实时地调用垃圾回收器对某个对象或所有对象进行垃圾回收,但可通过System.gc()方法“通知”垃圾回收器运行。该方法的执行会停止所有响应,去检查内存中是否有可回收对象,对程序正常运行和性能造成巨大威胁,不推荐使用。

4)         判断内存空间是否符合垃圾回收标准:给对象赋予了空值null,以后没有再使用过;给对象赋予新值,重新分配了内存空间。

5)         内存泄漏:在堆中申请的空间没有被释放;对象不再使用,但仍在内存中保留着。由于垃圾回收机制能有效解决第一种,所以Java语言中的内存泄漏主要指第2中情况。

6)         内存泄漏原因:

静态集合类,它们的生命周期与程序一致,在程序结束前不能被释放;

各种连接,连接在close()关闭后才会回收对于的对象,若不显示关闭则无法回收;

监听器,应用中用到多个监听器,打在释放对象的同时没有相应地删除监听器;

变量不合理的作用域,变量的作用范围大于实用范围,没有及时将对象设置为null

7)         堆和栈:

栈内存用来存放基本数据类型与引用变量;堆内存用来存放运行时创建的对象(new对象)

栈的存储速度更快,堆可以在运行时动态地分配内存。

9.    容器

1)         Java Collections框架提供了List列表、Queue队列、Set集合、Stack栈、Map映射表,其中List、Queue、Set、Stack继承自Collection接口

2)         Set:集合内的元素不能重复,每个元素定义equals确保对象唯一性。实现类:HashSet和TreeSet,其中TreeSet实现了SortedSet接口,该容器元素有序

3)         List按对象进入顺序保存,允许重复对象。包括LinkedList、ArrayList、Vector实现类

4)         Map提供了一个从键映射到值的数据结构,包括HashMap、TreeMap、LinkedMap、WeakHashMap和IdentityHashMap。

5)         迭代器是一个对象,用来遍历并选择序列中的对象。

a.使用容器的iteractor()方法返回一个Iteractor,然后通过Iteractor的next()方法返回第一个元素

b.使用Iteractor的hasNext()方法判断容器中是否还有元素

c.可通过remove()方法删除迭代器返回的元素

6)         ArrayList、Vector、LinkedList类均在java.util包中,可动态改变长度的数组。ArrayList和Vector数据存储连续,可通过下标访问。ArrayList是非同步的,而Vector的绝大多数(add、insert、remove、set、equals、hascode)都是同步的,因此Vector是线程安全的。LinkedList采用双向列表实现,对数据的索引要从列表头开始遍历,访问效率低,插入效率高,非线程安全的。

数据主要操作时索引或末端增加删除数据采用ArrayList;在数据指定位置插入或删除时选取LinkedList;多线程是选用Vector安全。

7)         java.util.Map中HashMap、HashTable和TreeMap。

HashMap允许空值,HashTable不允许,HashTable线程安全,HashMap不支持线程同步不是线程安全的。HashMap效率高于HashTable,

8)         Collection是集合接口,提供对集合对象进行基本操作的通用接口方法,实现该接口的类主要由List和Set。

Collections是针对集合类的一个包装类,它提供一系列静态方法,其中大多数方法是用来处理线性表

10.         多线程

1)         线程四种状态:运行、就绪、挂起和结束,多线程可减少程序响应时间、开销小、高效利用CPU资源、简化程序

2)         Java多线程实现方式:

继承Thread类,重写run()方法(不带返回值)

实现Runnable接口,实现run()方法(不带返回值):自定义Runnable接口实现run方法,创建Thread对象并实例化,调用Thread的start方法。

实现Callable接口,重写call()方法(带返回值)

3)         run()和Start()方法的区别

系统调用线程类的start()方法来启动一个线程,此时线程处于就绪状态,可以被JVM来执行。在调度中JVM通过调用线程类的run()方法完成实际操作。

如果直接调用run()方法,会被当做一个普通的函数调用,程序中还是仅由主线程一个,即start()方法能够异步地调用run()方法。

4)         多线程同步方式:

synchronized方法;wait()方法与notify()方法(wait等待,notify唤醒);Lock

5)         sleep()和wait()

sleep()是线程用来控制自身的流程,时间一到自动苏醒,wait需要notify唤醒;

sleep()不会释放锁,wait()会释放它所占用的锁;

wait必须在同步控制方法或同步语句块中使用,sleep方法不限制位置

6)         sleep()和yield()

sleep()不考虑优先级因此低优先级有机会,yield会先运行高优先级;

线程执行sleep()后会转入阻塞状态,在指定时间内不会被执行,yield方法只是当前线程重新回到可执行状态,有可能进入到可执行状态后又马上被执行。

7)         stop()和suspend()方法。

suspend()方法不会释放锁,在锁恢复前不会被释放(易发生死锁)

stop()方法会释放已锁定的所有监视资源。

以上终止线程方法均不建议使用。

8)         终止线程方法:采用线程自行结束进入Dead状态。

9)         synchronize和Lock的区别

synchronize使用Object对象本身的notify、wait、notifyAll机制,Lock使用Condition进行线程调度

用法:synchronize托管JVM执行,Lock需要显式的代码

性能:在资源竞争不激烈时synchronize优于ReetrantLock,在竞争激烈时synchronize性能下降过快,RenetrantLock性能不变

锁机制:synchronize获得和释放锁都是在块结构中,自动解锁,Lock手动释放

10)     线程:守护线程(服务线程)和用户线程,守护线程优先级较低。如果用户线程已经全部退出运行,只剩下守护线程,那么JVM也就退出了。

垃圾回收器是典型守护线程,只要JVM启动,它始终在运行,实施监控和管理系统中可以被回收的资源

11)     join()方法的作用是让调用该方法的线程在执行完run()方法后,再执行join方法后的代码。即两个线程合并,用于实现同步功能。

11.         Java数据库操作

1)         JDBC访问数据库步骤:

a.加载JDBC驱动器

b.加载JDBC驱动

c.建立数据库连接,取得Connection对象

d.建立Statement对象或PreparedStatement对象

e.执行SQL语句

f.访问结果集ResultSet对象

g.依次关闭ResultSet、Ststement、PreparedStatement、Connection对象,释放资源

2)         JDBC事务处理,一般通过commit()方法或rollback()方法结束事务的操作。其中commit()方法表示完成对事务的提交,rollback()方法表示完成事务回滚。两种方法均位于java.sql.Connection类中。一般事务默认,自动调用commit()方法,否则调用rollback()方法。

3)         class.forName()方法是将类加载到JVM中,它返回一个与带有给定字符名的类或接口相关的Class对象,并且JVM会加载这个类,同时JVM会执行该类的静态代码段。

4)         Statement、PreparedStatement和CallableStatement

Statement用于执行不带参数的简单SQL语句,并返回它所生成结果的对象,每次执行SQL语句时都要编译SQL语句。

PreparedStatement相比Statement效率高(一次解析,不再被编译)、代码可读性、可维护性好、安全性高(能预防SQL注入)。(SQL注入是指通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器,达到执行恶意SQL命令的目的)

5)         少量数据可采用getString()等方法从ResultSet中获取,大量数据使用getObject()方法。

6)         JDO是Java数据对象,用于存取某种数据仓库中的对象的标准化API,开发人员能间接访问数据库。

7)         Hibernate是JDBC的封装