题1:如何理解 final 关键字?
1)类的final变量和普通变量有什么区别?
当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。
2)被final修饰的引用变量指向的对象内容可变吗?
引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的
3)final参数的问题
在实际应用中,我们除了可以用final修饰成员变量、成员方法、类,还可以修饰参数、若某个参数被final修饰了,则代表了该参数是不可改变的。如果在方法中我们修改了该参数,则编译器会提示你:
The final local variable i cannot be assigned. It must be blank and not using a compound assignment。
java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响。
题2:为什么 String 类型是被 final 修饰的?
1、为了实现字符串池
final修饰符的作用:final可以修饰类,方法和变量,并且被修饰的类或方法,被final修饰的类不能被继承,即它不能拥有自己的子类,被final修饰的方法不能被重写, final修饰的变量,无论是类属性、对象属性、形参还是局部变量,都需要进行初始化操作。
String为什么要被final修饰主要是为了”安全性“和”效率“的原因。
final修饰的String类型,代表了String不可被继承,final修饰的char[]代表了被存储的数据不可更改性。虽然final修饰的不可变,但仅仅是引用地址不可变,并不代表了数组本身不会改变。
为什么保证String不可变呢?
因为只有字符串是不可变,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现,反之变量改变它的值,那么其它指向这个值的变量值也会随之改变。
如果字符串是可变,会引起很严重的安全问题。如数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接或在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则改变字符串指向的对象值,将造成安全漏洞。
2、为了线程安全
因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
3、为了实现String可创建HashCode不可变性
因为字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算。使得字符串很适合作为Map键值对中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。
题3:接口(interface)和抽象类(abstract class)有什么区别?
默认方法
抽象类可以有默认的方法实现;而接口类在JDK1.8之前版本,不存在方法的实现。
实现方式
抽象类子类使用extends关键字来继承抽象类,如果子类不是抽象类,子类需要提供抽象类中所声明方法的实现;而接口类子类使用implements来实现接口,需要提供接口中所有声明的实现。
构造器
抽象类中可以有构造器;而接口中不能有构造器。
和正常类区别
抽象类不能被实例化;而接口是完全不同的类型。
访问修饰符
抽象类中抽象方法可以有public、protected、default等修饰;而接口类默认是public,不能使用其他修饰符。
多继承
抽象类一个子类只能存在一个父类;而接口类一个子类可以存在多个接口。
添加新方法
抽象类中添加新方法,可以提供默认的实现,因此可以不修改子类现有的代码;而接口类中添加新方法,则子类中需要实现该方法。
题4:面向过程与面向对象有什么区别?
面向过程
性能相比面向对象高,因其类调用时需要实例化,开销比较大,消耗资源,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
面向对象
易维护、复用以及扩展,由于面向对象有封装、继承、多态性等特征,可以设计出低耦合、高内聚的系统,使得更加灵活,易于维护。
题5:Java 编程语言有哪些特点?
1)简单易学;
2)面向对象(封装,继承,多态);
3)平台无关性(Java虚拟机实现平台无关性);
4)可靠性;
5)安全性;
6)支持多线程;
7)支持网络编程并方便易用;
8)编译与解释并存。
题6:重载和重写有什么区别?
重载(Overload) 是指让类以统一的方式处理不同类型数据的一种手段,实质表现就是多个具有不同的参数个数或者不同类型的同名函数,存在于同一个类中,返回值类型不同,是一个类中多态性的一种表现。
调用方法时通过传递不同参数个数和参数类型来决定具体使用哪个方法的多态性。
重写(Override) 是指父类与子类之间的多态性,实质就是对父类的函数进行重新定义。
如果子类中定义某方法与其父类有相同的名称和参数则该方法被重写,需注意的是子类函数的访问修饰权限不能低于父类的。
如果子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法,如需父类中原有的方法则可使用super关键字。
题7:静态方法和实例方法有什么不同?
静态方法和实例方法的区别主要体现在两个方面:
其一在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式而实例方法只能试用后面这种方式。也就是说,调用静态方法可以无需创建对象进行实例化。
其二静态方法在访问本类的成员时,只允许访问静态成员也就是静态成员变量和静态方法,而不允许访问实例成员变量和实例方法,实例方法是没有这个限制的。
题8:== 和 equals 两者有什么区别?
使用==比较
用于对比基本数据类型的变量,是直接比较存储的 “值”是否相等;
用于对比引用类型的变量,是比较的所指向的对象地址。
使用equals比较
equals方法不能用于对比基本数据类型的变量;
如果没对Object中equals方法进行重写,则是比较的引用类型变量所指向的对象地址,反之则比较的是内容。
题9:Integer 和 int 两者有什么区别?
Integer是int的包装类,默认值是null;int是基本数据类型,默认值是0;
Integer变量必须实例化后才能使用;int变量不需要;
Integer实际是对象的引用,指向此new的Integer对象;int是直接存储数据值。
分析总结
1)Integer与new Integer不相等。new出来的对象被存放在堆,而非new的Integer常量则在常量池,两者内存地址不同,因此判断是false。
2)两个值都是非new Integer,如果值在-128,127区间,则是true,反之为false。
这是因为java在编译Integer i2 = 128时,被翻译成:
Integer i2 = Integer.valueOf(128);
而valueOf()函数会对-128到127之间的数进行缓存。
3)两个都是new Integer,两者判断为false,内存地址不同。
4)int和Integer对比不管是否new对象,两者判断都是true,因为会把Integer自动拆箱为int再去比。
题10:什么是 Java 内部类?
内部类是指把A类定义在另一个B类的内部。
例如:把类User定义在类Role中,类User就被称为内部类。
class Role {
class User {
}
}
1、内部类的访问规则
1)可以直接访问外部类的成员,包括私有
2)外部类要想访问内部类成员,必须创建对象
2、内部类的分类
1)成员内部类
2)局部内部类
3)静态内部类
4)匿名内部类