-------android培训、java培训、期待与您交流!--------------
面试题
byte b = 2;
b = b + 3;这是错的,因为b在内存中占1个8位,3在内存中默认为int,占4个8位,
在执行b+3的时候,b自动提升了int类型与3运算,运算过后的结果还是int
类型,再将int类型的值赋给byte类型,这就会导致错误,除非进行强制类型
转换。如:b = (byte)(b+3);
byte b = 2;
b = (byte)b + 3;
这是错的,因为b原本就是byte,再将b转成byte没有意义,在进行b+3的时候,b依旧会提升为int类型
byte b = 2;
b += 3;
这是正确的,因为b+=3在进行运算时,它就做了强制转换,它有一个内置的强制类型转换
byte b = 3 + 3;
这是正确的,因为3+3在进行运算时,它就做了强制转换,在赋值的时候已经转成转换动作
byte b = 3;
b++;
这是正确的,因为b++在进行运算时,它就做了强制转换,在赋值的时候已经转成转换动作
-------------------------------------------------
5 % 1 = 0
5 % 2 = 1
1 % 5 = 1
2 % 5 = 2
3 % 6 = 3
左边如果小于右边,结果是左
1 % -5 = 1
5 % 2 = 1
-1 % 5 = -1
-5 % 2 = -1
如果运算时出现负数,看左边
-------------------------------------------------
char类型中能否装中文?
答:能,因为一个中文默认是两个字节,而char类型也是两个字节,所以可以装
-------------------------------------------------
以前喜欢考这种题,现在考不考不知道
int x = 3;
x += 4;
那么x的值是多少?
x += 4; 相当于 x = x + 4;,所以结果是 7。
-------------------------------------------------
无限循环的最简单表现形式
for( ; ; ){}
while(true){}
-------------------------------------------------
写出一个 冒泡排序 和 选择排序
选择排序:
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
冒泡排序:
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {// -i:让每次比较元素少一个。-1避免数组越界
if (arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
-------------------------------------------------
有一个 有序 的数组,想要将一个元素插入到该数组中,
还要保证该数组是有序的,如何获取该元素在数组中的位置?
答:可以通过折半的方式,去查找那个元素在数组中的位置,如果这个数存在,
那么就在存在的位置上把元素插入就行。如果元素不存在,则返回最小角标的值,就可以得到要插入的位置
代码演示:
public static int getIndex_2(int[] arr,int key){
int start = 0,end = arr.length-1;
int mid=(start+end)/2;
while(start<=end){
if(key>arr[mid])
start=mid+1;
else if(key<arr[mid])
end=mid-1;
else
return mid;//如果元素存在,则返回存在的位置
mid=(start+end)/2;
}
return -start;//如果元素不存在,则返回最小角标的值,该值就是插入的位置
}
-------------------------------------------------
一维数组定义方式:int[] x;int x[];
二维数组定义方式:int[][] x;
int x[][];
int[] x[];
有两个数组为:int[] x,y[]; 那么一下的题中哪个是正确的?
1,x[0] = y; no
2,y[0] = x; yes
3,y[0][0] = x; no
4,x[0][0] = y; no
5,y[0][0] = x[0]; yes
6,x = y; no
-------------------------------------------------
什么是面向对象:
1.我通过电脑能够和对方视频,和对方聊天,那么电脑就是对象。因为我不需要直接去和对方面对面的说话
而是通过电脑的形式直接和对方说话,我只知道电脑能够视频就行,而不用管它是怎么执行的,这就是面向对象。
2.汽车具备行驶的功能,而我要去某个地方,我可以使用汽车开过去。我不需要知道汽车的驱动是什么原理,也不
需要知道汽车为什么能够行驶。而我只需要知道汽车具备行驶的功能,我去调用汽车的行驶功能,汽车就能把我送到
目的地。那么,汽车就是一个对象,我只是在调用这个对象,而我不需要知道这个对象是如何实现它的功能。
3.手机的拨号功能,我输入拨号的号码后按下拨号键就能拨号,我不需要知道它是如何实现这个拨号功能的,
我只知道它能够拨号
-------------------------------------------------
class Person {
int age;
String name;
/*
构造代码块。
作用:给对象进行初始化。
对象一建立就运行,而且优先于构造函数执行。
和构造函数的区别:
构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化
构造代码块中定义的是不同对象共性的初始化内容
*/
{
System.out.println("构造代码块运行");
}
public Person(){
System.out.println("构造方法Person()运行");
}
public Person(String name){
System.out.println("构造方法Person(String name)运行");
}
}
public class Demo {
public static void main(String[] args) {
new Person();
new Person("zhangsan");
/*
结果:
构造代码块运行
构造方法Person()运行
构造代码块运行
构造方法Person(String name)运行
*/
}
}
-------------------------------------------------
class Demo1 {
int num = 9;
public Demo1() {
System.out.println("a");
}
static {// 静态代码块,给类初始化的
// num = 10; //此语句不能被执行,否则编译错误,因为静态代码块加载进类时num还没加载,所以静态代码块中无法存放num
System.out.println("b");
}
{// 构造代码块,给对象初始化的
System.out.println("c");
}
public Demo1(int x) {// 构造函数,给对应对象初始化的
System.out.println("d");
}
}
public class Demo {
public static void main(String[] args) {
new Demo1(5);// 结果:b c d
}
}
-------------------------------------------------
单例设计模式:
饿汉式: Single类一进内存,就已经创建好了Single对象
class Single{
private static final Single s = new Single();
private Single(){}
public static Single getSingle(){
return s
}
}
懒汉式: Single类进内存,对象还没有存在,只有调用了getSingle方法时,才建立Single对象
class Single {
private static Single s = null;
private Single() {
}
public static Single getSingle() {
if (s == null) {
synchronized (Single.class) {
if (s == null) {
s = new Single();
}
}
}
return s;
}
}
开发时建议使用饿汉式
(面试专用题,必考题,不懂就背下来)
注意:懒汉式和饿汉式有什么不同?懒汉式的特点在于延迟加载,饿汉式不延迟加载。
懒汉式的延迟加载有没有问题?有,如果多线程访问时会出现安全问题。
怎么解决?可以加同步来解决,用同步代码块和同步方法都行,但是稍微有些低效。
用双重判断方式可以解决这个效率问题。
加同步时候,使用的锁是哪一个?该类所属的字节码。
-------------------------------------------------
class Fu {
int num = 3;
void demo1() {
System.out.println("fu_1");
}
void demo2() {
System.out.println("fu_2");
}
static void demo4() {
System.out.println("fu_4");
}
}
class Zi extends Fu {
int num = 5;
void demo1() {
System.out.println("zi_1");
}
void demo3() {
System.out.println("zi_3");
}
static void demo4() {
System.out.println("zi_4");
}
}
public class Demo {
public static void main(String[] args) {
Fu f = new Zi();
f.demo1(); // 结果为zi_1 ,成员函数多态时,看右边
f.demo2(); // 结果为fu_2 ,成员函数多态时,看右边,右边有没此方法,则去父类中找
// f.demo3(); //编译失败,因为class Fu中没有demo3这个方法
f.demo4();//fu_4 ,静态方法多态时,看左边,左边是什么类型的类,就执行什么类型的类
System.out.println(f.num); // 结果为3 ,成员变量多态时,看左边。左边是什么类型的类,就执行什么类型的类
}
}
在多态中成员函数的特点:
在编译时期:参阅引用变量所属的类中是否有调用的方法(左边)。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法(右边),如果有,则执行右边,没有,则执行左边
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
在多态中,成员变量的特点:
无论在运行还是编译时,都参考左边(引用型变量所属的类)。
在多态中,静态成员函数的特点:
无论运行还是编译时,都参考左边
在多态中,静态变量的特点:
无论运行还是编译时,都参考左边
-------------------------------------------------
外部其他类访问内部类的格式要记住,面试会考
访问格式:
1.当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中直接建立
内部类对象。格式 外部类名.内部类名 变量名 = new 外部类名().new内部类名
2.当内部类在的成员位置上,就可以被成员修饰符所修饰。
比如:private: 将内部类在外部类中进行封装,外部其他类无法访问该内部类
static: 内部类就具备了static的特性。
当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。
在外部其他类中,如何访问static内部类的非静态成员呢?
new Wai.Nei2().function_2();
在外部其他类中,如何访问static内部类非静态成员呢?
Wai.Nei2.function_3();
注意:当内部类中定义了static成员,那么内部类必须是static的
什么时候使用内部类:当事物中还有内部事物的时候,使用内部类(如:人是一个事物,而心脏是人的内部事物,那么
可以将心脏建立为内部类)
class Wai{
int x = 3;
class Nei{
int x = 4;
static final int y = 3; //注意:非静态内部类中可以放 静态常量,但是不能放静态变量。如:static int y = 3;
public void function_1(){
int x = 5;
System.out.println("这是内部类的方法");
System.out.println(x); //结果为5
System.out.println(this.x); //结果为4
System.out.println(Wai.this.x); //结果为3
}
}
static class Nei2{
public void function_2(){
System.out.println("static内部类非静态方法");
}
public static void function_3(){
System.out.println("static内部类静态方法");
}
//public void function_4(){
// x = 7; //此语句错误,如果将外部类的x修饰为static那就正确,因为静态的内部类只能访问静态的成员变量
//}
}
// class Nei3{ //内部类中定义了static成员,那么内部类必须是static的
// public static void function_4(){
// System.out.println("非静态内部类的static方法");
// }
//}
}
public class Demo {
public static void main(String[] args) {
Wai.Nei n = new Wai().new Nei();//外部其他类中访问内部类的方式
n.function_1();
new Wai.Nei2().function_2();//外部其他类中访问static内部类的非静态成员方式
Wai.Nei2.function_3();//外部其他类中访问static内部类的静态成员方式
}
}
-------------------------------------------------
/*
面试题:
问:在没有父类或者接口情况下,能否使用匿名内部类吗?
答:能,代码如下
*/
public class Demo {
public static void main(String[] args) {
new Object(){
public void function(){
System.out.println("123");
}
}.function();
/*这个使用方式是错误的,Object o = new Object(){},
相当于Object o = new Object的子类,因为Obcect类中
没有function方法,所以不能调用function方法
Object o = new Object(){
public void function(){
System.out.println("123");
}
};
o.function();
*/
}
}
-------------------------------------------------
/*
问:这段代码编译会通过吗?
会,因为RuntimeException是一个特殊的异常,抛出异常时,可以不用进行声明
*/
class ExceptionDemo {
int div(int a, int b)//此处没有声明异常,编译会通过吗?
{
if (b < 0)
throw new RuntimeException();
return a / b;
}
}
-------------------------------------------------
/*
问:此程序中finally语句有执行到吗
没有执行到,因为发成异常时,在catch语句中执行了System.exit(0);导致了系统退出,所以finally没有执行到
*/
class Test {
public double function(double a, double b) throws Exception {
if (b <= 0)
throw new Exception();
return a / b;
}
}
public class Demo {
public static void main(String[] args) {
Test t = new Test();
try {
double num = t.function(3, 0);
} catch (Exception e) {
System.out.println(e.toString());
System.exit(0);//系统退出。当执行这里时,funally是执行不到的
} finally {
System.out.println("finally run");
}
System.out.println("over");
}
}
-------------------------------------------------
/*
* 写出程序结果
*/
class Wai{
int y = 6;
class Nei{
static int y = 3;
void show(){
System.out.println(y);
}
}
}
public class Demo {
public static void main(String[] args) {
Wai.Nei wn = new Wai().new Nei();
wn.show();
}
}
/*
* 编译失败:非静态内部类中不可以定义静态成员,静态常量除外
* 内部类中如果定义了静态成员,该内部类必须被静态修饰
*/
-------------------------------------------------
线程中,主函数直接调用run方法和调用start方法有什么区别?
答:主函数调用run方法和函数调用差不多,只有主线程在执行代码。
当调用start方法时,则代表开启了一个线程,那么,程序中相当于有两个线程在执行。一个是主线程,一个是run方法
-------------------------------------------------
实现方式和继承方式有什么区别呢?
答:
实现方式的好处:避免了单继承的局限性。
定义线程时,建议使用实现的方式。
-------------------------------------------------
同步函数和静态同步函数用的锁是什么?
答:同步函数用的锁是this
静态同步函数用的锁是类的字节码 既:类名.class
-------------------------------------------------
/*
写一个死锁程序
*/
class Test1 implements Runnable {
public void run() {
while (true) {
synchronized (Test1.class) {
System.out.println("Test1...Test1.class");
synchronized (Test2.class) {
System.out.println("Test1...Test2.class");
}
}
}
}
}
class Test2 implements Runnable {
public void run() {
while (true) {
synchronized (Test2.class) {
System.out.println("Test2...Test2.class");
synchronized (Test1.class) {
System.out.println("Test2...Test1.class");
}
}
}
}
}
public class Demo {
public static void main(String[] args) {
new Thread(new Test1()).start();
new Thread(new Test2()).start();
}
}
-------------------------------------------------
String s1 = "abc";
String s2 = new String("abc");
问:s1和s2有什么区别呢?(面试题)
答:
s1在内存中有一个对象。
s2在内存中有两个对象。
-------------------------------------------------
面试题
/*
* JDK1.5 版本以后出现的新特性。
*/
public class Demo {
public static void main(String[] args) {
Integer a = new Integer(127);
Integer b = new Integer(127);
print(a==b);//false //不管是不是在-128~127范围 a和b都是不同对象
print(a.equals(b));//true
Integer c = new Integer(128);
Integer d = new Integer(128);
print(c==d);//false //不管是不是在-128~127范围 c和d都是不同对象
print(c.equals(d));//true
Integer x = 127;
Integer y = 127;//JDK1.5 以后,自动装箱,如果装箱是byte范围内(-128~127),如果该数值已经存在,则不会开辟新的空间
print(x == y);//true 注意:x和y指向了同一个对象,因为x和y在-128~127之间
print(x.equals(y));//false
Integer z = 128;
Integer k = 128;//因为128超过了byte范围,所以新开辟了一个空间
print(z == k);//false 注意:z和k是不同对象,因为z和k大于 byte范围(-128~127)
print(z.equals(k));//false
Integer i1 = 4;
Integer i2 = i1 + 2;// i1进行自动拆箱,变成int类型,和2进行加法运算。再将和进行自动装箱赋值给i2。 i1自动拆箱的方式是 i1.intValue();
}
public static void print(Object o){
System.out.println(o);
}
}
-------------------------------------------------
|--Collection
|--List:有序(存入和取出的顺序一致),元素都有索引(角标),元素可以重复
|--ArrayList:底层是数组数据结构。特点:查询速度很快,增删稍慢。线程不同步
保证唯一性原理:判断元素是否相同或者保证唯一性 只 依赖于equasl方法。ArrayList只会调用equals方法。
|--LinkedList:底层是使用链表数据结构。特点:增删速度很快,查询稍慢。线程不同步
|--Vector:底层是数组数据结构。现在基本不用,因为已经被ArrayList代替。增删,查询都很慢。线程同步。
|--Set:元素不能重复,无序。
|--HashSet:底层数据结构是哈希表,线程是不同步的
保证唯一性原理:判断元素的hashCode值是否相同。
如果相同,还会继续判断元素的equals方法是否为true。
|--TreeSet:底层数据结构是二叉树,可以对Set集合中的元素进行排序。线程不同步
TreeSet第一种排序方式:
让元素自身具备比较性。元素要实现Comparable接口,覆盖ComparTo方法,
如果本类对象大于比较类,则返回正数。小于返回负数。等于返回0。
这种方式也称为元素的自然顺序,或者叫做默认顺序。
TreeSet第二种排序方式:
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合具备比较性。
在集合初始化时,就有了比较方式
-------------------------------------------------
/*
面试会考addLast、addFirst的存入结果,
和removeLast、removeFirst删除的结果
*/
import java.util.*;
public class Demo {
public static void main(String[] args) {
// function1();
function2();
}
public static void function1() {
LinkedList link = new LinkedList();
link.addLast("java01");
link.addLast("java02");
link.addLast("java03");
print(link);// 结果:[java01, java02, java03]
print(link.getFirst());// 结果:java01
print(link.getFirst());// 结果:java01注意:这里是java01
print(link.removeFirst());// 结果:java01
print(link.removeFirst());// 结果:java02。注意:这里是java02,因为java01已经被删除,于是java02为第一个
}
public static void function2() {
LinkedList link = new LinkedList();
link.addFirst("java01");
link.addFirst("java02");
link.addFirst("java03");
print(link);// 结果:[java03, java02, java01]
// 不用迭代器遍历link
while (!link.isEmpty()) {//如果link不为空
print(link.removeFirst());// 结果:java03 java02 java01
}
}
public static void print(Object obj) {
System.out.println(obj);
}
}
-------------------------------------------------
问:在集合中,哪些集合是同步的,哪些集合是非同步的
答:在集合中除了Vector是同步的,其他的集合都是非同步的。在对非同步的
集合进行多线程操作时,可以使用加锁的形式限定
-------------------------------------------------
问:ArrayList 和 HashSet判断元素是否相同,或者保证唯一性,依赖于什么方法?两者有什么不同?
答:ArrayList判断元素是否相同或者保证唯一性 只 依赖于equasl方法。ArrayList只会调用equals方法。
HashSet判断元素是否相同或者保证唯一性不仅依赖于hasCode方法,还依赖于equals方法。
HashSet先调用hashCode方法,如果返回的hashCode值相同,则去调用equals方法。如果返回的hashCode值不同,则不调用equals方法
-------------------------------------------------
问:Hashtable 和 HashMap 有什么区别?
答:Hashtable 不可以 存入null键和null值。该集合是线程 同步 的。JDK1.0 出现的,效率低。
HashMap 允许 使用null键和null值。该集合是 不同步 的。JDK1.2 出现的,效率高
Hashtable 和 HashMap的相同点,都是哈希表数据结构
-------------------------------------------------
问:Collection和Collections有什么区别?
答:
Collection是集合类跟类,他的子类主要有Set 和List.
Collections是集合类的一个帮助类,他提供一些静态方法实现对各种集合的搜索、排序、线程安全化等操作。
-------------------------------------------------
double d1 = Math.ceil(16.34);//ceil返回大于指定数据的最小整数
double d2 = Math.floor(16.34);//floor返回小于指定数据的最大整数
print("d1="+d1);//17.0
print("d2="+d2);//12.0
double d3 = Math.pow(2, 3);//2的3次幂
print("d3="+d3);//d3=8.0
long long1 = Math.round(12.51);//四舍五入
long long2 = Math.round(12.49);//四舍五入
print("long1="+long1);//long1=13
print("long2="+long2);//long2=12
-------------------------------------------------
UDP:
1,面向无连接
2,数据封包,数据大小限制带64k内
3,是不可靠协议
4,传输速度快
哪些属于udp传输:聊天
TCP
1,面向连接
2,大数据量传输
3,是可靠协议
4,因为需要连接,所以效率低
哪些属于tpc传输:下载
-------------------------------------------------
列出5个常见异常:
IOException ArrayIndexOutOfBoundsExceptionInterruptedException
NullPointerException ConnectExceptoinBindException
-------------------------------------------------
/*
*1,用代码详细描述线程间的通信(等待唤醒机制)
*/
class ThreadDemo implements Runnable {
static Object obj = new Object();// 定义一个锁
public void run() {
synchronized (ThreadDemo.obj) {
try {
System.out.println("线程进入等待");
obj.wait();// 当执行到这里,线程就进入了等待。等待被另外一个线程所唤醒
System.out.println("线程已经被唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo {
public static void main(String[] args) throws Exception {
new Thread(new ThreadDemo()).start();// 开始线程
Thread.sleep(3000);// 让程序暂停3秒再往下执行
synchronized (ThreadDemo.obj) {// 代码1
// 代码2
ThreadDemo.obj.notifyAll();// 唤醒了ThreadDemo类中正在等待的线程
}// 代码3
// 如果将以上的代码1,2,3注释,将代码改为如下代码,会发生异常。因为等待唤醒机制必须定义在同步中。
// ThreadDemo.obj.notifyAll();
// 如果将以上的代码1,2,3注释,将代码改为如下代码,会发生异常。因为等待唤醒机制必须使用同一个锁
// synchronized (Demo.class) {
// ThreadDemo.obj.notifyAll();
// }
}
}
/*
* 由此实例可知。 当一个线程进入等待时,线程就不再往下执行了。 如果想往下执行,必须在另外一个线程中将等待的线程给唤醒,否走线程会一直等待下去
*
* 等待唤醒机制的前提: 必须使用在同步中,并且使用的是同一个锁。 同步可以使用synchronized的方法,也可以使用Lock的方式加锁
*/