黑马程序员--Java基础面试题整理

时间:2021-11-14 00:34:44
------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流!


Java面试题整理(小妞自己学习过程中整理的重点题目,为面试做准备,还不完整,待续)




编程基础


1.(面试题):
char c1 = 126;
char c2 = 180;
char c3 = 300;
System.out.println(c1);//126
System.out.println(c2);//-76
System.out.println(c3);//44


解释:180在内存中的存储为00000000 00000000 00000000 10110100(补码)
可以得到反码:00000000 00000000 00000000 10110011
原码: 00000000 00000000 00000000 11001100
由于char类型在内存中占一个字节,所以只截取最后8位,即:11001100
转换为十进制为:-76


300在内存中的存储为:00000000 00000000 00000001 00101100(补码)
原码也为:00000000 00000000 00000001 00101100
截取最后8位:00101100


2.面试题:
short s = 4;
s = s + 5;//编译失败,涉及到类型转换
s+=5;//编译成功,自动强转
3.例(面试题):
   byte a=3;
   byte b=4;
   byte c=a+b;
   byte d=3+4;//不会报错,因为参与运算的是常量,编译器会先计算值,再看该值是否是左边能够表示的范围。如果是,就不报错。


这个byte c=a+b;是要报错的,因为a+b在计算的时候是默认转换成int型计算的(byte,short,char类型的变量计算时皆会提升为int,而其它类型则按它们自己的类型计算),结果也是int型,此时应对a+b进行byte强制转换。
另:在强制转换时应对int用()括起来,不然报错!
4.面试题
byte b1=3,b2=4,b;
b=b1+b2; 
b=3+4;
哪句是编译失败的呢?为什么呢?


5.最有效率的方式算出2乘以8等于几?
2<<3
6.对两个整数变量的值进行互换。
位^运算符
a = a ^ b;
b = a ^ b;
a = a ^ b;
7.面试题。switch语句后面的表达式可以是byte吗?可以是long吗?可以是String吗?
值x:用于和表达式进行匹配的值。


可以是byte,short,int,char
JDK5以后可以是枚举(就业班讲,实际上就是一个特殊的类)。
JDK7以后可以是String。


8.
/*
打印九九乘法表:面试题
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
*/
for (int i=1;i<=9 ;i++ )
{
for (int j=1;j<=i ;j++ )
{
System.out.print(j+ "*" + i + "=" +j*i+"\t");//制表符\t
}
System.out.println();
}


面向对象:


1.面向对象的思想:(能举例说)
A:是一种更符合人们思考习惯的思想。
B:把复杂的事情简单化了。
C:把我们从执行者变成了指挥者。


举例:
买电脑。
洗衣,做饭。
旅游。
把大象装进冰箱。
2.(面试)类与对象的关系:(掌握)
把事物转换成类:
A:成员变量
定义在类中,方法外。
B:成员方法
和以前的区别是去掉static。


类:是相关的属性和行为的集合。是一个抽象的概念。
对象:是某种事物的具体存在,具体的表现形式。


举例:
类:学生
对象:张三
3.构造代码块


(这个知识点主要是面试用)
作用:给对象进行初始化(或者说是把所有构造函数*同的内容提取出来)
      对象一建立就运行,而且优先于构造函数执行。new一个执行一次
特点:用于定义不同对象共性的初始化内容。
与构造函数的区别:
构造代码块是给所有对象进行统一初始化;而构造函数是给对应的对象初始化。
class Person
{
private String name;
private int age;
{
System.out.println("person code run");//这就是构造代码块!
}
Person()
{
System.out.println("A:name="+name+",age="+age);//构造函数
}


}


4.
对象的初始化过程(面试).jpg


5.代码块(面试题)
(1)执行顺序:
静态代码块 --> 构造代码块 --> 构造方法
eg.继承中的执行顺序:
父类静态代码块-->子类静态代码块-->父类构造代码块-->父类构造方法-->子类构造代码块-->子类构造方法
(2)注意事项:
静态代码块只执行一次。


6.延迟加载的单例设计模式(懒汉式)










7.继承
好处:(面试)
A:提高代码的复用性。
B:让类与类之间产生了一个关系,是多态的前提。
继承的特点:(面试)
A:Java只支持单继承,不支持多继承。
为什么?如果支持多继承,当多个父类定义了相同功能,但功能内容不同时,不确定要运行哪一个,就会有调用不明确的问题。
B:Java支持多层(重)继承。
8.面试题:方法重载和方法覆盖的区别
方法重写是在子父类两个类中实现的,实现的是方法的覆盖,两个方法是完全一样的;
方法重载是在同一个类中实现的,实现的是方法的并列存在,两个方法只是名字一样,而方法参数类型或者参数个数至少有一个不同。


重载:只看同名函数的参数列表
    重写:子父类方法要一模一样


9.抽象:
面试题
abstract不能和哪些关键字共存。
1)private :因为一个abstract方法需要被重写,而被private修饰的方法不能重写,所以不能修饰为private;
  2)final:因为一个abstract方法需要被重写。而被final修饰的类不能被继承,被final修饰的方法是不能被重写的,所以不能同final共存;
    3)static:因为一个方法要是同时被static 和abstract修饰,那么这个方法就可以类名.方法名 调用. 但是此方法是抽象的,调用也无意义,所以就导致static 和abstract不能共存.


10.抽象类和接口的关系?(面试题掌握)
面试题必考之题!
抽象类和接口的区别与特点总结.
     1:成员特点
抽象类:
成员变量:可以是变量,也可以是常量。
构造方法:有构造方法。
成员方法:可以是抽象方法,也可以是非抽象方法。

接口:
成员变量:只能是常量。
 默认修饰符:public static final
成员方法:只能是抽象方法。
 默认修饰符:public abstract


     2:关系特点
类与类:
继承关系,只能单继承,可以多层继承。


类与接口:
实现关系,可以单实现,也可以多实现。
还可以在继承一个类的同时,实现多个接口。


接口与接口:
继承关系,可以单继承,也可以多继承。




     3:设计理念的区别
抽象类被继承,这个类中定义的是整个继承体现的共性内容。
体现:is a  //当一个类是另外一个类的一种的时候,就使用继承.举例:狗是动物的一种.
接口被实现,这个接口中定义的是整个体现的扩展内容。
体现:like a   //当一个类像某个东西的时候,就用实现. 举例: 中国人学了英语,但是你还是中国人,只不过像老外而已.
     ====>对事物本质的抽取,用抽象类
        对事物拓展功能的抽取,用接口
11.内部类:
1.想通过外部类去访问内部类,则需要通过外部类对象去创建内部类对象,格式为:
Outer.Inner in = new Outer().new Inner();--->面试用,平时几乎用不到。


2.方法内部类如果需要访问所在方法的局部变量,则此变量必须定义为final型常量。
原因(面试用):局部变量会在方法调用完毕后,立马消失。而方法内部类中如果有地方使用着局部变量,
当方法消失后,这个方法区中的内容还没有消失(随着类还在堆内存中等待垃圾回收器回收),
也就是说这个变量还必须存在。所以,为了延长局部变量的生命周期,就需加final修饰。




常用API


1.重点问题:
A.(面试题)字符串最大特点:一旦被初始化就不可以被改变。
指的是字符串在常量池中的值不可改变,但是指向该字符串的引用是可以改变的,也就是说这个引用可以改变后指向别的字符串。
eg.     String str = "abcd";
      str+="efgh";
System.out.println(str);//输出结果为abcdefgh
解释:1."abcd"这个内容在常量池中,不可改变;2."efgh"也在常量池中开辟一个空间,也不可改变;3.再开辟一个空间,存放"abcdefgh",然后指向"abcd"的引用指向了"abcdefgh".
===>另一种类型题(面试题):
基本类型:形式参数改变不影响实际参数;
引用类型:形式参数改变直接影响实际参数。
但是,String是一种特殊的引用类型,它的形式参数的改变不影响实际参数
eg.
public class Test {
public static void main(String[] args) {
String s = "abc";
change(s);
System.out.println(s);//abc
}
public static void change(String s){
s+="hello";
System.out.println(s);//abchello
}
}
B.(面试题)
class StringDemo
{
public static void main(String[] args)
{
String s1 = "abc";//s1是一个类类型变量,"abc"是一个对象。
String s2 = new String("abc");//s1和s2有什么区别?s1在内存中有一个对象,s2在内存中有两个对象。
}
}
String str = new String("abc");和 String str ="abc";有什么区别吗?
有区别。前者在内存中有两个内存空间,后者只有一个。原因是前者创建对象在堆内存中开辟了一个空间,然后又在常量池中给"abc"开辟了一个空间,对象引用指向堆内存,堆内存指向常量池;后者只在常量池中开辟一个空间存储"abc",没有再堆内存中开辟空间。
===>与之类似的题目(面试题):常量相加会直接累加,然后在常量池里面去找有没有,如果有,就是常量池里面的值,不会再开辟新的空间存储;
 而变量则会开辟新的空间。
eg.
public class Test {
public static void main(String[] args) {
String s1 = "a";
String s2 = "b";
String s3 ="ab";
System.out.println(s3==s1+s2);//false
System.out.println(s3=="a"+"b");//true
}
}


集合:
1.ConCurrentModificationException 并发修改异常:
// 创建集合对象
List list = new ArrayList();


// 添加元素
list.add("hello");
list.add("world");
list.add("java");


// 需求:请遍历集合,判断其中是否有"hello"这个元素,如果有,就再添加一个元素:"IOS"
Iterator it = list.iterator();
while (it.hasNext()) {
String s = (String) it.next();
if ("hello".equals(s)) {
list.add("IOS");//ConCurrentModificationException 通过迭代器遍历集合时,不能通过集合去操作。
//有两个解决办法 A:ListIterator B:for
//it = list.iterator();// 这样从原理是可以解决的,但是它会引起另外一个问题。OutOfMemoryError
}
}
System.out.println("list:" + list);




解决办法:
// 完全通过集合实现
for (int x = 0; x < list.size(); x++) {
String s = (String) list.get(x);
if ("hello".equals(s)) {
list.add("IOS");
}
}
System.out.println("list:"+list);
System.out.println("-----------");


// 遍历
ListIterator lit = list.listIterator();
while (lit.hasNext()) {
String s = (String) lit.next();
if ("hello".equals(s)) {
lit.add("IOS");
}
}
System.out.println("list:" + list);