Java基础题的复习----第五章

题目:


1.三种集合差别,集合类都是什么,数据结构是什么,都什么时候用  
2.Map集合的主要接口:Map 、Map.Entry  、 AbstractMmap、SortedMap
3.hashset为什么要重写hashcode和equals方法?
4.treeset两种实现方式,在哪用到过,
5.红黑树原理
6.ArrayList和LinkList各自什么时候用
7.Map两种解析方式,并举例框架中的源码使用的源代码段,至少两段
8.迭代器模式,iterator在ArrayList和hashset中实现的源码段,说出设计模式及模式使用的场合
9.Collections和Collection的差别
   写出Collections五个常用方法和demo
   数组和List相互转换的方法及demo
10.说明在遍历数据库结果集时如果类似写法会出现什么问题,简单画出内存图 
ArrayList<user> al = new ArrayList<user>();
User user =new User();
for()
{
        user.setName();
        .....
        ......
        al.add(user);
}
11.线程安全的集合有哪些,线程安全的list的特点
12.泛型如何提供安全监测机制(编译期),什么是类型擦除(删除)


1.三种集合差别,集合类都是什么,数据结构是什么,都什么时候用  

1. List
List接口表示一个有序的集合,允许重复元素。每个元素都有一个索引,可以根据索引来访问元素。

常见实现类:ArrayList,LinkedList,Vector
底层数据结构:ArrayList:动态数组。
                         LinkedList:双向链表。
                         Vector:动态数组(线程安全)。

使用场景:

ArrayList:需要快速随机访问元素,插入和删除操作不频繁的场景。

List<String> arrayList = new ArrayList<>();
arrayList.add("A");
arrayList.add("B");
System.out.println(arrayList.get(0)); // 输出 "A"

LinkedList:需要频繁插入和删除操作,且不需要快速随机访问的场景。

List<String> linkedList = new LinkedList<>();
linkedList.add("A");
linkedList.add("B");
linkedList.remove(0);


Vector:与ArrayList相似,但需要线程安全的场景(不推荐使用,通常使用Collections.synchronizedList来替代)。

List<String> vector = new Vector<>();
vector.add("A");
vector.add("B");

2. Set
Set接口表示一个无序的集合,不允许重复元素。
常见实现类:HashSet,LinkedHashSet,TreeSet
底层数据结构:HashSet:哈希表。
                         LinkedHashSet:哈希表和链表(维持插入顺序)。
                         TreeSet:红黑树(有序集合)。
使用场景:

HashSet:需要快速判断元素是否存在,不关心元素顺序的场景。

Set<String> hashSet = new HashSet<>();
hashSet.add("A");
hashSet.add("B");

LinkedHashSet:需要快速判断元素是否存在,同时需要维持插入顺序的场景。

Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("A");
linkedHashSet.add("B");

TreeSet:需要有序的集合,按自然顺序或自定义比较器排序的场景。

Set<String> treeSet = new TreeSet<>();
treeSet.add("A");
treeSet.add("B"); 

3. Map
Map接口表示一个键值对的集合,每个键映射到一个值。键不能重复,但值可以重复。

常见实现类:HashMap,LinkedHashMap,TreeMap,Hashtable
底层数据结构:HashMap:哈希表。
                         LinkedHashMap:哈希表和链表(维持插入顺序)。
                         TreeMap:红黑树(按键的自然顺序或自定义比较器排序)。
                         Hashtable:哈希表(线程安全)。
使用场景:

HashMap:需要根据键快速查找值,不关心键的顺序的场景。

Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("A", 1);
hashMap.put("B", 2);

LinkedHashMap:需要根据键快速查找值,同时需要维持键的插入顺序的场景。

Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("A", 1);
linkedHashMap.put("B", 2);

TreeMap:需要根据键快速查找值,同时需要键按自然顺序或自定义比较器排序的场景。

Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("A", 1);
treeMap.put("B", 2);


Hashtable:与HashMap相似,但需要线程安全的场景(不推荐使用,通常使用Collections.synchronizedMap来替代)。

Map<String, Integer> hashtable = new Hashtable<>();
hashtable.put("A", 1);
hashtable.put("B", 2);

2.Map集合的主要接口:Map 、Map.Entry  、 AbstractMmap、SortedMap

1. Map

Map接口表示一个键值对的集合,每个键映射到一个值。键不能重复,但值可以重复。 

2. Map.Entry

Map.Entry是一个内部接口,用于表示Map中的一个键值对。Map的entrySet方法返回一个包含所有映射关系的集合,每个映射关系都是一个Map.Entry对象。

常用方法

  • getKey(): 返回与此条目对应的键。
  • getValue(): 返回与此条目对应的值。
  • setValue(V value): 用指定值替换与此条目对应的值。
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

 3. AbstractMap

  AbstractMap是一个实现了Map接口的大部分功能的抽象类,提供了Map接口的骨干实现,以减少实现此接口所需的工作量。具体的Map实现类可以继承AbstractMap并实现其抽象方法。

public class CustomMap<K, V> extends AbstractMap<K, V> {
    private final Map<K, V> map = new HashMap<>();

    @Override
    public Set<Entry<K, V>> entrySet() {
        return map.entrySet();
    }

    @Override
    public V put(K key, V value) {
        return map.put(key, value);
    }
}

 4. SortedMap

  SortedMap接口继承自Map接口,表示一个按键进行排序的Map。SortedMap中的所有键都必须实现Comparable接口,或者必须提供一个Comparator。键按其自然顺序排序,或者按映射创建时提供的Comparator排序。

常用方法

  • comparator(): 返回对此映射中的键进行排序的比较器,如果此映射使用其键的自然顺序,则返回 null
  • firstKey(): 返回此映射中当前第一个(最低)键。
  • lastKey(): 返回此映射中当前最后一个(最高)键。
  • headMap(K toKey): 返回此映射的部分视图,其键严格小于 toKey
  • tailMap(K fromKey): 返回此映射的部分视图,其键大于等于 fromKey
  • subMap(K fromKey, K toKey): 返回此映射的部分视图,其键范围从 fromKey(含)到 toKey(不含)。
SortedMap<String, Integer> sortedMap = new TreeMap<>();
sortedMap.put("C", 3);
sortedMap.put("A", 1);
sortedMap.put("B", 2);

System.out.println(sortedMap.firstKey()); // 输出 "A"
System.out.println(sortedMap.lastKey());  // 输出 "C"
System.out.println(sortedMap.subMap("A", "C")); // 输出 {A=1, B=2}


3.hashset为什么要重写hashcode和equals方法?

  在Java中,HashSet的工作原理依赖于哈希表的实现,而哈希表的运作需要依靠对象的hashCode和equals方法。为了正确地存储和检索对象,必须重写这些方法。这是因为HashSet需要保证集合中的元素唯一性,并高效地进行插入、查找和删除操作。

hashCode方法
  hashCode方法返回一个整数,该整数用于在哈希表中确定对象的存储位置。HashSet使用哈希值来快速查找对象。因此:如果两个对象被认为是相等的(通过equals方法),它们必须具有相同的哈希码。这是为了确保在比较对象时,如果它们是相等的,就会落在同一个“桶”(bucket)中,从而可以找到和检索相同的对象。
  如果对象的hashCode实现不一致(即相等的对象有不同的哈希码),那么在插入和查找时会出现问题,可能导致HashSet无法正确存储和检索对象。
equals方法
  equals方法用于确定两个对象是否相等。在HashSet中,这用于确定是否已经存在与要插入的新对象相等的对象。因此:当插入一个新对象时,HashSet首先使用hashCode方法确定对象应该存储的位置。如果在该位置上已经存在其他对象,HashSet会使用equals方法逐一比较这些对象,以确定是否已经存在一个与新对象相等的对象。
  如果没有重写equals方法,HashSet将使用Object类的默认实现,这通常是基于对象的引用(即对象的内存地址)。这意味着除非两个引用指向同一个对象,否则equals方法将返回false,即使这两个对象的内容是相同的。


4.treeset两种实现方式,在哪用到过

1. 自然排序(Natural Ordering)

自然排序是通过元素自身的Comparable接口实现的排序。集合中的元素必须实现Comparable接口,并重写compareTo方法,以定义元素的自然顺序。

package code711;

import java.util.TreeSet;

public class code12 {
    public static void main(String[] args) {
        TreeSet<Integer> treeSet = new TreeSet<>();
        treeSet.add(5);
        treeSet.add(1);
        treeSet.add(3);
        treeSet.add(2);
        treeSet.add(4);
        System.out.println("TreeSet with natural ordering: " + treeSet);
    }
}

在这个例子中,TreeSet使用了Integer类的自然顺序(从小到大)来排序元素。

如果我们有一个自定义类,例如Person,该类需要实现Comparable接口:

package code711;

import java.util.TreeSet;

public class code13 {
    public static void main(String[] args) {
        TreeSet<Person> treeSet = new TreeSet<>();
        treeSet.add(new Person("Alice", 30));
        treeSet.add(new Person("Bob", 25));
        treeSet.add(new Person("Charlie", 35));

        System.out.println("TreeSet with natural ordering: " + treeSet);
    }
}

class Person implements Comparable<Person> {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Person other) {
        return this.age - other.age; // 根据年龄进行比较
    }

    @Override
    public String toString() {
        return name + " (" + age + ")";
    }
}


2. 自定义排序(Custom Ordering)

自定义排序是通过传递一个实现了Comparator接口的比较器对象来实现的。Comparator接口提供了一个compare方法,用于定义两个对象的比较逻辑。

package code711;

import java.util.TreeSet;
import java.util.Comparator;

public class code14 {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return s2.compareTo(s1); // 按照字符串的降序排列
            }
        });

        treeSet.add("Apple");
        treeSet.add("Banana");
        treeSet.add("Cherry");
        treeSet.add("Date");
        treeSet.add("Elderberry");

        System.out.println("TreeSet with custom ordering: " + treeSet);
    }
}


在这个例子中,我们使用一个自定义的Comparator来按照字符串的降序排列TreeSet中的元素。

对于自定义类,例如Person,可以定义一个自定义的比较器来按姓名排序:

package code711;

import java.util.Comparator;
import java.util.TreeSet;

public class code15 {
    public static void main(String[] args) {
        TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                return p1.name.compareTo(p2.name); // 根据姓名进行比较
            }
        });

        treeSet.add(new Person("Alice", 30));
        treeSet.add(new Person("Bob", 25));
        treeSet.add(new Person("Charlie", 35));

        System.out.println("TreeSet with custom ordering: " + treeSet);
    }
}
    

TreeSet的这两种实现方式广泛应用于需要排序的场景中,包括但不限于以下场景:

  1. 数据处理和分析:例如在处理数据时,需要对数据进行排序,以便于查找、过滤和统计。
  2. 报表生成:生成有序的报表或日志,确保数据按特定顺序排列。
  3. 搜索和查找:在实现自定义搜索算法时,可以利用TreeSet的排序特性进行高效查找。
  4. 排队系统:在需要维护有序队列的系统中,例如优先级队列、事件调度系统等。

通过自然排序和自定义排序,TreeSet提供了灵活的方式来管理和处理有序数据。

5.红黑树原理

这个实在内容太多,已经理解,有空会写一个代码和博客。


6.ArrayList和LinkList各自什么时候用

  1. ArrayList

    • 内部实现:基于动态数组实现。
    • 优势
      • 随机访问速度快,时间复杂度为 O(1)。
      • 适合对元素的访问操作比较频繁的场景。
    • 劣势
      • 在插入和删除操作时,如果需要频繁地在中间或开头插入或删除元素,需要移动大量元素,效率较低(时间复杂度为 O(n))。

    适用场景

    • 当需要快速访问元素,而对插入和删除操作的效率要求不是特别高时,可以选择使用 ArrayList
  2. LinkedList

    • 内部实现:基于双向链表实现。
    • 优势
      • 在插入和删除操作时,不需要像 ArrayList 那样移动大量元素,时间复杂度为 O(1)。
      • 对于频繁的插入和删除操作,LinkedList 的效率要高于 ArrayList
    • 劣势
      • 随机访问元素时效率较低,需要 O(n) 的时间复杂度来获取第 n 个元素。
      • 消耗的空间相对 ArrayList 较大,因为需要存储额外的链表节点。

    适用场景

    • 当需要频繁进行插入和删除操作,而对访问操作要求不是特别高时,可以选择使用 LinkedList


7.Map两种解析方式,并举例框架中的源码使用的源代码段,至少两段

1. 通过键集(keySet)解析

通过键集解析Map的方式是首先获取Map中所有键的集合,然后遍历这个集合,对于集合中的每个键,使用Map的get方法获取对应的值。

import java.util.HashMap;  
import java.util.Map;  
import java.util.Set;  
  
public class MapExample {  
    public static void main(String[] args) {  
        Map<String, Integer> map = new HashMap<>();  
        map.put("one", 1);  
        map.put("two", 2);  
        map.put("three", 3);  
  
        // 通过键集解析  
        Set<String> keys = map.keySet();  
        for (String key : keys) {  
            Integer value = map.get(key);  
            System.out.println("Key = " + key + ", Value = " + value);  
        }  
    }  
}

2. 通过键值对集(entrySet)解析

通过键值对集解析Map的方式是首先获取Map中所有键值对的集合(entrySet),然后遍历这个集合,对于集合中的每个键值对对象,可以直接获取键和值。

 

import java.util.HashMap;  
import java.util.Map;  
import java.util.Set;  
import java.util.Map.Entry;  
  
public class MapExampleEntrySet {  
    public static void main(String[] args) {  
        Map<String, Integer> map = new HashMap<>();  
        map.put("one", 1);  
        map.put("two", 2);  
        map.put("three", 3);  
  
        // 通过键值对集解析  
        Set<Entry<String, Integer>> entries = map.entrySet();  
        for (Entry<String, Integer> entry : entries) {  
            String key = entry.getKey();  
            Integer value = entry.getValue();  
            System.out.println("Key = " + key + ", Value = " + value);  
        }  
    }  
}

总结

  • keySet解析:适用于仅需要键的场景,或者当你想对键进行进一步操作时使用。
  • entrySet解析:适用于同时需要键和值的场景,因为它直接提供了键值对对象。

 

8.迭代器模式,iterator在ArrayList和hashset中实现的源码段,说出设计模式及模式使用的场合

迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供了一种方法顺序访问一个聚合对象(如列表、集合等)中的各个元素,而又不暴露该对象的内部表示。迭代器模式使得在不暴露对象内部结构的情况下,可以遍历集合对象中的元素。

设计模式

迭代器模式 允许用户通过一种统一的方式来遍历访问集合中的元素,而无需关心集合的内部表示,或者集合是如何被构建的。这种方式简化了集合的遍历过程,并且使得集合类的接口和迭代器类的接口之间解耦。

使用场合

迭代器模式通常用于以下场合:

  1. 遍历集合:当需要遍历访问一个集合对象中的元素时,但又不想暴露该对象的内部表示时。
  2. 统一接口:当需要为不同的集合提供统一的遍历方式时。
  3. 多态性:当需要实现多态的集合操作时,比如对不同的集合类(如列表、队列、栈等)进行遍历。 

9.Collections和Collection的差别
   写出Collections五个常用方法和demo
   数组和List相互转换的方法及demo

Collections和Collection的差别

  • Collection 是一个接口,它是Java集合框架的一部分,定义了集合的基本操作,如添加、删除、清空集合等。它不能直接被实例化,只能被其实现类(如ArrayListLinkedListHashSet等)实例化。

  • Collections 是一个工具类,提供了操作或返回集合的静态方法,如排序、搜索、替换、反转等。这个类不能被实例化,因为它所有的方法都是静态的。

package code711;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class code16 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(5, 1, 4, 2, 8);
        Collections.sort(numbers);
        System.out.println(numbers);  // 输出: [1, 2, 4, 5, 8]

        List<String> words = Arrays.asList("apple", "banana", "cherry");
        Collections.reverse(words);
        System.out.println(words);  // 输出: [cherry, banana, apple]

        Collections.shuffle(numbers);
        System.out.println(numbers);  // 输出可能会不同,例如: [4, 5, 2, 1, 3]


        Integer max = Collections.max(numbers);
        System.out.println(max);  // 输出: 8

        List<String> list = new ArrayList<>();
        Collections.addAll(list, "apple", "banana", "cherry");
        System.out.println(list);  // 输出: [apple, banana, cherry]
    }
}

 

10.说明在遍历数据库结果集时如果类似写法会出现什么问题,简单画出内存图 
ArrayList<user> al = new ArrayList<user>();
User user =new User();
for()
{
        user.setName();
        .....
        ......
        al.add(user);
}

只会有一个user对象在ArraysList中,然后循环一次就在堆区中改数据。 


11.线程安全的集合有哪些,线程安全的list的特点

在Java中,有多种线程安全的集合类,它们通过内部同步机制确保在多线程环境下的数据一致性。以下是一些常见的线程安全集合:

  • Vector:这是最早的动态数组实现,其中的方法大多是同步的。但是,由于其性能较低(每次方法调用都进行同步),现在较少使用。
  • Hashtable:类似于HashMap,但它是线程安全的。同样,由于其性能问题,现在推荐使用ConcurrentHashMap
  • Collections.synchronizedList(List<T> list):可以将任何List转换为线程安全的列表。这个方法通过包装原始列表来提供同步访问。
  • CopyOnWriteArrayList:这是一个线程安全的ArrayList变体,它通过在每次修改时复制底层数组来避免并发修改异常。它适用于读多写少的场景。
  • ConcurrentHashMap:虽然不是List,但它是Map接口的一个线程安全且高效的实现,通常用于替代Hashtable
  • ConcurrentSkipListMapConcurrentSkipListSet:这些是线程安全的可排序映射和集合,基于跳表实现。

 

线程安全的List的特点
  • 同步性:线程安全的List通过内部同步机制(如锁)来确保在多线程环境下对列表的访问是互斥的,从而避免数据不一致。
  • 性能考虑:虽然线程安全的List提供了线程安全性,但它们往往比非线程安全的集合(如ArrayList)在性能上有所牺牲,特别是在高并发环境下。
  • 适用场景:线程安全的List适用于需要保证数据一致性的多线程环境。但是,在选择时需要考虑性能和适用场景,比如CopyOnWriteArrayList适用于读多写少的场景。

12.泛型如何提供安全监测机制(编译期),什么是类型擦除(删除)

泛型提供的安全监测机制(编译期)

Java泛型在编译期提供了类型安全监测机制,这意味着编译器会检查代码中对泛型的使用是否符合类型约束。例如,如果你有一个List<String>,编译器会确保你只能向这个列表中添加String类型的对象,而不能添加其他类型的对象。这种检查是在编译时进行的,有助于在代码运行之前发现并修正类型错误。

类型擦除(删除)

Java的泛型是通过类型擦除来实现的。类型擦除指的是在编译期间,Java编译器会将泛型代码中的类型参数替换为它们的限定类型(通常是Object),然后生成普通的字节码。这个过程称为类型擦除。例如,List<String>在编译后会被擦除为List<Object>(实际上是List,因为原始类型在Java中没有泛型信息)。但是,请注意,这并不意味着你可以向List<String>中添加任意类型的对象,因为Java虚拟机(JVM)在运行时会通过强制类型转换和类型检查来维护泛型约束的安全性。

类型擦除的主要目的是为了保持与Java 1.5之前版本的兼容性,因为JVM本身在引入泛型之前并不支持泛型。类型擦除也意呀着泛型信息不会保留在运行时,因此你不能在运行时检查一个集合是否包含特定类型的元素(除了通过反射和类型转换时的异常)。但是,Java提供了Class<T>和其他泛型类型信息(如TypeToken在Google Guava库中)来帮助处理与泛型相关的运行时问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值