学习篇(四)

五、集合

集合框架概述

集合框架的作用:用于操作管理一组相同类型的数据。数组结构、链表结构、二叉树结构都可以实现。数组最大的问题在于数组中的元素个数是固定的,要实现动态数组,比较麻烦,自己实现链表或是二叉树结构来管理对象更是不方便。
集合中分为三大接口:Collection、Map、Iterator。接口和类在java.util包中
 

集合框架结构图

Collection接口
Collection层次结构中的根接口。Collection表示一组对象,这些对象也成为collection的元素。一些collection允许有重复的元素,而另一些不允许。一些collection时有序的,而另一些时无序的。JDK提供更具体的子接口(Set,List)实现。此接口通常用来传递collection,并在需要最大普遍性的地方操作这些collection。
定义:public interface Collection<E>;    extendsIterable<E>
Collection接口用于存储单个对象的集合

集合框架List接口

List接口:
格式:public interface List<E> extends Collection<E>
特点:有序的collection(也称为序列)可以重复的。此接口的用户可以对列表中每个元素的插入位置进行精确的控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。允许多个null元素。具体的实现有:ArrayList,Vector,LinkedList
实际开发中的选择:
    安全性问题(Vector)
    是否频繁插入、删除(LinkedList)
    是否时存储后遍历(ArrayList)

ArrayList:
定义:public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
格式:List list = new ArrayList();    //这种方式可以存储多个数据类型的元素,在处理时会比较麻烦。通常使用List<E>(泛型)在一个集合中存储相同的类型。
特点:List接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括null在内的所有元素。除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
注意:
    实现原理是采用动态对象数组实现,默认构造方法创建了一个空数组;
    第一次添加元素,扩展容量为10,之后的扩充算法:原来数组大小+原来数组大小的一半;
    不适合进行删除或插入操作
    为了防止数组动态扩充次数过多,建议创建ArrayList时,给定初始容量
    线程不安全,适合在单线程访问时使用
Vector:
格式:public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
特点:Vector类可以实现可增长的对象数组。和数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector的大小可以根据需要增大减小,以适应创建Vector后进行添加或移除 项的操作。
注意:
    实现原理,采用动态对象数组实现,默认构造方法创建了一个大小为10的对象数组
    扩充的算法:当增量为0时,扩充为原来大小的2被,当增量大于0时,扩充为原来大小+增量
    不适合删除或插入操作。
    为了防止数组动态扩充次数过多,建议创建Vector时,给定初始容量
    线程安全,适合在多线程访问时使用,在单线程下使用效率较低
LinkedList:
格式:public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Clkoneable, Serializable
特点:List接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括null)。除了实现List接口外,LinkedList类还为在列表的开头及结尾get、remove和insert元素提供了统一的命名方法。
注意:
    实现原理:采用双向链表结构实现
    适合插入,删除操作,性能高。

集合框架Set接口

Set接口:
public interface Set<E> extends Collection<E>
一个不包含重复元素的collection。更确切地讲,set不包含满足e1.equals(e2)的元素对e1和e2,并且最多包含一个null元素。此接口模仿了数学上的set抽象。
选择:
如果要排序,选择treeSet。
如果不要排序,也不用保证顺序选择HashSet
不要排序,要保证顺序,选择LinkedHashSet

HashSet:
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable
类实现Set接口,由哈希表(实际上是一个HashMap实例)支持。不保证Set的迭代顺序;特别是不保证顺序恒久不变。此类允许使用null元素。添加元素时把元素作为HashMap的key存储,HashMap的value使用一个固定的object对象。排除重复元素时通过equals来检查对象是否相同。判断两个对象是否相同,先判断两个对象的hashCode是否相同(相同,不一定是同一个对象,但不同一定不是同一个对象),如果相同,还要进行equals判断,相同则是同一个,不同就不是;自定义对象要认为属性值都想同时为同一个对象,需要重写对象所在类的hashCode和equals方法。
hashCode(方法用于返回字符串的哈希码。

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。空字符串的哈希值为 0。)深入分析:
    hashcode()方法,在object中定义:public native int hashCode();
    hashCode是本地方法,实现是根据本地机器相关,我们可以在自己写的类中覆盖hashcode()方法。
    在java集合中,判断两个对象是否相等的规则是:
        判断两个对象的hashCode是否相等(相等也不一定时同一个对象,因为得到的是一个正整数,可能重复)
        判断两个对象用equals运算是否相等(关键)
总结:
哈希表的存储结构是:数组+链表,数组里的每个元素以链表的形式存储。
如何把对象存储到哈希表中:先计算对象的hashCode值,再对数组的长度求余数,来决定对象要存储在数组中的那个位置。
解决hashSet中的重复值使用的方式如上。

TreeSet:
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
基于TreeMap的NavigableSet实现。使用元素的自然顺序对元素进行排序,或者根据创建set时提供的Comparator进行排序,具体取决于使用的构造方法。
总结:
    有序的,需要对象所在类实现comparable接口的comparator方法或者定义比较器,对象比较器还可以去掉重复元素。,如果自定义的数据类没有实现比较器接口,将无法添加到TreeSet集合中。 

LinkedHashSet:
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable
具有可预知迭代顺序的Set接口的哈希表和链接列表实现。此实现与HashSet的不同之处在于,后者维护一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到set的顺序(插入顺序)进行迭代。注意:插入顺序不受在set中重新插入的元素的影响。(如果在s.contains(e)返回true后立即调用s.add(e),则元素e会被重新插入到set s中。)
总结:
    维护着一个运行于所有条目的双重链接列表。定义里迭代顺序,即按照插入到set中的顺序(插入顺序)进行迭代。

集合框架Iterator接口

集合输出:遍历。遍历集合的方式:Iterator、ListIterator、Enumeration、foreach。Iterator使用率最高。
Iterator<Cat> iter = c.iterator();
while(iter.hasNext()){    System.out.println(iter.next())}
Enumeration<String> es = vs.elements();
while(es.hasNext()){    System.out.println(es.next())}    // 优先使用Iterator 
ListIterator提供向前迭代。提供set方法,修改元素内容。
foreach
numbers.forEach((Integer integer) -> {System.out.println(integer);});
numbers.forEach(integer -> {System.out.println(integer);});
numbers.forEach(integer -> System.out.println(integer));
numbers.forEach(System.out::println);
numbers.forEach(new MyConsumer());
Consumer<T> 消费者接口
Function<T, R> 表示接受一个参数并产生结果的函数。
Supplier<T> 代表结果供应商
Predicate<T> 断言接口

Stream

是元素的集合,看起来类似Iterator;可以支持顺序和并行的对原Stream进行汇聚的操作。
Stream可以看作一个高级版本的Iterator。原始的Iterator,用户只能一个一个的遍历元素并对其执行某些操作;高级的Stream,用户只要给出需要对其包含的元素执行什么操作,具体这些操作如何应用到每个元素上,就是Stream的工作了。
Stream不是存储数据结构,数据源可以是一个集合,为了函数式编程创造,惰式执行,数据只能被消费一次。
两种类型的操作方法:中间操作(生成一个Stream);结束操作(执行计算操作)
方法举例:
Stream<String> stream = Stream.of();
// forEach遍历
stream.forEach(System.out::println);
// filter筛选
stream.filter((s) -> s.length() >3)
// distinct去重
stream.distinct()
// map映射
stream.map(s->s.toUpperCase())
// flatMap合并集合
Stream<List<Integer>> ss = Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5));
ss.flatMap(list->list.stream())
// reduce用于取最大值/最小值等的比较
Optional<String> opt = stream.reduce((s1,s2) -> s1.length()>=s2.length()?s1:s2)
System.out.println(opt.get())
// collect根据流生成不同的集合
List<String> list = stream.collect(Collectors.toList());
// ::方法引用  引用静态方法:Integer::valueOf    引用对象方法  list::add    引用构造方法  ArrayList::new

集合框架Map接口

Map接口
将键映射到值的对象,一个映射不能包含重复的键;每个键最多只能映射到一个值。
总结:键值对存储一组对象;Key不能重复(唯一),Value可以重复;具体的实现类:HashMap,TreeMap,Hashtable,LinkedHashMap
方法:
void clear()    清空Map集合中的内容
boolean containsKey(Object Key)    判断集合中是否存在指定的key
boolean containsValue(Object Value)    判断集合中是否存在指定的value
Set<Map.Entry<K, V>> entrySet()    将Map接口变为Set集合
V get(Object key)    根据key找到其对应的value
boolean isEmpty()    判断是否为空
Set<K> keySet()    将全部的key变为Set集合
Collection<V> values()    将全部的value变为Collection集合
V put(K key, V value)    向集合中增加内容
void putAll(Map<? extends K, ? extends V> m)    增加一组集合
V remove(Object key)    根据key删除内容

HashMap
public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable, Serializable
基于哈希表的Map接口的实现。此实现提供所有可选的映射操作,并允许使用null值和null键。(除了非同步和允许使用null之外,HashMap类和Hashtable大致相同)此类不保证映射的顺序,特别是他不保证该顺序恒久不变。
方法:
添加:.put();
取值:.get();//已知键。
    遍历:
        Set<Entry<Integer, String>> entrySet = map.entrySet();  for(Entry e : entrySet){e.getKey()+"->"+e.getValue()};  
        Set<Integer> keys = map.keySet(); for (Integer i: keys){String value = map.get(i); }
        Collection<String> values = map.values();    for(String value: values){ System.out.println(values);}
        map.forEach((key, value) -> System.out.println(key+"->"+value))
实现原理:
    基于哈希表(数组+链表+二叉树(红黑树,又叫平衡二叉树))
    默认加载因子=0.75,默认数组大小是16
    把对象存储到哈希表,过程:把key对象通过hash()方法计算hash值,然后用这个hash值对数组长度取余数(默认16),来决定该Key对象在数组中存储的位置,当这个位置有多个对象时,以链表结构存储,JDK1.8后,当链表长度大于8时,链表将转换为红黑树结构存储。
    这样的目的是为了取值时提高效率,存储的数据量越大,性能的表现越明显。
    扩充原理:当数组的容量超过了75%,那么表示该数组需要扩充,扩充方式:当前数组容量<<1(相当于乘2)扩大一倍。此时所  有对象重新排列,此操作极为损耗性能,建议不要扩充多次。
    线程不安全,适合在单线程中使用。

Hashtable
public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K,V>, Cloneable, Serializable
此类实现一个哈希表,该哈希表将键映射到相应的值。任何非null对象都可以用作键或值。为了成功的在哈希表中存储和获取对象,用作键的对象必须实现hasCode方法和equals方法。
实现原理:
    基于哈希表实现(数组+链表)
    默认数组大小为11,加载因子0.75
    扩充方式:原数组大小<<1(*2)+1
    线程安全,用在多线程访问时。

LinkedHashMap
public class LinkedHashMap<K, V> extends HashMap<K, V> implements Map<K,V>
Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。是HashMap的子类,由于HashMap不能保证顺序恒久不变,此类使用一个双重链表来维护元素添加的顺序。

TreeMap
public class TreeMap<K, V> extends AbstractMap<K, V> implements NavigableMap<K,V>, Cloneable, Serializable
基于红黑树的NavigableMap实现。该映射根据其键的自然顺序进行排序,或者根据创建映射是提供的Comparator进行排序,具体取决于使用的构造方法。

数据结构:数组、链表、二叉树(红黑树)、哈希表(数组+链表/数组+链表+红黑树)、栈、队列。

在JDK8中Map接口提供了一些新的便利的方法。因为在此提到的所有Map方法都是以默认值方法的方式实现的,所以现有的Map接口的实现可以直接拥有这些在默认值方法中定义的默认行为,而不需要新增一行代码。
getOrDefault(Object, V)  获取键对应的值,如果没有将V当作默认值返回。
putIfAbsent(K, V)  如果为空,将V映射到K上。
remove(Object key, Object value)  根据键值都匹配时才删除。
replace(K, V)  将K映射的的值替换为V
replace(K, V, V)  将K映射的值为V的值替换为V 。
compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)  将key映射的值作为参数传入函数,并将结果重新赋值
computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)  将key映射的值作为参数传入函数,并将结果重新赋值,前提是其值为空
merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)  将新值加到旧值之后,如果旧值为空,则直接等于新值。

Collections工具类

Collections类,提供了大量针对Collection/Map的操作。总体可分为四类,都是静态方法。
1、排序(主要针对List接口相关):
    reverse(List list)    反转指定List集合中的元素顺序;
    shuffle(List list)    对List中的元素进行随机排序(洗牌);
    sort(List list)    对List里的元素根据自然升序排序
    sort(List list, Comparator c)    自定义比较器进行排序
    swap(List list, int i, int j)    将指定List集合中i处元素和j处元素进行交换
    rotate(List list, int distance)    将所有元素右移位指定长度,如果distance等于size那么结果不变。
2、查找和替换(主要针对Collection接口相关)
    binarySearch(List list, Object key): 使用二分搜索法,以获得指定对象在List中的索引,前提时集合已经排序
    max(Collection coll):返回最大元素
    max(Collection coll, Comparator comp):根据自定义比较器,返回最大元素
    min(Collection coll):返回最小元素
    min(Collection coll, Comparator comp):根据自定义比较器,返回最小元素
    fill(List list, Object obj):使用指定对象填充
    frequency(Collection Object o):返回指定集合中指定对象出现的次数
    replaceAll(List list, Object old, Object new):替换 
3、同步控制
    Collections工具类中提供了多个synchronized XXX方法,该方法返回指定集合对象对应的同步对象,从而解决多线程并发访问集合时线程的安全问题。HashSet、ArrayList、HashMap都是线程不安全的,如果需要考虑瞳步,则使用这些方法。这些方法由:synchronizedSet、synchronizedSortedSet、synchronizedList、synchronizedMap、synchronizedSortedMap。
    特别需要指出的,在使用迭代方法遍历集合时需要手工同步返回的集合。
4、设置不可变的集合
    Collections有三类方法可返回一个不可变集合:
        emptyXxx()    返回一个空的不可变的集合对象
        singletonXxx()    返回一个只包含指定对象的,不可变的几何对象
        unmodifiableXxx()    返回指定集合对象的不可变视图
5、其他
    disjoint(Collection<?> c1, Collection<?> c2  如果两个指定collection中没有相同元素,返回true
    addAll(Collection<? super T> c, T... a)  一种方便的方式,将所有指定元素添加到指定collection中
    Comparator<T> reverseOrder(Comparator<T> cmp)  返回一个比较器,它强行反转指定比较器的顺序。如果制定比较器为null,则此方法等同于reverseOrder()(返回一个比较器,该比较器将清醒反转实现Comparable接口的哪些对象collection上的自然顺序)

Optional容器类
这是一个可以为null的容器对象。如果值存在则isPresent()方法返回true,调用get()方法会返回该对象。
of:为非null的值创建一个Optional
ofNullable:为制定的值创建一个Optional,如果指定值为null,则返回一个空的Optional
isPresent:如果值存在返回true,否则false
get:如果Optional有值则将其返回,否则抛出NoSuchElementException。
ifPresent:如果Optional实例有值则为其调用consumer,否则不做处理
orElse:如果优质则将其返回,否则返回指定的其他值
orElseGet:与orElse类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现来生成默认值。
orElseThrow:如果有值则将其返回,否则抛出supplier接口创建的异常
map:如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
flatMap:如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须时Optional。调用结束时,flatMap不会对结果用Optional封装
filter:如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。

Queue、Deque接口

队列(Queue)时一种特殊的线性表,是一种先进先出的数据结构。它只允许在表的前端进行删除操作,而在表的后端进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
LinkedList是Queue接口的实现类
boolean add(E e):将制定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回true,如果但钱没有可用空间,则抛出lllegalStateException。
E element():获取,但是不移除此队列的头。
boolean offer(E e):将制定的元素插入此队列,当使用有容量限制的队列是,此方法通常要优于add(E),后者可能无法插入元素而只是抛出一个异常。
E peek():获取但不移除此队列的头;如果为空,返回null
E poll():获取并一处此队列的头;如果为空,返回null
E remove():获取并移除此队列的头。

Deque:一个线性collection,支持在两端插入和移除元素。
此接口既支持有容量限制的双端队列,也支持没有固定大小限制的双端队列。
接口定义在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。

对象一对多与多对多关系

可以用集合来表示实际开发中对象的一对多关系和多对多关系。

迭代器设计模式

提供一个方法按顺序遍历一个集合内的元素,而又不需要暴露该对象的内部表示
应用场景:访问一个聚合的对象,而不需要暴露对象的内部表示;支持对聚合对象的多种遍历;对遍历不同的对象,提供统一的接口。
迭代器模式的角色构成:
迭代器角色(Iterator):定义遍历元素所需要的方法,一般来说会有三个:取得下一个元素的方法next(),判断是否遍历结束的方法hasNext(),移出当前对象的方法remove()。
具体迭代器角色(Concrete Iterator):实现迭代器接口中定义的方法,完成集合的迭代。
容器角色(Aggregate):一般是一个接口,提供一个iterator()方法,例如Collection接口,List接口,Set接口等。
具体容器角色(ConcreteAggregate):就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkedList,Set接口的哈希列表实现HashSet等。

guava对集合的支持

Guava工程包含了若干被Google的Java项目广泛依赖的核心库,例如:集合collections、缓存caching、原生类型支持primitives support、并发库concurrency libraries、通用注解common annotations、字符串处理string processing、I/O等等。所有这些工具每天都在被Google的工程师应用在产品服务中
Guava对JDK集合的扩展,这是Guava最成熟和为人所知的部分。
1、不可变集合:用不变的集合进行防御性编程和性能提升
2、新集合类型:multisets,multimaps,tables等
3、强大的集合工具类:提供java.util.Collections中没有的集合工具
4、扩展工具类:让实现和扩展集合类变得更容易,比如创建Collection的装饰器,或实现迭代器。

使用:
1、只读设置:Arrays.asList("", "", "", ...);创建固定长度的集合;Collection.unmodifiableList(list); 将已有的list/Set等集合转换为只读的;ImmutableList.of(); Guava中设置只读的。
2、函数式编程:过滤器。Lists.newArrayList(); 创建List。Collections2.filter(list, (e) -> e.startsWith("j")); 过滤返回一个Collection
3、函数式编程:转换。Collection2.transform(timeSet, (e) -> new SimpleDateFormat("yyyy-MM-dd").format(e)); 转换,返回一个Collection
4、组合式函数编程。Functions.compose(f1, f2);将两个Function合并为一个。然后通过转换实现。
5、加入约束:非空、长度验证。checkArgument  checkNotNull
6、集合操作:交集、差集、并集。Sets.intersection(set1, set2);  交集;Sets.difference(set1, set2);  差集;Sets.union(set1, set2)  并集
7、Multiset:无序可重复。HashMultiset.create();返回一个HashMultiset对象。HashMultiset.elementSet();返回无序可重复Set。
8、Multimap:key可以重复。ArrayListMultimap.create();返回一个Multimap对象。 一个键对应多个值。
9、BiMap:双向Map(bidirectionalMap)键与值不能重复。HashBiMap.create();返回一个双向Map。
10、双键的Map-->Table-->rowKey+columnKey+value。HashBasedTable.create();返回一个双键的Map 

六、网络编程

网络编程基本概念

计算机网络:把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息,共享硬件、软件、数据信息等资源。
主要功能:资源共享、信息传输与集中处理、均衡负荷与分布处理、综合信息服务等。
网络通信协议:要使计算机练成的网络能够互通信息,需要对数据传输速率、传输代码、代码结构、传输控制步骤、出错控制等制定一组标准,这一组共同遵守的通信标准就是网络通信协议,不同的计算机之间必须使用相同的通讯协议才能进行通信。
网络通信接口:为了使两个结点之间能进行对话,必须在它们之间建立通信工具(即接口),使彼此之间能进行信息交换。接口包括两部分:硬件装置:实现节点之间的信息传送;软件装置:规定双反进行通信的约定协议。

TCP/IP协议:传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互连网络的基础,简单地说嘛就是由网络层的IP协议的传输层的TCP协议组成的。
IP地址:网络中每台计算机的一个标识号。
端口号:端口号范围在0到65535之间,0到1023之间的端口数是用于一些知名的网络服务和应用。
层级:应用层-表示层-会话层-传输层-网络层-数据链路层-物理层。

程序开发结构
网络编程主要是指完成C/S程序的开发,程序的开发结构有两种:
C/S(客户端/服务器):开发两套程序,两套程序需要同时维护;
B/S(浏览器/服务器):开发一套程序,客户端使用浏览器进行访问。BS程序一版稳定性较差,畏怯安全性较差。
CS程序主要可以完成:TCP(传输控制协议,采用三方握手的方式,保证准确的连接操作)、UDP(数据报协议,发送数据报)两种程序的开发。
TCP、UDP的数据帧格式:
协议类型|源IP|目标IP|源端口|目标端口|帧序号|帧数据
其中协议类型用于区分TCP、UDP

网络编程TCP协议

TCP程序概述:TCP是一个可靠的协议,面向连接的协议。实现TCP程序,需要编写服务器端和客户端,JavaAPI为我们提供了java.net包,为实现网络应用程序提供类。
ServerSocket:此类实现服务器套接字。
Socket:此类实现客户端套接字。
Socket是网络驱动层提供给应用程序变成的接口和一种机制。
数据发送过程:
    应用程序产生Socket;
    应用程序调用bind将Socket的信息通知给驱动程序;
    应用程序将要发送的数据传送给Socket;
    驱动程序从Socket去除数据并通过网卡发送出去。
数据接收过程:
    应用程序产生Socket;
    应用程序调用bind将Socket的信息通知给驱动程序;
    驱动程序根据从网卡传送来的数据报中的指定目标端口号,将处理后的数据传送到相应的Socket中;
    应用程序从Socket中取数据。
实现服务器端与客户端程序
    服务器端:public class ServerSocket extends Object此类实现服务器套接字。服务器套接字等带请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
    使用:
        ServerSocket(int port);    创建绑定到特定端口的服务器套接字
        void setSoTimeout(int timeout);    通过指定超时值启用/禁用SO_TIMEOUT,以毫秒为单位
        InetAddress getInetAddress();    返回此服务器套接字的本地地址
        Socket accept();    侦听并接收此套接字的连接
    客户端:public class Socket extends Object此类实现客户端套接字。套接字是两台机器间通信的端点。
    使用:
        Scoket(String host, int port);    创建一个流套接字并将其连接到指定主机上的指定端口号
        InputStream getInputStream();    返回此套接字的输入流
        OutputStream getOutputStream();    返回此套接字的输出流
        void setSoTimeout(int timeout);    通过指定超时值启用/禁用SO_TIMEOUT,以毫秒为单位
ECHO,应答,程序的功能是客户端向服务器发送一个字符串,服务器不做任何处理,直接把字符串返回给客户端,Echo程序是最基本的CS程序。

TCP实现ECHO程序

服务器与多客户端通信:将每一个连接的客户端都创建一个新的线程对象。ExecutorService的实现类Executors的execute方法,传入的参数为处理方式。。

多客户端之间的通信:客户端的数据包通过服务器中转,发送到另一个客户端。需要定义信息类,属性包括:发送者;接收者;消息类型;消息内容等。

网络编程UDP协议

User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立地信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的,每个被传输的数据报必须限定在64KB之内。主要使用:DatagramPacket表示数据报包;DatagramSocket表示用来发送和接收数据报包的套接字。

URL

uniform resource location类,URL代表一个统一资源定位符,它是指向互联网资源的指针。
URLConnection是所有类的超类,它代表应用程序和URL之间的通信连接。

MINA框架

一个简洁易用的基于TCP/IP通信的JAVA框架。
开发一个Mina应用:创建连接,设定过滤规则,编写自己的消息处理器。

七、反射与内省

反射

Reflection:由对象去调用类信息。

Class类

是一切反射的根源。将类的信息进行一个抽象就是Class。
得到Class类的对象有三种方式:Object类中的getClass()方法;类.class;通过Class类的forName方法。
使用得到的Class类对象来实例化对象:默认使用无参构造方法,因此类需要保留无参构造方法;getConstructors()方法返回所有的构造方法,getConstructor()获取指定的构造器。newInstance()方法创建对象。getFields()方法获取所有的非私有属性。getDeclaredFields()方法获取所有属性(包括私有属性)。针对获取到的属性,getModifiers()得到访问权限修饰符的数字表示,Modifier.toString(modifiers)可以将数字转为对应的字符串表示,getName()方法得到属性名。

通过Class类取得类信息

取得类所在的包:
    public Package getPackage();  得到一个类所在的包
    public String getName();    得到名字
取得一个类中的全部方法:
    public Method[] getMethods();  获取包括父类在内的所有公有方法。getDeclareMethods()获取本类的所有方法(虽然获取到,但是私有方法不能被调用,想要调用私有方法需要.setAccessible(true)去除访问修饰符检查)。
    public int getModifiers() //获取访问权限修饰符 Modifier.toString(mod)还原修饰符
    public Class<?> getReturnType()  获取返回类型
    public Class<?>[] getParameterTypes()
    public Class<?>[] getExceptionTypes()
    public static String toString(int mod)
区的一个类中的所有属性
    public Field[] getFields()
    public Field[] getDeclaredFields()
    public Class<?> getType()
    public int getModifiers()
    public String getName()

通过Class类调用属性和方法

调用类中的方法,传入实例化对象,以及具体的参数内容。
public Object invoke(Object obj, Object ... args)
直接调用属性:
public Objcet get(Object obj)
public void set(Object obj, Object value) 设置属性,扽沟通与使用"="
public void setAccessible(boolean flag) 让属性对外部可见。

动态代理

动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期实现动态关联。
java动态代理主要是使用java.lang.reflect包中的两个类。
InvocationHandler类
public Object invoke(Object obj, Method method, Object[] obs)
第一个参数obj指的是代理类,method是被代理的方法,obs是指被代理的方法的参数组。此方法由代理类来实现。
Proxy类
protected Proxy(InvocationHandler h);
static Class getProxy(ClassLoader loader, Class[] interfaces);
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h);
动态代理其实是在运行时生成class,所以,我们必须提供一组interface,然后告诉他class已经实现了这些interface,而且在生成Proxy的时候,必须给他提供一个handler,让他来接管实际工作。

类加载器原理分析与实现
类的加载过程:JVM将类加载过程分为三个步骤:装载(Load)、链接(Link)和初始化(Initialize)。链接又分为验证、准备、解析三个步骤。
装载:查找并加载类的二进制数据。
链接:验证:确保被加载类的正确性;
          准备:为类的静态变量分配内存,并将其初始化为默认值;
          解析:把类中的付号引用转换为直接引用
初始化:为类的静态变量赋予正确的初始值
类的初始化时间:
    创建类的实例,也就是new一个对象;
    访问某个类或接口的静态变量,或者对该静态变量赋值;
    调用类的静态方法;
    反射(ClassforName("com.vince.Dog"))
    初始化一个类的子类(会首先初始化子类的父类)
    JVM启动时表明的启动类,即文件名和类名相同的那个类
类的加载:指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的Java.lang.Class对象,用来封装类在方法区类的对象。

JavaBean的概念

Bean理解为组件的意思,也就是Java组件,广泛的理解就是一个类,对于组件来说,关键在于要具有“能够被IDE构建工具侦测其属性和时间”的能力,通常在Java中。
一个JavaBean要具备的命名规则:
    对于一个名为xxx的属性,通常要写两个方法:getXxx()和setXxx()。任何浏览这些方法的工具,都会把get/set后面的第一个字母自动转换为小写。
    对于布尔型属性,可以使用以上get和set地方式,不过也可以把get替换成is。
    Bean的普通方法不必遵循以上命名规则,不过必须是public的
    对于时间,要使用Swing中处理监听器的方式。(addWindowListener,removeWindowListener) 

BeanUtils是Apache开发的一种工具,可以帮我们把属性封装到javabean对象的对应属性中(.setProperty(类实例对象, 属性名, 属性值))。封装时要求参数名称和javabean的属性名相同。

内省

Introspector。是Java语言对Bean类属性、时间的一种缺省处理方法。例如A类中由属性name,那么可以通过getName, setName来得到他的值或者设置他的值。通过getName/setName来访问属性,这就是默认的规则。
Java中提供了一套API来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解规则,这些API存放于包java.beans中,一般的做法是通过类Introspector的getBeanInfo方法来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述其就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。

Introspector相关API
Introspector:此类为通过工具学习有关受目标JavaBean支持的属性、事件和方法的知识提供了一个标准方法。
static BeanInfo getBeanInfo(Class<?> beanClass)  在JavaBean上进行内省,了解其所有属性、公开的方法和事件。
BeanInfo类:此类实现此Bean Info接口并提供有关其bean的方法、属性、事件等显式信息。
MethodDescriptor[] getMethodDescriptors() 获得beans MethodDescriptor。
PropertyDescriptor[] getPropertyDescriptors()  获得beans PropertyDescriptor。
Properties属性文件工具类的使用。
PropertyDescriptor类:描述JavaBean通过一对存储器方法导出的一个属性。
Method getReadMethod()  获得应该用于读取属性值的方法
Method getWriteMethod()  获得应该用于写入属性值的方法
MethodDescriptor类:描述了一种特殊方法,即JavaBean支持从其他组件对其进行外部访问。
Method getMethod()  获得此Method Descriptor封装的方法 

示例:
    首先要有一个配置文件,内容包括类的路径,类中属性的名-值的键值对。操作过程:
    使用静态代码块读取配置文件,Thread.currentThread().getContextClassLoader().getResouceAsStream(配置文件路径)将配置文件导入流中;Properties().load(流)读取流内容;使用getProperty(属性名)获取到配置文件中的类的路径;使用Class.forName(路径)得到类;使用.newInstance()创建类对象(BeanInfo类对象);通过getPropertyDescriptors()获取所有的属性描述器;对所有属性描述器进行遍历,getName()获取属性名,getWriteMethod()获取set方法,获取到的set方法使用.invoke()方法进行调用。

AOP:Aspect Oriented Programming(面向切面编程)。
使用场景:封装横切关注点:
    权限、缓存、错误处理、调试、记录跟踪、持久化、同步、事物等

单例模式优化

使用同步保证线程按权synchronized
使用volatile关键字,volatile提醒编译器它后边定义的变量随时都有可能改变,因此变异后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。
防止反射调用私有构造方法  如果不为空抛出异常。 
让单例类序列化安全 implements Serializable

八、正则

用单个字符来描述、匹配一系列符合某个句法规则的字符串

九、枚举

让某个类型的变量取值只能为若干个固定值中的一个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值