JavaGuide基础⾯试题
1. ⾯向对象和⾯向过程的区别
⾯向过程:⾯向过程的性能⽐⾯向对象是要⾼的,虽然⾯向过程也需要分配内存,计算内存偏移量,但是⾯向对象类调⽤时的实例化开销更⼤,更消耗资源。
⾯向对象:因为⾯向对象存在封装,继承,多态的特性,所以⾯向对象易扩展,易维护,易复⽤,但是性能相较于⾯向过程要低⼀些。
⽽Java性能差的根本原因是java是半编译语⾔,最终的执⾏代码不是可以直接被cpu运⾏的⼆进制机械码,⽽⼤多数⾯向过程语⾔的最终执⾏代码都是直接编译成机械码被cpu执⾏。
2. 关于jvm jdk jre的解答
JVM:
是运⾏java字节码(.class)的虚拟机,针对不同的系统存在特定的实现,⽬的是为了跨平台。
java程序从源代码(.java)到运⾏的步骤:
以前,.class–>机器码的过程中,jvm类加载器⾸先加载字节码⽂件,然后通过解释器逐⾏解释执⾏。这种⽅法执⾏速度相对缓慢,⽽且,有些⽅法和代码块是需要被经常调⽤的(热点代码)
后来,引进了JIT编译器,JIT属于运⾏时编译,当JIT编译器完成第⼀次编译后,其会将热点代码的字节码对应的机器码保存,⽤于下次直接使⽤。这种情况下,热点代码就属于编译执⾏⽽不是解释执⾏了。
JDK & JRE
jdk:包含了jre,还有编译器javac和⼯具javadoc,jdb等。
jre:java运⾏环境,它是运⾏已编译java程序所需要的所有内容的合集,包括JVM,Java类库,java命令和⼀些基础构建。
3. Java和c++的区别
java不提供指针来直接访问内存,程序内存更加安全
java只能单继承(可以多实现接⼝),c++⽀持多重继承
java由内存管理机制,c++需要⼿动释放内存
4. 字符型常量和字符串常量有什么区别
形式上:字符型常量 ‘A’ ,字符串常量 “ABC”
含义上:字符型常量相当于⼀个整形值(ASCII),可以参与表达式运算;字符串常量代表⼀个内存地址
占内存⼤⼩:字符型通常只占2个字节,字符串常量占若⼲个字节
5. 构造器是否可以被override(重写)
继承时就讲过,⽗类的私有属性和构造⽅法不能被继承,SB问题
6. 重载和重写的区别
重载:发⽣在同⼀个类中,⽅法名字必须相同,参数不同,返回值和修饰符可以不同,参考构造⽅法。
重写:发⽣在⽗⼦类中,⽅法名字,参数列表必须相同,返回值和抛出异常的范围欸必须⼩于等于⽗类,访问修饰符范围必须⼤于⽗类,如果⽗类访问修饰符为private,则⼦类不能重写该⽅法。
7. Java⾯向对象编程三⼤特性:封装继承多态
封装
封装把⼀个对象的属性私有化,同时提供⼀些可以被外界访问的属性的⽅法。
继承
继承是使⽤已存在的类(⽗类)的定义作为基础建⽴新类(⼦类)的技术,拥有⽗类对象所有的属性和⽅法(包括私有属性和私有⽅法),但是⽗类中的私有属性和⽅法⼦类是⽆法访问,只是拥有。⼦类也可以对⽗类进⾏扩展。通过使⽤继承我们能够⾮常⽅便地复⽤以前的代码。
多态
多态简单来说就是⼀个接⼝,因为使⽤不同的实例⽽执⾏不同的操作。
⽐较难理解所以通过⼀个继承实现多态的实例进⾏解释:
⽗类Employee
class Employee{
private String name;
private String addr;
private int id;
public void mailCheck(){
System.out.println("邮寄⽀票给:"+this.name +" "+this.addr);
}
public Employee(){
}
public Employee(String name, String addr,int id){
System.out.println("Employee 构造");
this.name = name;
this.addr = addr;
this.id = id;
}
public get and set ...
}
⼦类Salary 继承了 Employee,获得了Employee的所有属性和⽅法,增加了属性sal,修改了⽅法mailCheck
class Salary extends Employee {
private double sal;
public Salary(String name, String addr,int num,double sal){
super(name, addr, num);
this.sal = sal;
}
@Override
public void mailCheck(){
java接口有没有构造方法System.out.println("Sal类的mailCheck");
System.out.println("邮寄⽀票给:"+getName()+" "+ sal);
}
public get and set ...
}
执⾏Demo,实例化了两个Salary对象,⼀个使⽤Salary引⽤s,⼀个使⽤Employee引⽤e。
当调⽤s.mailCheck()时,编译器在编译时会在Salary类中寻mailCheck(),执⾏过程 JVM 就调⽤ Salary 类的 mailCheck()。
当调⽤e.mailCheck()时,编译器在编译时会在Employee类中寻mailCheck(),也就是先检查⽗类中是否存在该⽅法,如果不存在,则编译错误;如果有,则调⽤⼦类的同名⽅法。所以执⾏过程JVM 就调⽤ Salary 类的 mailCheck()。
也就是我们常说的,编译看左边,运⾏看右边
public class Demo11 {
public static void main(String[] args){
Salary s =new Salary("员⼯A","beijing",3,3600.00);
Employee e =new Salary("员⼯B","shanghai",2,2400.00);
s.mailCheck();
e.mailCheck();
}
}
执⾏结果
Employee 构造
Employee 构造
Sal类的mailCheck
邮寄⽀票给:员⼯A 3600.0
Sal类的mailCheck
邮寄⽀票给:员⼯B 2400.0
8. String StringBuffer和StringBuilder的区别是什么?String为什么是不可变的?
可变性
String类中使⽤final关键字修饰字符数组来保存字符串,private final char value[ ],所以String对象是不可变的。
⽽StringBuilder与StringBuffer都继承⾃AbstractStringBuilder类,在AbstractStringBuilder中也是使⽤字符数组保存字符串,char[ ] value,但是没有⽤final关键字修饰,所以这两种对象都是可变的。
线程安全性
String中的对象是不可变的,也就可以理解为常量,线程安全。
AbstractStringBuilder是StringBuilder与StringBuffer的公共⽗类,定义了⼀些字符串的基本操作,如
expandCapacity,append,insert,indexOf等公共⽅法。 StringBuffer对⽅法加了同步锁或者对调⽤的⽅法加了同步锁,所以是线程安全的。StringBuilder并没有对⽅法进⾏加同步锁,所以是⾮线程安全的。
性能
每次对String类型进⾏改变的时候,都会⽣成⼀个新的String对象,然后将指针指向新的String对象。
StringBuffer/Builder每次都会对其对象本⾝进⾏操作,⽽不是⽣成新的对象并改变对象引⽤。StringBuilder相⽐使⽤StringBuffer仅能获得10%~15%左右的性能提升,但却要冒多线程不安全的风险。
对于三者使⽤的总结:
操作少量的数据:适⽤String
单线程操作字符串缓冲区下操作⼤量数据:适⽤StringBuilder
多线程操作字符串缓冲区下操作⼤量数据:适⽤StringBuffer
9. 在⼀个静态⽅法内调⽤⼀个⾮静态成员为什么是⾮法的?
静态⽅法属于整个类,⽽不是某个对象,也就是被该类下的所有对象共享。静态成员可以使⽤类名直接访问,不需要实例化类来调⽤。
简单来说,把类⽐作⼀个设计图,静态⽅法或属性作为该设计图的⼀部分;把实例对象⽐作完成品。我们不能在设计图中到任何完成品的属性,因为每⼀个完成品都是不同的。
10. 在Java中定义⼀个不做事且没有参数的构造⽅法的作⽤
回想以下我们在通过类创建⼀个对象时,会通过调⽤它的构造⽅法完成创建。如果该类是某个⽗类的⼦类,还会在构造⽅法中super()隐式调⽤⽗类的⽆参构造⽅法。
且如果⽗类中只定义了特定的有参构造⽅法,没有重载⽆参构造(如果不添加构造的情况下,会默认隐式创建⼀个⽆参构造),⽽在⼦类的构造⽅法中没有⽤super()调⽤⽗类特定的构造⽅法,则编译时将发⽣错误,因为Java程序在⽗类中不到⽆参构造⽅法执⾏。
11. 接⼝和抽象类的区别
参数抽象类接⼝
默认的⽅法
实现可以有⾮抽象的⽅法实现
接⼝只定义抽象⽅法,接⼝的所有⽅法默认会隐式加上public
abstract(JDK1.8 可以在接⼝中定义静态⽅法)
实现⼦类使⽤extends关键字继承抽象类,且必须重写抽象⽗类的抽象
⽅法
⼦类使⽤关键字 implements 来实现接⼝。它需要提供接⼝中所有声
明的⽅法的实现
与普通java 类的区别抽象类不能实例化
接⼝可以实例化,但接⼝并不是⼀个类,它和类同属于java数据类型的
引⽤类型
构造器抽象类可以有构造器接⼝不是类不存在构造器
访问修饰符抽象⽅法可以有public protected default 修饰符,但不能使⽤
private,因为抽象⽅法⽬的就是为了重写
接⼝⽅法默认修饰符是 public,不可以使⽤其它修饰符
main⽅法接⼝中可以有main,所以能够运⾏抽象类接⼝没有 main ⽅法,因此不能运⾏接⼝效率⽐接
⼝效率⾼接⼝是稍微有点慢的,因为它需要时间去寻在类中实现的⽅法变量任意接⼝中所有变量必须为static final
12. 成员变量和局部变量区别
属性成员变量局部变量
语法形式成员变量属于类局部变量是在⽅法中定义的变量或⽅法的参数
访问修饰符成员变量可以被各种修饰符修饰局部变量不能被访问控制修饰符以及静态修饰,除了final
存储⽅式属于实例对象,存在于堆内存存在于栈内存
⽣存时间随对象的创建⽽存在随⽅法的调⽤⽽消失
赋值成员变量会根据其类型默认赋值局部变量不会⾃动赋值
13. 创建⼀个对象⽤什么运算符?对象实体与对象引⽤有何不同?
new运算符,new创建对象实例并存储在堆内存,对象引⽤则指向对象实例(对象引⽤存放在栈内存)
⽐较难理解所以通过实例说明:
public class Demo{
public Demo{}//默认构造
}
接下来⽤Demo类创建⼀个对象
Demo demo =new Demo();
这个类实例化语句包含了4个动作:
1. 右边的new Demo是以Demo类为模板,在堆内存中创建了⼀个Demo对象
2. 末尾的()意味着,在对象创建后,⽴即调⽤Demo类的构造函数,对刚⽣成的对象进⾏初始化
3. 左边的Demo demo创建了⼀个Demo类的引⽤变量demo,它存放在栈内存,⽤于指向Demo对象
4. "="操作符使对象引⽤指向刚创建的Demo对象的内存地址
⼀个对象引⽤可以指向0-1个对象;⼀个对象实体可以有n个引⽤指向它。
14. 什么是⽅法的返回值?返回值在⽅法中的作⽤
⽅法的返回值是我们获取到某个⽅法体中代码执⾏后产⽣的结果。
其作⽤是接收结果,使其可以⽤于其他操作
15. ⼀个类的构造⽅法作⽤?若⼀个类没有声明构造⽅法,程序能否正确执⾏?
构造⽅法主要是完成对类对象的初始化⼯作,可以参考13题中对象实体在堆内存的创建过程。
⼀个类即使没有显式声明构造⽅法也会存在默认⽆参构造⽅法。
16. 构造⽅法特性
⽆返回值
名字与类名相同
⽣成类的对象时⾃动执⾏,不需要调⽤
17. 静态⽅法和实例⽅法的区别
属性静态⽅法实体⽅法外部调⽤通过"类名.⽅法名"/“对象名.⽅法名”通过"对象名.⽅法名"
访问范围静态⽅法在访问本类成员时,只能访问静态成员实例⽅法⽆限制18. 对象的相等和指向它们的引⽤相等,两者有何不同
对象的相等,⽐较的是内存中存放的内容是否相等。
对象的引⽤相等,⽐较的是内存中的地址是否相等。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。