JAVA笔记05 - Go语言中文社区

JAVA笔记05


道德三皇五帝,功名夏后商周。
五霸七雄闹春秋,秦汉兴亡过手。
青史几行名姓,北邙无数荒丘。
前人田地后人收,说甚龙争虎斗

集合框架

在这里插入图片描述
从上面的集合框架图可以看到,Java集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection接口又有3种子类型,List、Set和Queue,再下面是一些抽象类,最后是具体实现类,常用的有ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap等等。

从Collection接口开始讲起

Collection接口是处理对象集合的根接口,其中定义了很多对元素进行操作的方法,AbstractCollection是提供Collection部分实现的抽象类。

在这里插入图片描述
Collection接口结构

常用的方法有:add()添加一个元素到集合中,addAll()将制定集合中的所有元素添加到集合中,contains()方法检测集合中是否包含指定的元素,toArray()方法返回一个表示集合的数组。
Collections是一个类,容器的工具类,就如同Arrays是数组的工具类

Collection是 Set List Queue和 Deque的接口
Queue: 先进先出队列
Deque: 双向链表

注:Collection和Map之间没有关系,Collection是放一个一个对象的,Map 是放键值对的
注:Deque 继承 Queue,间接的继承了 Collection
在这里插入图片描述

Collection的三个子接口

List

它可以定义一个允许重复的有序集合,从List接口中的方法来看,List接口主要是增加了面向位置的操作,允许在指定位置上操作元素,同时增加了一个能够双向遍历线性表的新列表迭代器ListIterator。AbstractList类提供了List接口的部分实现。AbstractSequentialList扩展自AbstractList,主要是提供对链表的支持。下面介绍List接口的两个重要的具体实现类,也是我们可能最常用的类,ArrayList和LinkedList。

最常用的集合框架ArrayList

  • 内部数据结构
//用来存放数据元素的数组
transient Object[] elementData;
//当前存储元素的个数
private int size;
  • 添加指定元素
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  //扩容处理
    elementData[size++] = e;//添加元素
    return true;
}

//此方法主要是确定将要创建的数组大小。
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

//确定了添加元素后的大小之后将元素复制到新数组中
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容后的容量增加一半
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
       newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}
  • 移除指定元素
public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}
    
private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0) // 删除某个元素时需要移动其它数组元素
        System.arraycopy(elementData, index+1, elementData, index, numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

  • 容器类遍历的方法
    • 如果没有使用泛型,建议使用迭代器进行遍历
    Iterator iterator = h.iterator();
            while (iterator.hasNext()){
                System.out.println(iterator.next());
            }
    
    • 如果使用了泛型,可以使用增强型for循环或者for循环进行遍历

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。
java hero.name="garen"; hero1.name="ketty"; ArrayList<Hero> heroArrayList = new ArrayList<>(); heroArrayList.add(hero); heroArrayList.add(hero1); for (Hero hh : heroArrayList) { System.out.println(hh.name); } for (int i = 0; i < heroArrayList.size(); i++) { System.out.println(heroArrayList.get(i).name); }

LinkedList

LinkedList同样实现了List接口,LinkedList还实现了双向链表结构Deque
可以很方便的在头尾插入删除数据.

  • 源码赏析
    transient关键字 总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
    -数据结构
    //存储的元素个数
    transient int size = 0;
    //头节点
    transient Node<E> first;
    //尾节点
    transient Node<E> last;
    
    • 添加元素
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    
    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);//有趣
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
    
    • 删除元素
    E unlink(Node<E> x) {
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;
    
        if (prev == null) {// 当前节点为头节点,重置头节点
            first = next;
        } else {//当前节点非头节点,将前驱节点和后继节点连接
            prev.next = next;
            x.prev = null;
        }
    
        if (next == null) {//当前节点为尾节点,重置尾节点
            last = prev;
        } else {// 当前节点非尾节点
            next.prev = prev;
            x.next = null;
        }
    
        x.item = null;
        size--;
        modCount++;
        return element;
    }
    

List接口的常用方法

名称 作用
add 增加一个元素
contains 是否存在一个元素
get 根据下表获取值
indexOf 获取对象所处的位置
remove 删除
set 替换
size 获取大小
toArray 转换为数组
addAll 把另一个容器的对象都加入进来
clear 清空容器

Map

对于Map而言,key是唯一的,不可以重复的。

HashMap

安利一篇关于jdk1.8的HashMap详解
HashMap原理:使用数组加链表加红黑树,如果链表长度大于8,则将链表自动转换为红黑树结构,关于红黑树的原理精讲,暂且存着
进行键值映射
HashMap和HashSet都是无序的,具体顺序和JVM有关系

  • 和HashTabe的区别
    HashMap可以存放null
    HashTable不能存放null
    HasoMap不是线程安全类

常用方法

 HashMap<String,Integer>map = new HashMap<>();
map.put("lihouhua",18);
map.keySet()//获取所有的key
map.values()//获取所有的values
map.get(str)
map.putAll(map)
map.clear();

HashSet

原理,依赖HashMap函数,所有插入的元素作为键,值为final PRESENT
这也是没有重复元素的原因

  • LinkedList和TreeSet
    HashSet无序
    LinkedHashSet按照插入顺序,及不重复又有顺序,天然去重
    TreeSet从小到大排序
  • 常用的方法
    add addall remove

Hashcode原理

所有的对象都有一个对应的hashcode,但并不是说所有的hashcode值肯定不一样,具体原理为hashcode本身是一个native方法
对于hashcode函数来说,有些JVM在实现时是直接返回对象的存储地址,但是大多时候并不是这样,只能说可能存储地址有一定关联。下面是HotSpot JVM中生成hash散列值的实现:
 该实现位于hotspot/src/share/vm/runtime/synchronizer.cpp文件下。

static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ;
  if (hashCode == 0) {
     // This form uses an unguarded global Park-Miller RNG,
     // so it's possible for two threads to race and generate the same RNG.
     // On MP system we'll have lots of RW access to a global, so the
     // mechanism induces lots of coherency traffic.
     value = os::random() ;
  } else
  if (hashCode == 1) {
     // This variation has the property of being stable (idempotent)
     // between STW operations.  This can be useful in some of the 1-0
     // synchronization schemes.
     intptr_t addrBits = intptr_t(obj) >> 3 ;
     value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
  } else
  if (hashCode == 2) {
     value = 1 ;            // for sensitivity testing
  } else
  if (hashCode == 3) {
     value = ++GVars.hcSequence ;
  } else
  if (hashCode == 4) {
     value = intptr_t(obj) ;
  } else {
     // Marsaglia's xor-shift scheme with thread-specific state
     // This is probably the best overall implementation -- we'll
     // likely make this the default in future releases.
     unsigned t = Self->_hashStateX ;
     t ^= (t << 11) ;
     Self->_hashStateX = Self->_hashStateY ;
     Self->_hashStateY = Self->_hashStateZ ;
     Self->_hashStateZ = Self->_hashStateW ;
     unsigned v = Self->_hashStateW ;
     v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
     Self->_hashStateW = v ;
     value = v ;
  }
 
  value &= markOopDesc::hash_mask;
  if (value == 0) value = 0xBAD ;
  assert (value != markOopDesc::no_hash, "invariant") ;
  TEVENT (hashCode: GENERATE) ;
  return value;
}

对于使用到hashcode才能成立的数据结构,我们在使用equals函数之后,如果对于一个使用到hashcode的方法来说的话,我们同时需要对hashcode函数进行重写,不然相关函数会返回Null。
hashcode文章详解

collections类

clolections类是colllections对应的工具类,常用的类方法有

方法 简介
reverse 反转
shuffle 混淆,顺序乱掉
sort 排序
swap 交换
rotate 滚动
synchronizedList 线程安全化,把非线程安全的类转化为线程安全类

泛型

意义

泛型的用法是在容器后面添加Type可以是类,抽象类,接口,泛型表示这种容器,只能存放APHero,ADHero就放不进去了。
可以在一定程度上保证安全。

通配符参数

一般来说? extends Hero作为参数,而不需要直接初始化,
常用的来说,我们传入一个苹果类可以用 ? extends Fruitl

lambada表达式

代替方法参数的表达式,从匿名类转化过来,匿名类
假设一个情景: 找出满足条件的Hero
本教程将从使用普通方法,匿名类,以及Lambda这几种方式,逐渐的引入Lambda的概念

普通方法:
public static int filter(ArrayList<Hero>heroes ){
        int count = 0;
        Iterator iterator = heroes.iterator();
        for (int i = 0; i < heroes.size(); i++) {
            if (heroes.get(i).hp>50){
                count++;
            }
        }
        return count;
    }
 匿名类:
 首先继承接口,之后实现匿名方法
 Hero_count hero_count = new Hero_count() {
            @Override
            public boolean hero_count(Hero hero) {
                if (hero.hp>50)return true;
                return false;
            }
        };
之后调用匿名类
    private static int filter(ArrayList<Hero> arrayList, Hero_count hero_count) {
        int count=0;
        for (Hero h :
                arrayList) {
            if (hero_count.hero_count(h))count++;
        }
        return count;
    }
Lambda的使用:---一种匿名方法
调用方式相同,传入的参数不同
传入的参数为h->h.hp>50
Hero_count c = h->h.hp>50
    private static int filter(ArrayList<Hero> arrayList, Hero_count hero_count) {
        int count=0;
        for (Hero h :
                arrayList) {
            if (hero_count.hero_count(h))count++;
        }
        return count;
    }

网络编程

基本概念

  • IP:IP地址的作用就是标识一台在网络中的主机。
    127.0.0.1表示this也就是本地主机
  • 端口 对应相应服务
  • 对应异常是UnknowHostException

方法

  • 获取本机IP地址
InetAddress host = InetAddress.getLocalHost();
String ip = host.getHostAddress();

如何执行ping命令

Process p = Runtime.getRuntime().exec("ping "+"192。168.2.106");
BufferedReader br - new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_39760343/article/details/103567457
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢