zoukankan      html  css  js  c++  java
  • 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使用场景梳理

  • 相关阅读:
    c# 进程间同步实现
    mysql 中文支持
    堆排序算法详解
    CodeSmith 使用
    东软C#编程规范
    红伞各版key 申请和下载
    sql 添加删除字段
    第一个Hibernate 程序终于测试通过了
    C#下载大文件并实现断点续传
    Ms rdlc 打印
  • 原文地址:https://www.cnblogs.com/lao-liang/p/5128262.html
Copyright © 2011-2022 走看看