面试题(一)—Java基础(上)
1.面向对象的三大特征
(1)封装
封装性指的是隐藏了对象的属性和实现细节,对外仅提供公共的访问方式。
好处: 将变化隔离,提供复用性和安全性。
(2)继承
提高代码的复用性,继承是多态的前提。
子类所有的构造方法都会默认访问父类的空参数构造方法,默认第一行有super()。若无空参构造函数,子类需指定,另外子类的构造函数可以用this关键字指定自身的其他构造函数。
(3)多态
父类的引用指向子类对象,提高了程序的扩展性,虽然提高了扩展性,但是只能访问父类具备的方法,不能访问子类中的方法。
2.四种访问权限修饰符
3.Java的基本数据类型
Java四类八种基本数据类型
整型: byte(1)、short(2)、int(4)、long(8)
浮点型: float(4)、double(8)
布尔型: boolean(1/8)
字符型: char(2)
4.short s =1;s = s + 1; 与 short s = 1; s+=1;
由于s+1运算时会自动提升表达式的类型,所以结果是int型,再赋值给short类型s时,编译器将报告需要强制转换类型的错误。
对于short s = 1; s += 1;由于 += 是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。
5.&与&&的区别
&和&&都可以用作逻辑与的运算符,表示逻辑与(and)。当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式。例如,对于if(str != null && !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。If(x==33 & ++y>0) y会增长,If(x==33 && ++y>0)不会增长。
&还可以用作位运算符。当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。
6.int与Integer的区别
int是基本数据类型,Integer是int的一个包装类。
@Test
public void testInteger(){
Integer a = new Integer(3);
Integer b = 3; //将3自动装箱为Integer类型
int c = 3;
System.out.println(a == b); //false 两个引用没有指向同一对象
System.out.println(a == c); //true a自动拆箱成int类型再和c比较
}
@Test
public void testInt(){
Integer a = 100;
Integer b = 100;
Integer c = 200;
Integer d = 200; System.out.println(a == b); //true
System.out.println(c == d); //false
}
当我们给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf。
public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
如果整型字面量的值在-128到127之间,那么不会new新的Integer对象,而是直接引用常量池中的Integer对象。
7.final、finally、finalize的区别
final: final修饰类:当一个类被final修饰时,表示该类是一个终态类,即不能被继承。
final 修饰方法:当一个方法被final修饰时,此方法不能被重写(Override)。
final 修饰属性:当一个属性被final修饰时,此属性不能被改写。
当final修饰一个原生数据类型时,表示该原生数据类型的值不能发生变化;
当final修饰一个引用类型时,表示该引用类型不能再指向其他对象了,但该引用所指向的内容是可以发生
变化的。
其初始化可以在两个地方:
(1)定义处,在final变量定义时直接给其赋值;
(2)构造函数中。
finally: 异常处理语句结构的一部分,表示总是执行。
finalize: 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。 JVM 不保证此方法总被调用。
8."=="和"equals"
"=="既可以用于基本数据类型的比较,也可以用于引用类型的比较。
"equals"只能用于引用类型的比较。
"=="
(1)对于原生类型来说,比较的是左右两边的值是否相等。
(2)对于引用类型来说,比较左右两边的引用是否指向同一个对象,或者说左右两边的引用地址是否相同。
equals()方法
该方法定义在Object类中,因此Java每个类中都具有该方法,对于Object类的equals()方法来说,它判断的是用equals()方法与传进来的引用是否一致,即两个引用是否指向同一个对象。对于Object类的equals()方法,等价于==。对于String类中equals()方法来说,它复写了Object类中的equals()方法,它是判断当前字符串与传进来的字符串的内容是否一致。
9.Overload和Override
方法重载Overload
表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。
方法参数不同有两层含义:
(1)参数个数不同。
(2)参数类型不同。 注意:方法的返回值对重载没有任何影响。
重写Override
表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了。
这也是面向对象编程的多态性的一种表现。子类覆盖父类的方法时, 只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法是 private 类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
10.Abstract Class和interface的区别
Abstract Class
含有abstract修饰符的class即为抽象类, abstract类不能创建的实例对象。含有abstract方法的类必须定义为 abstract class, 抽象类中的方法不必是抽象的。抽象类中定义抽象方法必须在具体子类中实现, 所以,不能有抽象构造方法或抽象静态方法。 如果的子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为 abstract类型。
Interface
可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。 接口中的方法定义默认为 public abstract 类型,接口中的成员变量类型默认为 public static final。
A: 抽象类只能被单继承。
接口可以多实现,接口的出现避免了多继承的局限性。
B: 抽象类中的数据特点
成员变量: 可以是变量,也可以是常量。
成员方法: 可以是抽象方法,也可以是非抽象方法。
构造方法: 有构造方法。
接口中的数据特点
成员变量: 是常量。默认修饰 public static final。
成员方法: 都是抽象方法。都有默认修饰 public abstract。
构造方法: 没有构造方法。
C: 抽象类中定义的是继承体系中的共性功能。
接口中定义的是继承体系中的扩展功能。
11.String、StringBuffer、StringBuilder的区别
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
执行速度: StringBuilder > StringBuffer>String
简要的说,String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。
而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“simple”).append(“ test”);你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
String S1 = “This is only a” + “ simple” + “test”; 其实就是:
String S1 = “This is only a simple test”;
所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;这时候 JVM 会规规矩矩的按照原来的方式去做。
12.try {}里有一个 return 语句,那么 紧跟在这个 try 后的 finally {}里的 code会不会被执行?
public static int testDemo(){
int i = 1;
try{
System.out.println("Before retrun...");
return i;
}
finally{
System.out.println("finally invoked...");
++i;
}
}
输出:
Before retrun...
finally invoked...
1
在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。在转去之前,try中先把要返回的结果存放到不同于i的局部变量中去,执行完finally之后,在从中取出返回结果,因此,即使finally中对变量i进行了改变,但是不会影响返回结果。
13.List子类的特点
ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
14.ArrayList和Vector的区别
(1)同步性
Vector 是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList 是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用 ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用 Vector,因为不需要我们自己再去考虑和编写线程安全的代码。
(2)数据增长
ArrayList 与 Vector 都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加 ArrayList 与 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。 Vector 默认增长为原来两倍,而ArrayList 是增长为原来的1.5倍。 ArrayList 与 Vector 都可以设置初始的空间大小, Vector 还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空间的方法。
总结:即 Vector 增长原来的一倍, ArrayList 增加原来的0.5倍。
15.List、Set、Map的区别
List、Set都继承自Collection接口。Map没有。
List:有序的,元素可重复,有索引。
Set:无序的,元素不可重复,无索引。
Map:元素按键值对存储,无存放顺序。
16.HashMap和Hashtable的区别
(1)继承和实现方式不同
HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
(2)线程安全不同
Hashtable的几乎所有函数都是同步的,即它是线程安全的,支持多线程。
HashMap的函数则是非同步的,它不是线程安全的。若要在多线程中使用HashMap,需要我们额外的进行同步处理。 对HashMap的同步处理可以使用Collections类提供的synchronizedMap静态方法,或者直接使用JDK 5.0之后提供的java.util.concurrent包里的ConcurrentHashMap类。
(3)对null值的处理不同
HashMap的key、value都可以为null。
Hashtable的key、value都不可以为null。
Hashtable的key或value,都不能为null!否则,会抛出异常NullPointerException。
HashMap的key、value都可以为null。 当HashMap的key为null时,HashMap会将其固定的插入table[0]位置(即HashMap散列表的第一个位置);而且table[0]处只会容纳一个key为null的值,当有多个key为null的值插入的时候,table[0]会保留最后插入的value。
(4)支持的遍历种类不同
HashMap支持Iterator(迭代器)遍历。
Hashtable支持Iterator(迭代器)和Enumeration(枚举器)两种方式遍历。
Enumeration 是JDK 1.0添加的接口,只有hasMoreElements(), nextElement() 两个API接口,不能通过Enumeration()对元素进行修改 。
Iterator 是JDK 1.2才添加的接口,支持hasNext(), next(), remove() 三个API接口。HashMap也是JDK 1.2版本才添加的,所以用Iterator取代Enumeration,HashMap只支持Iterator遍历。
(5)容量的初始值和增加方式都不一样
HashMap默认的容量大小是16;增加容量时,每次将容量变为“原始容量x2”。
Hashtable默认的容量大小是11;增加容量时,每次将容量变为“原始容量x2 + 1”。
17.HashMap的实现原理
HashMap的底层是数组和链表的结合体。
从上图可以看出HashMap底层就是一个数组结构,数组中的每一项又是一个链表,当新建一个HashMap时,就会初始化一个数组。
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table; static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
……
}
可以看出,Entry就是数组中的元素,每个 Map.Entry 其实就是一个key-value对,它持有一个指向下一个元素的引用,这就构成了链表。
(1)存储
public V put(K key, V value) {
// HashMap允许存放null键和null值。
// 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。
if (key == null)
return putForNullKey(value);
// 根据key的keyCode重新计算hash值。
int hash = hash(key.hashCode());
// 搜索指定hash值在对应table中的索引。
int i = indexFor(hash, table.length);
// 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
// 如果i索引处的Entry为null,表明此处还没有Entry。
modCount++;
// 将key、value添加到i索引处。
addEntry(hash, key, value, i);
return null;
}
当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
这里HashMap里面用到链式数据结构的一个概念。上面我们提到过Entry类里面有一个next属性,作用是指向下一个Entry。打个比方, 第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0] = A。一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next = A,Entry[0] = B,如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他们通过next这个属性链接在一起。所以疑问不用担心。也就是说数组中存储的是最后插入的元素。
(2)读取
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。
HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。
18.I/O流的分类
字节流
InputStream
FileInputStream
BufferedInputStream
OutputStream
FileOutputStream
BufferedOutputStream
字符流
Reader
FileReader
BufferedReader
Writer
FileWriter
BufferedWriter
转换流: 转换流的作用就是把字节流转换字符流来使用.
A:OutputStreamWriter
OutputStreamWriter(OutputStream os):默认编码,GBK
OutputStreamWriter(OutputStream os,String charsetName):指定编码。
B:InputStreamReader
InputStreamReader(InputStream is):默认编码,GBK
InputStreamReader(InputStream is,String charsetName):指定编码
面试题(一)—Java基础(上)的更多相关文章
- [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)
如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html 谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...
- Java 208 道面试题:Java 基础模块答案
目前市面上的面试题存在两大问题:第一,题目太旧好久没有更新了,还都停留在 2010 年之前的状态:第二,近几年 JDK 更新和发布都很快,Java 的用法也变了不少,加上 Java 技术栈也加入了很多 ...
- 笔试题之java基础
Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io 的语法,虚拟机方面的语法,其他.有些题来自网上搜集整理,有些题来自传智 ...
- 【面试题】Java基础部分面试题
Java基础面试题 Equals与==的区别 使用==比较原生类型如:boolean,,int,char等等, 使用equals()比较对象. 1. ==是判断两个变量或类型是不是指向同一个内存空 ...
- 【JAVA面试题系列一】面试题总汇--JAVA基础部分
JAVA基础 基础部分的顺序: 基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法 线程的语法,集合的语法,io 的语法,虚拟机方面的语法 每天几道,持续更新!! 1.一个". ...
- 面试题(二)—Java基础(下)
一.进程和线程 进程 (1)正在运行的程序,是系统进行资源分配和调用的独立单位. (2)每一个进程都有它自己的内存空间和系统资源. 线程 (1)是进程中的一条执行路径. (2)一个进程如果只有一条执行 ...
- 转载:[Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)
原文:http://www.cnblogs.com/wang-meng/p/5898837.html 一:继承.抽象类与接口区别.访问控制(private, public, protected,默认) ...
- Java面试题(Java基础篇)
Java 基础 1.JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Run ...
- Java面试题系列 ----- Java基础面试题(91道)
更多详情点击查看,点这里!这里!!这里!!! 文末获取所有面试PDF文档! Java概述 1. 何为编程 编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程. 为了 ...
随机推荐
- PrefixHeader.pch' file not found 以及 Xcode 中如何添加pch文件
在开发的过程中,有时候接触到旧项目,会报: 'PrefixHeader.pch' file not found 的错误! 在Xcode6之前,新建一个工程的时候,系统会帮我们自动新建一个以工程名为名字 ...
- HTTP严格安全传输(HTTP Strict Transport Security, HSTS)chromuim实现源码分析(二)
HTTP严格安全传输(HTTP Strict Transport Security, HSTS)chromuim实现源码分析(一) 下面来查看其他对保存HSTS信息的enabled_sts_hosts ...
- WebSocket浅析(一):实现群聊功能
首先WebSocket打破了传统的web请求响应模式,实现管道式的实时通信,并且可以持续连接. 相对于传统 HTTP 每次请求-应答都需要客户端与服务端建立连接的模式,WebSocket 是类似 So ...
- FineUIMvc随笔 - 动态创建表格列
声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 用户需求 用户希望实现动态创建表格列,在 WebForms 中,我们通过在 Page_Init 中创建列来实现: 但是在 MVC ...
- Dapper C# 访问SQLite
1.以操作SQLite为例.先下载Dapper,项目引用添加Dapper.dll,然后入下 SQLiteConnectionStringBuilder sb = new SQLiteConnectio ...
- 最近发现的.net core中的一些bugs
1.使用.net core的过程中发现TypeInfo.GetCustomAttributes()只能写在主线程中,否则如果该自定义特性存在于nuget中就会报错,貌似nuget中的dll仅在主线程使 ...
- Flex 布局教程
今天给大家分享一下flex布局的语法 网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于 ...
- Jquery基本用法
今天下午讲了Jquery的基本用法:在用Jquery方法时,首先要引用Jquery文件: <script src="jquery-1.11.2.min.js">< ...
- 咖啡师之路:第一日一杯Espresso
代码敲累了.产品要发布了.熬夜啊加班啊. 精神完全不在状态. 咋办--- 咋办--- 咋办---! 来一杯Espresso浓缩咖啡.各位码农,码神们的必备良品! 咖啡每天要2-3杯,不管是速溶还是现磨 ...
- vim编辑器的常见使用功能
Vim是一个类似于vi的著名的功能强大.高度可定制的文本编辑器,在Vi的基础上改进和增加了很多特性. 掌握简单的vim命令可以大大提高我们编辑文档效率,在装有vim编辑器的linux系统终端输入vim ...