1、阐述下对象的自动装箱和拆箱 2
基本数据类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0开始提供的功能。
自动装箱是java编译器在java原生类型和对应的对象包装类型上做的自动转换。
自动装箱:
Integer i = 1;
其实编译器为你自动实现了:
Integer i = Integer.valueOf(1);
自动拆箱:
Integer i = 1;
int a = i;
实际上执行了:
int a = i.intValue();
2、switch支持的数据类型
包括byte、short、char、int 和 enum ,及包装类型Character、Byte、Short和Integer,
java7后又加入了对String的支持。
阐述下支持String的原理:
使用字符串的hash值作为表达式的值,而由于相同哈希值的情况下仍存在冲突的可能,
所有在case语句块时仍需要通过equals方法来判断相等。
3、equals、==、hashCode:
== : 比较引用地址的相等或基本数据类型/枚举类型的相等
Equal:对象的值情况的相等
hashCode:返回对象的存储地址
关系:
两对象比较:euqals返回true时,hashCode也相等。
hashCode相等时,equals返回不一定相等。
instanceof: 判断对象类型5是否相等,当父、子类判断时存在单向情况。
对象判断equals方法:
1、 == 判断引用地址 2、instanceof 判断类型 3、属性匹配
4、自反性、对称性、传递性、一致性 5、重写hashcode
甲学生的年龄 :16 ,学号: 12345
乙学生的年龄 :16, 学号: 54321
这样甲和乙的hashcode 重写方式一样的 1 + 2+ 3+ 4+ 5 +(16*1 )= 31
但是 12345 不equals 54321
4、创建对象:
主要有以下四种对象创建方式:
1、new 2、反射 (这俩要调用构造函数) 3、clone 4、 反序列化
其中:
克隆:通过实现Cloneable、Serializable(序列化、反序列化实现)来实现对象的克隆
反射:
该方式的表现主要有:
1、运行时取得字段与方法和修改(包括常量)
2、创建对象
原理:jvm通过字节码文件生成相应的对象或获取其信息
优缺点:增加了程序设计的灵活性;性能消耗较大
5、简述下多态,Java多态的实现原理?动态绑定的理解?:
重载:同一类中,同名函数不同的参数形式,基于对象实际的类型来选择所调用的方法,达到动态绑定的目的。
重写:父类、子类中,同名同参方法,重新定义方法实现。
区别: 前者编译时多态性、后者运行时多态性
(静态方法除外,多态是针对实例方法)
将一个方法调用同一个方法主体关联起来被称作绑定,JAVA中分为 前期绑定和后期绑定(动态绑定或运行时绑定),
前期绑定: 在程序执行之前进行绑定(由编译器和连接程序实现)叫做前期绑定,因为在编译阶段被调用方法的直接地址就已经存储在方法所属类的常量池中了,程序执行时直接调用。
后期绑定:含义就是在程序运行时根据对象的类型进行绑定,想实现后期绑定,就必须具有某种机制,以便在运行时能判断对象的类型,从而找到对应的方法,简言之就是必须在对象中安置某种“类型信”,JAVA中除了static方法、final方法(private方法属于)之外,其他的方法都是后期绑定。
Java技术----多态的实现原理
6、简述下抽象和接口的区别:
抽象类:区别与普通的类,不能直接被实例化,可以有构造函数,并且子类可不实现其抽象方法。
接口:修饰符为public、变量为final,没有实际的方法,可实现多继承。
7、简述public、protected、private、default 的区别:2
也叫 作用域修饰词
public 作用范围:当前类、同一个包、子类、其他包;
protected 作用范围:当前类、同一个包、子类;
default 作用范围:当前类、同一个包;
private 作用范围:当前类;
8、简述下创建线程的方式:
1、直接通过new thread 的方式;
2、实现runnable接口;
3、通过接口callable (callable能拿到返回值和抛出异常);
4、通过线程池来生成线程;
9、sleep、wait、yield、notify、notifyall:
sleep和yield区别:
sleep 给予线程的运行机会 不考虑优先级,then 阻塞
yield:给优先级高的线程执行,然后进入就绪状态
wait和sleep区别:
wait:释放对象锁 object的方法 —> notify
sleep:不释放锁 thread的方法
两者都可通过interrupted 打断暂
notify和notifyall区别:
notify:唤醒的某一线程去得到锁
notifyall:唤醒所有等待线程去竞争锁
wait/notify/notifyall : 它们都需在同步块中调用 ,均可释放对象锁;
wait:立即释放控制权 然阻塞(需notify)
notify:执行完再释放
10、synchronized 、Lock区别:
synchronized:关键字
Lock:对象 可控制获取锁的时间与获取锁的信息
手动释放锁、让线程响应中断、可知获得锁与否
多线程竞争较激烈时,Lock较优
上下文切换:cpu控制权由一个正在运行的线程切换到另一个就绪状态的线程
11、异常处理:
Error、Exception:
父类:Throwable :含异常出现时的log
Error:系统级错误,如OOM
Exception:
需程序捕捉和处理的程序设计性错误
被检查异常(throw、try catch)、运行时异常
Throw:方法中抛出异常
Throws:申明异常
try catch finally:
try中有return 会记录返回值 待finally执行完 返回值不变
如finally中有return 则值会变
finally:释放外部资源
12、简述下JVM内存模型: 2
JVM的内存模型主要可以分为线程共享区和线程私有区,
线程共享区:java堆(放对象和数组、GC)、方法区(类信息、常量、静态变量等,永久代);
线程私有区:程序计数器(指示代码执行、无oom)、Java虚拟机栈(java方法调用)、native方法栈;
而每个线程都有自己的栈内存, 堆是共享的,线程会缓存对象到栈中使用,而volatile则可要求线程从内存中读取
13、简述下GC机制:2
判断对象内存是否该被回收:JVM根据可达性分析(引用计数会出现互相引用的情况)
java内存回收算法大概可分为:
分年代回收:年轻代(创建)、老年代(呆的久)、永久代
标记-复制算法:区域分两块 一块使用另一块回收 交替使用
空闲区满时 就被复制到老年代区
标记-清除、标记-整理算法
14、算法
排序(必须手写会)
//冒泡 排序
public static void BubbleSort(int [] arr){
int temp;//临时变量
for(int i=0; ii; j--){
if(arr[j] < arr[j-1]){
temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
}
}
}
}
排序算法总结
查找()
15、java中的基本数据类型?各占多少位?多少字节?取值范围?String是基本类型还是引用类型?
基本数据类型(8种):
1.Int 32 4 -2,147,483,648 ~ 2,147,483,647
2.Short 16 2 -32768 ~ 32678
3.long 64 8 -9,223,372,036,854,775,808~+9,223,372,036,854,775,807
4.float 32 4 -3,40292347E+38 ~ +3,40292347E+38
5.double 64 8 -1.79769313486231576E+308 ~ 1.79769313486231576E+308
6.char 16 2 ‘\u0000′ ~ ‘\uFFFF’
7.boolean 1 0.125 true/false
8.byte 8 1 -128 ~ 127
String是引用类型,
16、Java什么时候是值传递什么时候是引用传递?
值传递的时候,将实参的值,copy一份给形参;
引用传递的时候,将实参的地址值,copy一份给形参。
不管是值传递还是引用传递,形参拿到的仅仅是实参的副本,而不是实参本身。
Java到底是值传递?还是引用传递?
17、String相关的。String常量池,StringBuffer,StringBuilder。String不可变的理解。String的intern方法不同版本的实现原理的区别。
String常量池:
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中,就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突进行共享.
留意文章中的面试题: (貌似被虐过!!!)
String之常量池小结
String常量池,StringBuffer,StringBuilder的区别:
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
Java中的String,StringBuilder,StringBuffer三者的区别
a++与++a的区别,如果单独使用没有任何区别,如果在运算中就有区别了,a++是先运算在赋值,而++a是先赋值在运算!!
String不可变的理解:
举个例子:String str = "aa"; str = "aa"+"bb";
此时str的值为"aabb",但是"aabb"不是在开始的字符串"aa"后面直接连接的"bb",而是又新生成了字符串"aabb",字符串"aa"一旦被初始化,那么它的值不可能再改变了。
StringBuffer strb = StringBuffer("aa"); strb.append("bb");
此时的strb的值也为"aabb",但是"aabb"是直接在开始的字符串"aa"后面连接的“bb”,并没有生成新的字符串。
String对象的底层实际上是一个char[]数组:
private final char value[];
用final修饰的对象值可变,但是引用不变,
StringBuffer对象的底层也是一个char[]数组:
char[] value;
为什么String对象不可变,而StringBuffer可变?
18、JAVA集合框架
-
Collection:存储单个数据或者对象。
- |-List:列表:
- |-LinkedList :基于链表的List
- |-ArrayList :基于数组的List
- |-SubList:一个List的视图
- |-Vector:一个线程安全的List
- |-Stack:栈
- |-Queue:队列 ,通常作为数据存储结构,不作为操作容器。集合框架中应用比较少,主要在在并发包(java.util.concurrent)中实现的阻塞队列(消息队列)。
- |-ArrayDeque:基于数组实现的尾插队列(包含head,tail头尾指针).
- |-PriorityQueue:基于数组的自排序优先级队列(基于数组实现存储的二叉树堆排)。
- |-Set:一个不允许重复数据的集合
- |-HashSet:基于Hash+数组+链表实现的Set。
- |-LinkedHashSet:一个基于LinkedHashMap实现的Set。
- |-TreeSet:一个基于TreeMap实现的Set。
- |-EnumSet:
- |-JumboEnumSet
- |-RegularEnumSet
- |-HashSet:基于Hash+数组+链表实现的Set。
- |-List:列表:
-
Map:存储一组K-V键值对。
- |-HashMap:基于Hash+数组+链表实现的Map。
- |-LinkedHashMap:基于HashMap实现的双向链表。LruCache实现基础
- |-HashTable:基于Hash+数组+链表实现的线程安全(sync)Map。
- |-TreeMap:基于红黑树实现的有序Map。
- |-WeakHashMap:K为弱引用的HashMap,使用中,若k没有被引用则会自动回收掉
- |-HashMap:基于Hash+数组+链表实现的Map。
集合框架中唯一的两个线程安全集合
Vector(Stack是Vector的子类也是安全的)
Hashtable
ArrayList,LinkedList异同点:
- 相同点:
- List是数组的封装接口,所有实现类都可与数组转换,且进行index(索引下标)获取,对于ArrayList和LinkedList只不过是不同的实现方式
- 不同点:
- ArrayList是对数组的封装,使得对数组的操作更加方便,查询快,增删慢。LinkedList是链表的实现,增删快,查询慢
HashMap,HashTable中的关联和差异:
HashMap与HashTable最大的区别在于hashtable是线程安全的,
hashMap K-V都可为null,hashTable K-V都不能够为null.
ArrayList和Vector的比较:
- 相同点:
两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组, - 不同点:
- Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的
- ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList与Vector的存储空间,Vector增长原来的一倍,ArrayList增加原来的0.5倍。
补充: 底部的数据结构?散列表冲突的处理方法,散列表是一个什么样的数据结构?HashMap是采用什么方法处理冲突的?
HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置。
当程序执行 map.put(String,Obect)方法 时,系统将调用String的 hashCode() 方法得到其 hashCode 值——每个 Java 对象都有 hashCode() 方法,都可通过该方法获得它的 hashCode 值。
得到这个对象的 hashCode 值之后,系统会根据该 hashCode 值来决定该元素的存储位置。
HashMap采用的链表法的方式,链表是单向链表。
链表法就是将相同hash值的对象组织成一个链表放在hash值对应的槽位;
当创建 HashMap 时,有一个默认的负载因子(load factor),其默认值为 0.75,
增大负载因子可以减少 Hash 表(就是那个 Entry 数组)所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的的操作(HashMap 的 get() 与 put() 方法都要用到查询);
减小负载因子会提高数据查询的性能,但会增加 Hash 表所占用的内存空间。
http://blog.csdn.net/u011202334/article/details/51498893
集合面试题1
集合面试题2
集合框架
Java容器框架
19、Java容器相关的辅助类Arrays和Collections了解一下(看那个傻逼问!)。
- Array与Arrays的区别:
- Array :数组类 ,提供了动态创建和访问 Java 数组的方法。
- Arrays:工具类,该类中包含了一些方法用来直接操作数组,比如可直接实现数组的排序(sort())、搜索(binarySearch())等。
- Collection和Collections的区别:
- Collection:集合接口(集合类的一个顶级接口)
- Collections:集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
20、Java中final,finalize()和finally的区别:
- final:关键字,可以用于类,方法,变量前,用来表示该关键字修饰的类,方法,变量具有不可变的特性
- final关键字用于基本数据类型前:这时表明该关键字修饰的变量是一个常量,在定义后该变量的值就不能被修改。
- final关键字用于方法声明前:这时意味着该方法时最终方法,只能被调用,不能被覆盖,但是可以被重载。
- final关键字用于类名前:此时该类被称为最终类,该类不能被其他类继承。
- finalize():finalize方法来自于java.lang.Object,用于回收资源。
- 可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。
在实际应用中,不要依赖使用该方法回收任何短缺的资源,这是因为很难知道这个方法什么时候被调用。
- 可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。
- finally:当代码抛出一个异常时,就会终止方法中剩余代码的处理,并退出这个方法(代码块)的执行。
finally try catch 顺序问题
21、Java怎样开启一个线程。线程池是干什么的?有哪些常用的线程池?优缺点是什么?
开启线程的方式:
1、继承Thread类:
//1):定义一个类A继承于java.lang.Thread类.
class MusicThread extends Thread{
//2):在A类中覆盖Thread类中的run方法.
public void run() {
//3):在run方法中编写需要执行的操作
for(int i = 0; i < 50; i ++){
System.out.println("播放音乐"+i);
}
}
}
public class ExtendsThreadDemo {
public static void main(String[] args) {
for(int j = 0; j < 50; j ++){
System.out.println("运行游戏"+j);
if(j == 10){
//4):在main方法(线程)中,创建线程对象,并启动线程.
MusicThread music = new MusicThread();
music.start();
}
}
}
}
2、实现Runnable接口:
//1):定义一个类A实现于java.lang.Runnable接口,注意A类不是线程类.
class MusicImplements implements Runnable{
//2):在A类中覆盖Runnable接口中的run方法.
public void run() {
//3):在run方法中编写需要执行的操作
for(int i = 0; i < 50; i ++){
System.out.println("播放音乐"+i);
}
}
}
public class ImplementsRunnableDemo {
public static void main(String[] args) {
for(int j = 0; j < 50; j ++){
System.out.println("运行游戏"+j);
if(j == 10){
//4):在main方法(线程)中,创建线程对象,并启动线程
MusicImplements mi = new MusicImplements();
Thread t = new Thread(mi);
t.start();
}
}
}
}
3、直接在函数体使用(特殊的第二种):
void java_thread()
{
Thread t = new Thread(new Runnable(){
public void run(){
// run方法具体重写
mSoundPoolMap.put(index, mSoundPool.load(filePath, index));
getThis().LoadMediaComplete();
}});
t.start();
}
补:继承方式和实现方式的区别?(遇到过)
- 继承方式:
- 从设计上分析,Java中类是单继承的,如果继承了Thread了,该类就不能再有其他的直接父类了.
- 从操作上分析,继承方式更简单,获取线程名字也简单.(操作上,更简单)
- 从多线程共享同一个资源上分析,继承方式不能做到.
- 实现方式:
- 从设计上分析,Java中类可以多实现接口,此时该类还可以继承其他类,并且还可以实现其他接口,设计更为合理.
- 从操作上分析,实现方式稍微复杂点,获取线程名字也比较复杂,得使用Thread.currentThread()来获取当前线程的引用.
- 从多线程共享同一个资源上分析,实现方式可以做到(是否共享同一个资源).
线程池构成
- 线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
- 工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
- 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
- 任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
有哪些常用的线程池?优缺点是什么?
线程生命周期:
几个方法的比较:
Thread.sleep(long millis),thread 方法,一定是当前线程调用此方法,当前线程进入阻塞,但不释放对象锁,millis后线程自动苏醒进入可运行状态。作用:给其它线程执行机会的最佳方式。
obj.wait(),obj方法,当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout)timeout时间到自动唤醒。
Thread.yield(),一定是当前线程调用此方法,当前线程放弃获取的cpu时间片,由运行状态变会可运行状态,让OS再次选择线程。作用:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield()不会导致阻塞。
t.join()/t.join(long millis),当前线程里调用其它线程1的join方法,当前线程阻塞,但不释放对象锁,直到线程1执行完毕或者millis时间到,当前线程进入可运行状态。
obj.notify() 唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程。
22、volidate关键字的作用?
- volatile关键字不但可以防止指令重排
- 保证线程访问的变量值是主内存中的最新值。
什么是单例模式?
Volidate的原理和指令重排序
23、Java clone的使用。
Person p = new Person(23, "zhang");
Person p1 = (Person) p.clone();
System.out.println(p);
System.out.println(p1);
打印结果:
//com.pansoft.zhangjg.testclone.Person@2f9ee1ac
//com.pansoft.zhangjg.testclone.Person@67f1fba0
Java中的clone方法
24、Java反射机制
反射机制:是程序在运行时能够获取自身的信息。
在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
提供的功能:
在运行时能够判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任一对象的方法
在运行时创建新类对象
反射机制的优缺点:
- 优点:反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性
- 缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
25、Java静态代理和动态代理
Java静态代理和动态代理
26、类的加载过程,Person person = new Person();为例进行说明
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的java.lang.Class对象,用来封装类在方法区类的对象。
类从被加载到内存开始,到卸载出内存为止,其整个生命周期:
加载,验证,准备,解析,初始化,使用,卸载
其中:验证,准备,解析三个阶段又统称为“连接”
类加载的过程:
包括:加载,验证,准备,解析和初始化等5个阶段。
阿里、百度 都问过 自己看着办!