• Java基础知识


    1、介绍一下java的集合类?分别适合什么场景?

    2、简述hashtable的get和put函数的实现。

    3、举例final的使用场景?

    4、简述public、private、protected的作用域。

    5、简述接口与抽象类的区别。

    6、简述java的序列化与反序列化的原理。

    7、用java serversocket编写一个服务器向客户端发送 “hello“,编写客户端接收数据并打印出来。

    -----------------------------------------------------------------------------------------------------------------------

    如果你能快速回答上述问题,以下的就不用看了。

    ----------------------------------------------------------------------------------------------------------------------- 

    1、介绍一下java的集合类?分别适合什么场景?

      Java集合类有两类,一是Collection,二是Map,两个都是接口。其中Collection迭代器Iterable接口,所以Collection集合对象都有foreach特性。Collection有Set、List、Queue接口,Map有HashMap、Hashtable、SortedMap、WeakHashMap、IdentityHashMap、EnumMap。

    Collection
        Set                   // 接口。注意:为Set集合里的元素实现equals(Object)方法;对Set的构造函数,传入的Collection不能包含重复的元素
            HashSet           // 存入元素时,HashSet会调用对象的hashCode()方法来得到对象的hashCode值,再根据HashCode决定该对象在HashSet中的存储位置
                LinkedHashSet // 用链表维护元素的次序
            SortedSet         // 接口。此接口主要用于排序操作
                TreeSet       // 确保集合元素处于排序状态
            EnumSet
        List                  // 接口。表示有序、可重复的集合
            ArrayList
            Vector            // 老SDK中的集合对象,跟ArrayList差不多
                Stack
            LinkedList    
    Queue // 接口。队列 PriorityQueue // 优先队列,每次取出的是具有最高优先权的元素 Deque // 双端队列 ArrayDeque // 一个基于数组的双端队列 LinkedList
    Map                       // Map的key不允许重复
        HashMap               // 不保证key-value对的顺序。非线程安全,允许null key, null value
            LinkedHashMap     // 使用双向链表来维护key-value对的次序
        Hashtable             // 古老的Map实现类。线程安全,不允许null key, null value
            Properties        // 可以把Map对象和属性文件关联起来
        SortedMap             // 接口
            TreeMap           // 红黑树数据结构,保证所有的key-value对处于有序状态
        WeakHashMap           // 保留对实际对象的弱引用
        IdentityHashMap       // 当两个key严格相等(key1 == key2)时,IdentityHashMap才认为两个key相等
        EnumMap               // 所有key都必须是单个枚举类的枚举值
    • TreeSet支持两种排序方式: 自然排序、定制排序,因为它必须实现Comparable接口。
    • HashSet、TreeSet、EnumSet都是非线程安全,不过可以通过以下方式解决:
    SortedSet sortedSet = Collections.synchronizedSortedSet(new TreeSet(...));
    • List就是一个"线性表接口",ArrayList基于数组、LinkedList基于链表是线性表的两种典型实现。ArrayList通过ensureCapacity(int minCapacity)增加数组长度,从而减少重新分配的次数,提供性能。trimToSize()调整Object[]数组长度为当前元素的个数,减少ArrayList集合对象占用的内存空间。Stack保证了后进先出,LinkedList同时表现出了双端队列、栈的用法。PriorityQueue支持的排序和TreeSet一致。Deque代表了双端队列。
    • HashMap和Hashtable的差异见注释。TreeMap通常比HashMap、Hashtable要慢,因为TreeMap底层采用红黑树来管理key-value对。使用TreeMap的一个好处是:TreeMap中的key-value对总是处于有序状态,无须专门进行排序操作。
    2、简述hashtable的get和put函数的实现

      Hashtable的get() 获取key对应的value,没有就返回null;put() 对外提供接口,让Hashtable对象可以通过put()将“key-value”添加到Hashtable中。

    get()原理:

    • 首先通过key的hashCode计算索引
    • 通过key对应的Entry链表找出哈希值、键值和key都相等的元素
    public synchronized V get(Object key) {
        Entry tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return e.value;
            }
        }
        return null;
    }

    put()原理:

    • 若Hashtable中已存在键为key的键值对, 则用新的value替换旧的value
    • 若Hashtable中不存在键为key的键值对,将修改统计数modCount+1
    • 若Hashtable实际容量 > 阈值, 则调整Hashtable的大小
    • 将Hashtable中index位置的Entry链表保存
    • 创建新的Entry节点,并将新的Entry插入Hashtable的index位置,并设置新的Entry的下一个元素
    • 将Hashtable的实际容量+1
    public synchronized V put(K key, V value) {
        // Hashtable中不允许null value
        if (value == null) {
            throw new NullPointerException();
        }
    
        Entry tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                V old = e.value;
                e.value = value;
                return old;
            }
        }
    
        modCount++;
        if (count >= threshold) {
            // Rehash the table if the threshold is exceeded
            rehash();
    
            tab = table;
            index = (hash & 0x7FFFFFFF) % tab.length;
        }
    
        Entry<K,V> e = tab[index];
        tab[index] = new Entry<K,V>(hash, key, value, e);
        count++;
        return null;
    }
    3、举例final的使用场景

      final关键字用于修饰类时表示该类不允许被继承,修饰方法时表示该方法在派生类里不允许被覆写(override),修饰变量时(静态变量、实例成员变量、形式参数和局部变量)表示该变量的值不可变。

    • final保证只被赋值一次
    • 可以让匿名类直接进行引用
    • JVM可以对final变量的使用进行优化(且不用考虑线程间可见性等问题)
    4、简述public、private、protected的作用域
    作用域 当前类 同一package 子类 其它package
    public
    protected ×
    private × × ×
    5、简述接口与抽象类的区别

      在抽象类中可以有自己的数据成员,也可以有非抽象的成员方法;而在接口中,只能有静态的不能被修改的数据成员(static final类 型),所有的成员方法默认都是共有、抽象的。 《Effective Java》告诉我们,接口优于抽象类:

    • 现有的类易于更新,以实现新的接口
    • 接口是定义混合类型的理想选择
    • 接口允许我们构造非层次结构的类型框架
    6、简述java的序列化与反序列化的原理

      把对象转换为字节流的过程称为对象的序列化,相反的过程叫反序列化。Java中,实现Serializable或者Externalizable接口的类才能被序列化。其中Externalizable接口继承 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而实现Serializable接口的类可以采用默认的序列化方式。

    对象序列化步骤:

    • 创建一个对象输出流
    • 通过对象输出流的writeObject()方法写对象

    对象反序列化步骤:

    • 创建一个对象输入流
    • 通过对象输入流的readObject()方法读取对象
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeInt(25);
    }
    
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        int age = in.readInt();
    }
    7、用java serversocket编写一个服务器向客户端发送 “hello“,编写客户端接收数据并打印出来

    服务端:

    public class SocketServer {
        public static void main(String args[]) {
            try {
                // 1、指定服务器端的端口号
                ServerSocket serverSocket = new ServerSocket(7777);
                while (true) {
                    // 2、建立连接
                    Socket socket = serverSocket.accept();
                    // 3、打开输出流
                    OutputStream outputStream = socket.getOutputStream();
                    // 4、封装输出流
                    DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
                    // 5、向客户端发送数据
                    dataOutputStream.writeUTF("hello");
                    // 6、关闭打开的输出流
                    dataOutputStream.close();
                    // 7、关闭打开的socket对象
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    客户端:

    public class SocketClient {
        public static void main(String args[]) {
            try {
                // 1、创建本地socket对象
                Socket socket = new Socket("127.0.0.1", 7777);
                // 2、打开输入流
                InputStream inputStream = socket.getInputStream();
                // 3、封装输入流
                DataInputStream dataInputStream = new DataInputStream(inputStream);
                // 4、打印服务器端发送过来hello
                System.out.println(dataInputStream.readUTF());
                // 5、关闭输入流
                dataInputStream.close();
                // 6、关闭打开的socket对象
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    参考:

    Java集合类: Set、List、Map、Queue使用场景梳理

  • 相关阅读:
    CQUOJ 10819 MUH and House of Cards
    CQUOJ 9920 Ladder
    CQUOJ 9906 Little Girl and Maximum XOR
    CQUOJ 10672 Kolya and Tandem Repeat
    CQUOJ 9711 Primes on Interval
    指针试水
    Another test
    Test
    二分图匹配的重要概念以及匈牙利算法
    二分图最大匹配
  • 原文地址:https://www.cnblogs.com/lao-liang/p/5128262.html
Copyright © 2020-2023  润新知