Java面试中的一些基础知识点
¶面向对象与面向过程
-
面向过程:性能更高,不需要实例化,开销小,资源消耗小。
-
面向对象:易于维护、高复用性和高扩展性。
❗️ 注意 ❗️:Java性能差并不是因为它是面向对象的语言,而是因为它是半编译语言,最终的代码并不是直接被CPU执行的机器码。
¶Java语言特性
- 面向对象
- 封装:将类的属性特征隐藏在类的内部,不允许外部程序直接访问(private),而是提供对应的方法(setter/getter)进行操作和访问。
- 继承:子类继承父类全部的属性和方法(构造方法除外,构造方法在子类中第一行隐含调用super()),提高代码的复用性,多继承使用接口来实现。
- 多态:在操作不同对象时会产生不同的结果。
- 实现多态的方式有两种,一种是编译时多态,通过方法的重载实现的,另外一种是运行时多态,通过方法的重写实现的。
- 运行时多态存在的三个必要条件是继承、重写以及父类引用指向子类对象。
- 平台无关性–“一次编写,到处运行(Write Once,Run AnyWhere)”
- 运行在各种不同平台的JVM,可以载入和执行同一种存储格式的文件:字节码文件,这保证了Java的平台无关性。
- 可靠性和安全性
- Java舍弃了指针对存储器地址的直接操作,程序运行时,内存由虚拟机解释器分配,避免病毒通过指针侵入系统,也避免了指针操作中易产生的错误。Java还对程序提供了安全管理器,防止程序的非法访问。
- 支持多线程
- 支持网络编程
¶Java与C++区别
- Java是解释型语言,先编译成为字节码再被解释器解释成机器码,C++为编译型语言,一次编译链接形成机器码
- Java中不提供指针的操作
- Java中只有单继承,C++中存在多继承
- Java中有自动内存管理机制,C++需要自己管理内存
- Java字符串中没有结束符的概念,C++中有‘\0’作为结束符
- Java里面一切都是对象,是对象的话,字符串就有长度,既然有长度,编译器就可以确定要输出的字符个数,当然也就没有必要去浪费那1字节的空间用以标明字符串的结束了。
- java和c通信的时候,由于c中的char中有结束符,所以当java收到C发来的字符串时要将空字符处理掉,调用java字符串的trim()方法,该方法会将字符串前后的空字符读去掉。
¶字符型常量和字符串常量区别
-
字符型常量实际上是一个整型值(ASCII),字符串常量实际上是一个地址值(代表字符串在内存中的位置)。
-
字符型常量char占两字节,字符串常量占若干字节。
-
Java中基本类型的存储空间大小如下:
¶String、StringBuffer 和 StringBuilder
- String中对象不可变,指向常量池中一个字符串常量,当其值改变时,会生成一个新的String对象,然后指向该新的对象。
- StringBuffer 和 StringBuilder继承自父类AbstractStringBuilder,其中定义了字符串的一些基本操作,如expandCapacity、append、insert、indexOf等。
- StringBuffer对方法进行了加锁,所以是线程安全的,StringBuilder是非线程安全的。
- 使用情况:
- 操作少量数据:String
- 单线程操作大量数据:StringBuilder
- 多线程操作大量数据:StringBuffer
¶==与equals()
- ==判断两个对象的地址是否相等,即判断两个对象是不是同一个对象。基本数据类型中比较的是值,引用数据类型中比较的是内存地址。
- equals方法用于比较两个对象,当该类没有复写此方法时等同于==,当该类复写了该方法,将会使用复写的equals进行比较,例如,String中的equals方法就被重写过,用于比较两个字符串的值。
¶hashCode()与equals()
-
HashSet检查重复元素
当向HashSet中加入新的对象时,HashSet会先计算对象的hashcode值来判断对象加入的位置,如果该hashcode不存在,则该对象没有出现过,如果发现该hashcode存在,则调用equals()方法检查hashcode值相等的对象是否真的相同。如果真的相同,则不会加入该对象,如果不同就会重新散列。这种方式大大减少了equals的次数,提高执行速度。
-
hashCode()与equals()
- 如果两个对象相等,那么hashcode一定相等,调用equals方法返回true;
- 如果两个对象的hashcode值相等,它们也不一定相等;
- 如果equals方法被覆盖过,那么hashcode方法一定也要被覆盖过。
¶final、static、this、super关键字
¶final
- final修饰变量时,如果是基本数据类型,则其值在初始化之后不能更改;如果是引用类型的变量,则在初始化之后便不能再让其指向另外一个对象。
- final修饰方法的原因有两个:
- 将该方法锁定,避免子类中对其进行修改
- 早期java版本中final方法转为内嵌调用,用于提升效率,类中所有的private方法都可看做隐式的final
- final修饰一个类时,这个类不能被继承,且其中所有的成员方法都会被隐式的指定为final方法。
¶static
- 修饰成员变量和成员方法: 被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享,可以并且建议通过类名调用。被static 声明的成员变量属于静态成员变量,静态变量 存放在 Java 内存区域的方法区。调用格式:
类名.静态变量名
类名.静态方法名()
- 静态代码块: 静态代码块定义在类中方法外, 静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。 该类不管创建多少对象,静态代码块只执行一次.
- 静态内部类(static修饰类的话只能修饰内部类): 静态内部类与非静态内部类之间存在一个最大的区别: 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:1. 它的创建是不需要依赖外围类的创建。2. 它不能使用任何外围类的非static成员变量和方法。
- 静态导包(用来导入类中的静态资源,1.5之后的新特性): 格式为:
import static
这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法。
¶this
- this关键字用于引用当前类的实例
¶super
- 用于从子类访问父类的变量和方法
- 在构造器中使用
super()
调用父类中的其他构造方法时,该语句必须处于构造器的首行,否则编译器会报错。另外,this 调用本类中的其他构造方法时,也要放在首行。 - this、super不能用在static方法中
¶异常
- Java中所有的异常都继承于Throwable类,其中两个重要的子类:Exception和Error。
- Exception是程序本身可以处理的异常。其中一个重要的子类为RuntimeException,由JVM抛出。
- Error是程序无法处理的错误,表示运行程序中较严重的错误。
- 异常和错误的区别在于:异常能被程序本身处理,错误是无法处理。
- 异常的处理:
- try:用于捕获异常,其后跟零个或多个catch块,如果没有catch块必须跟一个finally块。
- catch:用于处理捕获到的异常。
- finally:无论是否捕获或处理异常,finally中的代码都会执行。如果try和catch中有return,finally中的语句会在返回前被执行。
- finally中不被执行的情况:
- finally中第一句异常;
- 前面的代码使用了System.exit(int)退出了程序;
- 程序所在线程死亡;
- 关闭了CPU。