基本数据类型
Java中有8种基本数据类型:
6种数字类型:
4种整数型:byte、short、int、long
2种浮点型:float、double
1种字符类型:char
1种布尔类型:boolean
数据类型的默认值以及所占空间如下:
注意:
-
Java里使用long类型的数据一定要在数值后面加上L,否则作为整数解析。
讲一下Java面向对象的特点
封装、继承、多态是Java面向对象编程的三大特点。
-
封装(Encapsulation):封装是面向对象编程的基本特点之一,它将数据和方法封装在对象内部,隐藏对象的内部实现细节,只暴露必要的接口供外部访问。通过封装,可以实现信息的隐藏和保护,提高代码的安全性和可靠性。
-
继承(Inheritance):继承是面向对象编程的重要特点,它允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以重用父类的代码,并可以通过扩展和重写来增加新的功能或修改现有功能。继承提高了代码的复用性和可维护性,同时也体现了类与类之间的关系。
-
多态(Polymorphism):多态是面向对象编程的核心概念之一,多态是指同一个方法名可以在不同的类中有不同的实现,不同的子类可以重写父类的方法,通过父类引用指向子类对象时,根据实际对象的类型来确定调用哪个方法。多态性提高了代码的灵活性和扩展性,使得程序更易于理解和维护。
用过“多态”吗?举一个具体例子
一个具体的例子是,假设有一个动物类(Animal)和它的两个子类:狗类(Dog)和猫类(Cat)。它们都有一个名为“makeSound”的方法,但是每种动物发出的声音是不同的。
class Animal { public void makeSound() { System.out.println("Some sound"); } } class Dog extends Animal { public void makeSound() { System.out.println("Woof"); } } class Cat extends Animal { public void makeSound() { System.out.println("Meow"); } } public class PolymorphismExample { public static void main(String[] args) { Animal dog = new Dog(); Animal cat = new Cat(); dog.makeSound(); // 输出:Woof cat.makeSound(); // 输出:Meow } }
通过多态性,可以创建一个Animal类型的引用指向一个具体的Dog或Cat对象。当调用这个引用的“makeSound”方法时,根据实际指向的对象类型,会执行相应子类的方法,从而实现不同动物发出不同声音的效果。这样就体现了多态的特性,同一个方法调用可以产生不同的行为,提高了代码的灵活性和可扩展性。
多态和重载有什么关系?
重载是一种编译时多态,而多态是一种运行时多态。两者都是实现多态性的方式,但发生的时间点和机制不同。
-
重载是指在同一个类中,方法名相同但参数列表不同的情况,通过参数个数、类型或顺序的不同来区分不同的方法。重载是静态绑定的概念,编译器在编译期间根据方法的参数列表来确定调用哪个方法。
-
多态是指同一个方法名可以在不同的类中有不同的实现,不同的子类可以重写父类的方法,通过父类引用指向子类对象时,根据实际对象的类型来确定调用哪个方法。多态是动态绑定的概念,运行时根据对象的实际类型来确定调用哪个方法。
Java中的异常
当程序出现异常时,Java会抛出一个异常对象。Java中的异常可以分为三类:
-
Checked Exception(受检异常):这种异常在编译时就可以被检测出来,必须要在代码中进行处理或者声明抛出,否则编译不通过。这类异常主要是由程序的外部环境引起的,例如文件不存在、网络连接失败等。常见的Checked Exception包括IOException、SQLException等。
-
Unchecked Exception(非受检异常):这种异常通常是由程序内部错误引起的,例如NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException等。这类异常不需要在代码中声明抛出,也可以不进行处理,但是如果不进行处理,程序会崩溃。
-
Error:这种异常通常是由JVM或者硬件引起的,例如OutOfMemoryError、StackOverflowError等。这类异常也不需要在代码中声明抛出,也可以不进行处理,但是如果不进行处理,程序也会崩溃。
在Java中,异常处理通常包括try-catch语句和throw语句。try-catch语句可以捕获异常并进行处理,而throw语句可以手动抛出异常。
String,StringBuilder, StringBuffer区别?单线程大量操作字符串用哪个?
回答:单线程大量操作字符串时应该使用StringBuilder,而在多线程环境下应该使用StringBuffer
补充:
String、StringBuilder和StringBuffer都是Java中用于操作字符串的类。
String是不可变的字符序列,每次对String进行修改时都会创建一个新的String对象,因此在大量操作字符串时,使用String会频繁地创建对象,导致性能较低。
StringBuilder和StringBuffer都是可变的字符序列,可以对其进行多次修改而不创建新的对象。两者的区别在于线程安全性,StringBuffer是线程安全的,而StringBuilder是非线程安全的。因为StringBuffer的所有共有方法都是同步的,所以在多线程环境下使用StringBuffer可以保证线程安全,但是会降低性能。而StringBuilder没有同步方法,所以在单线程环境下使用StringBuilder性能更高。
因此,在单线程环境下进行大量的字符串操作时,应该使用StringBuilder,可以获得更好的性能。在多线程环境下,使用StringBuffer可以保证线程安全,但是会牺牲一定的性能。
综上所述,单线程大量操作字符串时应该使用StringBuilder,而在多线程环境下应该使用StringBuffer。
NIO核心组件
NIO 主要包括以下三个核心组件:
-
Buffer(缓冲区):在传统的 BIO 中,数据的读写是面向流的, 分为字节流和字符流。
在 Java 1.4 的 NIO 库中,所有数据都是用缓冲区处理的,这是新库和之前的 BIO 的一个重要区别,有点类似于 BIO 中的缓冲流。NIO 在读取数据时,它是直接读到缓冲区中的。在写入数据时,写入到缓冲区中。 使用 NIO 在读写数据时,都是通过缓冲区进行操作。
-
Channel(通道):Channel 是一个通道,它建立了与数据源(如文件、网络套接字等)之间的连接。我们可以利用它来读取和写入数据,就像打开了一条自来水管,让数据在 Channel 中自由流动。
BIO 中的流是单向的,分为各种
InputStream
(输入流)和OutputStream
(输出流),数据只是在一个方向上传输。通道与流的不同之处在于通道是双向的,它可以用于读、写或者同时用于读写。Channel 与前面介绍的 Buffer 打交道,读操作的时候将 Channel 中的数据填充到 Buffer 中,而写操作时将 Buffer 中的数据写入到 Channel 中。
-
Selector(选择器):是 NIO 中的一个关键组件,它允许一个线程处理多个 Channel。Selector 是基于事件驱动的 I/O 多路复用模型,主要运作原理是:通过 Selector 注册通道的事件,Selector 会不断地轮询注册在其上的 Channel。当事件发生时,比如:某个 Channel 上面有新的 TCP 连接接入、读和写事件,这个 Channel 就处于就绪状态,会被 Selector 轮询出来。Selector 会将相关的 Channel 加入到就绪集合中。通过 SelectionKey 可以获取就绪 Channel 的集合,然后对这些就绪的 Channel 进行响应的 I/O 操作。