1. 什么是泛型 ?与 T 的区别
泛型是 Java 编程语言中的一个强大特性,它提供了编译时范例安全查抄机制,允许在定义类、接口和方法时使用范例参数。这些范例参数在使用时会被具体的范例所替代,从而实当代码的复用和范例安全。泛型的实现基于范例擦除机制,在编译时,泛型范例信息会被擦除,替换为原始范例。
比方,定义一个泛型类 Box<T>:
java
- public class Box<T> {
- private T item;
- public void setItem(T item) {
- this.item = item;
- }
- public T getItem() {
- return item;
- }
- }
复制代码
在使用时,可以指定具体的范例,如 Box<Integer> 或 Box<String>。
T 是泛型范例参数的一个常用命名约定,它代表 “Type”,表示未知的范例。在 Java 中,你可以使用任意合法的标识符作为范例参数名,但通常遵照一些约定,如 T 用于一样平常的范例,E 用于聚集元素范例,K 和 V 用于键值对。
- 编译时范例查抄:泛型在编译时进行范例查抄,确保代码的范例安全性,制止了运行时的 ClassCastException。
- 代码复用:通过泛型,可以编写通用的代码,淘汰重复代码的编写。
- 范例参数命名:T 只是一个常用的范例参数名,你可以根据须要使用其他合法的标识符。
- 泛型通配符:Java 提供了通配符 ? 来表示未知范例,分为上界通配符 ? extends T 和下界通配符 ? super T。上界通配符用于限制泛型范例的上限,下界通配符用于限制泛型范例的下限。
- 泛型方法:除了泛型类,还可以定义泛型方法。泛型方法可以在普通类中定义,也可以在泛型类中定义。
- 泛型接口:可以定义泛型接口,实现该接口的类须要指定具体的范例参数。
2. 什么是罗列范例,字节码层面理解 Enum
在 Java 中,罗列范例(enum)是一种特殊的类。从字节码层面看,罗列范例在编译后会被转换为一个继承自 java.lang.Enum 的类。每个罗列常量都是该类的一个静态最终实例,并且会在类加载时被初始化。
比方,以下罗列范例:
java
- public enum Color {
- RED, GREEN, BLUE;
- }
复制代码
编译后,Color 会变成一个类,其中 RED、GREEN 和 BLUE 是该类的静态最终实例。编译器会为罗列范例天生一些额外的方法,如 values() 用于返回所有罗列常量的数组,valueOf() 用于根据名称获取罗列常量。
- 继承自 java.lang.Enum:罗列范例在字节码层面是一个普通的类,继承自 java.lang.Enum。
- 静态最终实例:罗列常量是该类的静态最终实例,在类加载时被初始化。
- 额外方法:编译器会为罗列范例天生一些额外的方法,方便使用。
- 罗列属性和方法:罗列范例可以有本身的属性和方法,并且可以实现接口。通过为罗列常量添加属性和方法,可以实现更复杂的逻辑。
- switch 语句中的罗列:在 switch 语句中使用罗列范例可以进步代码的可读性和安全性。
3. 什么是值传递与引用传递,有什么区别
- 值传递:在 Java 中,根本数据范例(如 int、double 等)的参数传递是值传递。当调用方法时,会将实际参数的值复制一份传递给方法的形式参数,方法内部对形式参数的修改不会影响实际参数的值。
- 引用传递:对象范例的参数传递实际上也是值传递,但传递的是对象的引用(内存地址)。当调用方法时,会将对象的引用复制一份传递给方法的形式参数,方法内部可以通过这个引用修改对象的状态,但不能改变引用本身的值(即不能让引用指向另一个对象)。
- 值传递:传递的是实际参数的值的副本,方法内部对形式参数的修改不会影响实际参数。
- 引用传递:传递的是对象引用的副本,方法内部可以通过引用修改对象的状态,但不能改变引用本身。
- Java 只有值传递:Java 中只有值传递,没有真正意义上的引用传递。
- 理解值传递和引用传递的紧张性:理解值传递和引用传递对于处理方法参数和对象状态的修改非常紧张,特殊是在处理复杂的对象和数据布局时。
- 制止不测的副作用:在编写方法时,要明确方法是否会修改传入的对象状态,以制止不测的副作用。
4. 什么是字节流 字符流,有什么区别
- 字节流:以字节为单元进行数据的读写操作,主要用于处理二进制数据,如图片、音频、视频等。Java 中的字节流类都继承自 InputStream 和 OutputStream,如 FileInputStream 和 FileOutputStream。
- 字符流:以字符为单元进行数据的读写操作,主要用于处理文本数据。Java 中的字符流类都继承自 Reader 和 Writer,如 FileReader 和 FileWriter。
- 数据处理单元:字节流处理的是字节数据,适用于任何范例的数据;字符流处理的是字符数据,适用于文本数据。
- 字符编码息争码:字符流在读写时会进行字符编码息争码操作,而字节流不会。
- 读写效率:字符流的读写效率通常比字节流高,由于它一次可以处理多个字节构成的字符。
- 使用场景:在处理文本文件时,建议使用字符流,以制止字符编码问题;在处理二进制文件时,必须使用字节流。
- 字节流和字符流的转换:可以使用 InputStreamReader 和 OutputStreamWriter 进行字节流和字符流的转换。
5. 什么是静态内部类 匿名类,有什么区别
- 静态内部类:是定义在另一个类内部的类,使用 static 修饰。静态内部类不依赖于外部类的实例,可以直接创建对象。它只能访问外部类的静态成员。
- 匿名类:是一种没有显式名称的类,通常用于创建一个实现了某个接口或继承了某个类的对象。匿名类在创建时会立刻实例化,并且只能使用一次。
- 类名和使用次数:静态内部类有本身的类名,可以在多个地方使用;匿名类没有类名,只能使用一次。
- 成员变量和方法:静态内部类可以有本身的成员变量和方法;匿名类通常只重写接口或父类的方法。
- 外部类实例依赖:静态内部类不依赖于外部类的实例;匿名类可以访问外部类的成员变量和方法(如果是局部匿名类,访问外部局部变量时,该变量必须是 final 或 effectively final 的)。
- 静态内部类的使用场景:静态内部类可以用于封装一些与外部类相关的功能,进步代码的可读性和可维护性。
- 匿名类的使用场景:匿名类常用于变乱处理、回调函数等场景,简化代码的编写。
6. 什么是 hashtable 和 hashmap,有什么区别
- Hashtable:是 Java 早期的哈希表实现,它继承自 Dictionary 类,并且是线程安全的。Hashtable 使用哈希算法来存储和查找键值对,通过键的哈希码来确定存储位置。
- HashMap:是 Java 1.2 引入的哈希表实现,它继承自 AbstractMap 类,不是线程安全的。HashMap 同样使用哈希算法来存储和查找键值对,当发生哈希冲突时,HashMap 使用链表或红黑树(Java 8 及以后)来处理。
- 线程安全性:Hashtable 是线程安全的,而 HashMap 不是。因此,在多线程环境下,如果须要保证线程安全,可以使用 Hashtable 或 ConcurrentHashMap;在单线程环境下,建议使用 HashMap,由于它的性能更高。
- null 值处理:Hashtable 的键和值都不允许为 null,而 HashMap 的键和值都允许为 null。
- 迭代器:Hashtable 的迭代器是 Enumeration,而 HashMap 的迭代器是 Iterator。
- HashMap 的优化:在 Java 8 中,HashMap 进行了优化,引入了红黑树来处理哈希冲突,当链表长度高出一定阈值时,会将链表转换为红黑树,进步了查找效率。
- 使用建议:在单线程环境下,优先使用 HashMap;在多线程环境下,如果对线程安全要求不高,可以使用 Collections.synchronizedMap() 方法将 HashMap 转换为线程安全的映射;如果对并发性能要求较高,建议使用 ConcurrentHashMap。
7. 什么是匿名类
匿名类是一种没有显式名称的类,它是在创建对象的同时定义的。匿名类通常用于创建一个实现了某个接口或继承了某个类的对象,并且只能使用一次。
比方,以下是一个实现了 Runnable 接口的匿名类:
java
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- System.out.println("Running in anonymous class");
- }
- };
复制代码
- 无类名和一次性使用:匿名类没有类名,只能使用一次。
- 实现接口或继承类:匿名类可以实现接口或继承类,并重写其中的方法。
- 访问外部类成员:匿名类可以访问外部类的成员变量和方法(如果是局部匿名类,访问外部局部变量时,该变量必须是 final 或 effectively final 的)。
- 使用场景:匿名类常用于变乱处理、回调函数等场景,简化代码的编写。
- Lambda 表达式替代:在 Java 8 及以后的版本中,Lambda 表达式可以替代部分匿名类的使用,使代码更加轻便。
8. 什么是 Hashtable
Hashtable 是 Java 早期的哈希表实现,它继承自 Dictionary 类,并且是线程安全的。Hashtable 使用哈希算法来存储和查找键值对,通过键的哈希码来确定存储位置。当发生哈希冲突时,Hashtable 使用链表来处理。
- 线程安全性:Hashtable 是线程安全的,它的所有方法都是同步的,因此在多线程环境下可以保证数据的一致性。
- null 值处理:Hashtable 的键和值都不允许为 null,如果尝试插入 null 键或 null 值,会抛出 NullPointerException。
- 迭代器:Hashtable 的迭代器是 Enumeration,它不支持快速失败机制。
- 性能开销:由于 Hashtable 的所有方法都是同步的,在单线程环境下会有较大的性能开销,因此在单线程环境下建议使用 HashMap。
- 替代方案:在多线程环境下,如果须要更高的并发性能,可以使用 ConcurrentHashMap。
9. 什么是 ConcurrentHashMap
ConcurrentHashMap 是 Java 1.5 引入的线程安全的哈希表实现,它继承自 AbstractMap 类。ConcurrentHashMap 在多线程环境下提供了高效的并发访问,它接纳了分段锁(Java 7 及从前)或 CAS(Compare-And-Swap,Java 8 及以后)和 synchronized 相联合的机制来实现线程安全。
- 线程安全性和并发性能:ConcurrentHashMap 是线程安全的,并且在多线程环境下具有较高的并发性能。
- null 值处理:ConcurrentHashMap 的键和值都不允许为 null。
- 弱一致性迭代器:ConcurrentHashMap 的迭代器是弱一致性的,即迭代器在遍历过程中可能会反映出其他线程对映射所做的修改。
- Java 8 优化:在 Java 8 中,ConcurrentHashMap 进行了庞大优化,放弃了分段锁机制,接纳了 CAS 和 synchronized 相联合的方式,进一步进步了并发性能。
- 使用场景:ConcurrentHashMap 适用于多线程环境下的读写操作频仍的场景,如缓存、计数器等。
10. 什么是 HashMap
HashMap 是 Java 1.2 引入的哈希表实现,它继承自 AbstractMap 类,不是线程安全的。HashMap 使用哈希算法来存储和查找键值对,通过键的哈希码来确定存储位置。当发生哈希冲突时,HashMap 使用链表或红黑树(Java 8 及以后)来处理。
- 非线程安全和高性能:HashMap 不是线程安全的,在单线程环境下性能较高。
- null 值处理:HashMap 的键和值都允许为 null。
- 快速失败迭代器:HashMap 的迭代器是快速失败的,即当在迭代过程中发现映射被其他线程修改时,会抛出 ConcurrentModificationException。
- Java 8 优化:在 Java 8 中,HashMap 引入了红黑树来处理哈希冲突,当链表长度高出一定阈值(默认为 8)时,会将链表转换为红黑树,进步了查找效率。
- 使用建议:在单线程环境下,优先使用 HashMap;在多线程环境下,如果须要线程安全,可以使用 ConcurrentHashMap 或 Collections.synchronizedMap() 方法将 HashMap 转换为线程安全的映射。
友谊提示:本文已经整理成文档,可以到如下链接免积分下载阅读
https://download.csdn.net/download/ylfhpy/90496302
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |