Java 泛型

泛型 泛型意味着更好的类型安全性。主要目的是支持类型安全性的集合,让问题尽可能在编译阶段就能捉到。 泛型定义在类声明中 public class ArrayLiat<E> extends AbstractLìst<E> implements List<E> { public boolean add (E o); } E代表用来创建赋予初始ArrayList的类型 ArrayList<String> list = new ArrayList<String>; 编译器会自动把E看做String. 泛型方法 使用未定义在类声明的类型参数: 在返回类型之前指定泛型 maxKey: 返回给定ArrayMap中所有keys的最大值(仅在key可以比较的情况下)。假如这样写public static K maxKey(Map61B<K, V> map) { ... }会报错. 要将方法声明为泛型,必须在返回类型前面指定正式的类型参数 public static <K extends Comparable<K>, V> K maxKey(Map61B<K, V> map) { List<K> keylist = map.keys(); K largest = map.get(0); for (K k: keylist) { if (k.compareTo(largest)) { largest = k; } } return largest; } K extends Comparable<K> 保证了keys必须实现Comparable接口(也是一个generic接口), 并可以与其他K进行比较。 ...

2017-05-29 · 2 min · Cong Chan

Java 迭代 Iteration

Java提供了 foreach (enhanced for) 的循环简写语法: ArrayMap<String, Integer> am = new ArrayMap<String, Integer>(); for (String s : am) { System.out.println(s); } 实现的关键原理是使用Iterable接口使一个类变成可迭代的: 该接口包含一个iterator()方法用于返回一个Iterator对象。Iterator接口定义Iterator对象和hasNext(), next()方法来进行实际的迭代操作。 public class ArrayMap<K, V> implements Map61B<K, V>, Iterable<K> { private K[] keys; private V[] values; int size; public ArrayMap() { keys = (K[]) new Object[100]; values = (V[]) new Object[100]; size = 0; } @Override public Iterator<T> iterator() { return new KeyIterator(); } public class KeyIterator implements Iterator<K> { private int ptr; public KeyIterator() { ptr = 0; } public boolean hasNext() { return (ptr != size); } public K next() { K returnItem = keys[ptr]; ptr = ptr + 1; return returnItem; } } } 不同的数据结构,Iterator有不同的实现方式. ...

2017-05-29 · 1 min · Cong Chan

Java 高阶函数和回调

Higher Order Functions A higher order function is a function that treats other functions as data. 在 Java 7 及之前的版本, memory boxes (variables) 不能包含指向 functions 的 pointers, 也就是无法给 functions 指定 types. 所以不能像Python一样直接把 function 作为参数传递到另一个 function 中。只能借用 interface: public interface IntUnaryFunction { int apply(int x); } // 定义一个方法 public class TenX implements IntUnaryFunction { /* Returns ten times the argument. */ public int apply(int x) { return 10 * x; } } // 高阶方法 public static int do_twice(IntUnaryFunction f, int x) { return f.apply(f.apply(x)); } // 调用高阶方法 System.out.println(do_twice(new TenX(), 2)); 在JAVA 8中,提供了很多函数式的接口。Java 8 引入 java.util.Function<T, R>接口, 可以接受存储一个函数,<T, R>对应该函数的参数和返回对象 ...

2017-05-29 · 1 min · Cong Chan

Java Hash @Override equals() hashcode()

主要介绍: Hashcode(哈希码)与 equals(判断相等)的关系 Hashcode 方法的底层实现原理 开发中需要掌握的原则和方法 HashSet, HashMap, HashTable HashSet底层是调用HashMap. HashMap 使用hashCode和equals来进行对象比较。 拿HashSet和add()举例(其余的数据结构,和 remove, contains等方法类似): 假设HashSet里面已经有了obj1, 那么当调用HashSet.add(obj2)时: if (obj1 == obj2), 那么没有必要调用 hashCode(), 已经有了这个对象, 没必要添加了 else, if hashCode 不同,那么可以直接添加了, 没必要进一步调用 obj1.equals(obj2) 来判断对象是否相等 else hashCode 相同,那么需要进一步调用obj1.equals(obj2) 下面这段代码虽然 HashSet 只存了 a 对象,但当检查是否包含 b 对象时,返回true。 HashSet<String> wordSet = new HashSet<String>(); String a = "hello"; String b = "hello"; wordSet.add(a); return wordSet.contains(b); // return true 根据Javadoc for Set. adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). ...

2017-02-26 · 3 min · Cong Chan

Java 多线程

多线程 线程是独立的执行空间,Java语言内置多线程功能,用类Thread来表达。每个Java应用程序会启动一个主线程 – 将main()放在自己的执行空间的最开始处. JVM会负责主线程的启动(以及其他比如GC的系统线程). 程序员负责启动自己的建立的线程. 启动新线程 建立Runnable对象作为线程任务Runnable job = new MyRunnable(), Runnable接口只有一个方法run() 建立Thread对象并赋值Runnable Thread thread1 = new Thread(job); Thread thread2 = new Thread(job) 启动thread.start(); 另一种创建线程的方法是用Thread的子类覆盖掉run(), 构造新线程Thread t = new Thread();. 从OO的角度看待, 此时Thread 与线程任务是不同概念的. 让子类继承Thread的目的通常是需要更特殊的Thread, 需要特殊的行为, 如果没有这种需求, 就没必要继承Thread. 线程调度器 多线程间的切换由调度器scheduler来管理, 线程有多种状态: 执行中, sleep(2000): 睡眠2000ms, 时间到之前不会被执行, 但时间到了并不保证一定会被执行. 可能会抛出InterruptedException, 所以对它的调用要包含在try/catch中. locked. 线程的run完成执行后, 将无法重新启动. 调度器在不同的JVM有不同的做法. 测试多线程时需要在不同机器上测试. 并发 Concurrency并发环境中, 为了避免冲突, 需要上锁, 使用synchronized来修饰方法使之每次只能被单一线程读写. 同步化是有代价的, 查询钥匙有性能上的损耗, 同步化也会强制线程排队执行, 还可能出现死锁. 死锁 因为两个线程互相持有对方正在等待的东西, 导致没有一方可以脱离等待. 数据库有事务回滚机制来复原死锁的事务, 但Java没有处理死锁的机制. ...

2017-02-26 · 1 min · Cong Chan

Java 套接字Socket

Socket 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket,确切的说Socket是个代表两台机器之间网络连接的对象。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。 Socket socket = new Socket("192.168.2.1", 5000), 第一个参数是IP地址, 第二个参数是端口. Socket连接的建立代表两台机器之间存有对方的信息, 包括网络地址和TCP端口号. 但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。 使用BufferedReader从Socket上读取数据: 建立对服务器的Socket连接Socket socket = new Socket("192.168.2.1", 5000) 建立连接到Socket上低层输入串流的InputStreamReader InputStreamReader stream = new InputStreamReader(socket.getInputStream());, 作为从低层和高层串流间的桥梁, 把来自服务器的字节转换为字符 建立缓冲区BufferedReader来读取 BufferedReader reader = new BufferedReader(stream); String msg = reader.readLine(); 用PrintWriter写数据到Socket上: 建立对服务器的Socket连接 建立链接到Socket的PrintWriter PrintWriter writer = new PrintWriter(socket.getOutputStream()), 作为字符数据和字节间的转换桥梁, 可以衔接Strings和Socket两端 写入数据 writer.println("You have a message"); TCP/IP TCP/IP协议集包括应用层, 传输层,网络层,网络访问层。 应用层协议主要包括如下几个:FTP、TELNET、DNS、SMTP、NFS、HTTP。 FTP(File Transfer Protocol)是文件传输协议,一般上传下载用FTP服务,数据端口是20H,控制端口是21H。 Telnet服务是用户远程登录服务,使用23H端口,使用明码传送,保密性差、简单方便。 DNS(Domain Name Service)是域名解析服务,提供域名到IP地址之间的转换,使用端口53。 SMTP(Simple Mail Transfer Protocol)是简单邮件传输协议,用来控制信件的发送、中转,使用端口25。 NFS(Network File System)是网络文件系统,用于网络中不同主机间的文件共享。 HTTP(Hypertext Transfer Protocol)是超文本传输协议,用于实现互联网中的WWW服务,使用端口80。 网络接口层: ...

2017-02-26 · 2 min · Cong Chan

Java 抽象类

抽象类 有些情况下,有些父类在实际应用中只有被继承的和产生多态的意义,而没有实例化的意义(比如抽象的Animal, Canine等,实例化这些抽象概念没有实际意义),所以不希望这种父类会被初始化。通过标记类为抽象类,编译器就知道该类不能创建实例(不能作为new实例, 但可以用于声明类型). abstract class Canine extends Animal { ... } Canine c = new Dog; // Canine c = new Canine(); 无法编译 反之,不抽象的类就是具体类. 有抽象类自然就有抽象方法,抽象的方法没有实体,所有就不会含有具体的实现public abstract void doSomething();. 只有抽象类才能拥有抽象方法. 在抽象父类中定义可继承的抽象方法, 可以定义出一组子类共同的协议, 这样能够保证多态. 但因为抽象方法只是为了标记处多态而存在, 它们没有具体的内容, 这样在继承树结构下的第一个具体类就必须要实现所有的抽象方法. 当然, 树结构中的抽象类也可以提前把抽象方法实现了(default方法). 抽象类和接口的比较 接口是抽象类的极端形式,接口是完全抽象的,不包含实现(新的特性支持default method)。 有很多情景需要某个类继承多种父类。比如,因为原来的业务需求比较单一,只需要Animal - Canine - Dog这种类结构就满足需求了, 此时Dog只是Animal的子类. 但后来有了新的功能需求, 上线了宠物功能, 理论上可以为每一种具体的属于宠物的子类添加宠物功能, 这就涉及大量的人工和bug. 但假如额外设计一种Pet类, 那么Pet和Animal会有交叉重叠, 如果让宠物子类同时继承两种超类, 那就是多重继承. 因为多重继承会有致命方块的问题. 所以Java不支持这种方式. 而接口这个概念, 就是用于解决这个问题的: public interface Pet { public abstract void beFriendly(); public abstract void play(); } // 对于属于宠物的子类,让其实现接口`Pet`. public class Dog extends Canine implements Pet {} 基本上,接口能做的抽象类都可以做。 但接口的最大意义就是其无比的适用性, 若以接口取代具体的子类或抽象类作为参数或返回类型, 那么就可以传入任何有实现该接口的东西. 有了接口, ...

2017-02-26 · 2 min · Cong Chan

Java 类的继承扩展 Extends

类的继承扩展 定义class之间的层次关系. 假设要构建一个RotatingSLList,它具有与SLList相同的功能,如addFirst, size等,但是需要额外的rotateRight操作将最后一项放到列表的前面,因为继承允许子类重用已经定义的类中的代码。所以让RotatingSLList类从SLList继承部分代码: public class RotatingSLList<Item> extends SLList<Item> {} RotatingSLList“是一种”SLList, extends可以让我们继承SLList的原始功能,并能修改或添加其他功能。 /** The rotateRight method takes in an existing list, and rotates every element one spot to the right, moving the last item to the front of the list. For example, input [5, 9, 15, 22] should return [22, 5, 9, 15]. */ public void rotateRight() { Item x = removeLast(); addFirst(x); } 通过extends, 子类继承父类的所有成员,成员包括: ...

2017-02-25 · 4 min · Cong Chan

Java 13 | 接口默认方法

除了单纯提供声明之外,Java 8 也允许接口提供具体的实现方法。 缺省方法 从 Java 8开始支持 Default method。 我们可以在List中列出已实现的method。这些方法就是 default method,定义了List hypernyms的一些默认行为:default public void method() { ... }. 我们可以自由调用interface中定义的方法,而不用操心具体的实现。Default method 适用于实现接口的任何类型的对象!子类可以直接调用,而不必重新实现 default method。 // List default public void print() { ... } 不过,我们仍然可以override default method,在子类中重新定义该方法。这样,只要我们在LinkedLList上调用print(),它就会调用子类override的方案,而不是父类的。 // LinkedList @Override public void print() { ... } Dynamic type Java是通过一个叫“dynamic method selection”的特性,来确定要调用 default method 还是已经被子类override的method。 当实例声明List<String> l = new LinkedList<String>();, 则指明l是 static 类型的 List。由 new 生成的 object 是LinkedList类型,也从属于 List 类型。但是,因为这个对象本身是使用 LinkedList 构造函数实例化的,所以我们称之为 dynamic type。 ...

2017-02-24 · 1 min · Cong Chan

Java 12 | 接口 Interface

子类在什么情况下需要多个父类? 比如,因为原来的业务需求比较单一,只需要Animal - Canine - Dog这种类结构就满足需求了, 此时Dog只是Animal的子类. 但后来有了新的功能需求, 上线了宠物功能, 理论上可以为每一种具体的属于宠物的子类添加宠物功能, 这就涉及大量的人工和bug. 但假如额外设计一种Pet类, 那么Pet和Animal会有交叉重叠, 如果让宠物子类同时继承两种超类, 那就是多重继承. 因为多重继承会有致命方块的问题, 不同父类对同一个方法的可能有不同的实现方式, 这会导致冲突. 所以Java不支持这种方式. 接口 而接口这个概念, 就可以用于解决这个问题的. 类不需要继承多个父类, 只需要实现一个或多个接口指定的所有方法/行为的关系. public interface Pet { public abstract void beFriendly(); public abstract void play(); } // 对于属于宠物的子类,让其实现接口`Pet`. public class Dog extends Canine implements Pet {} 接口作为参数 我们前面创建的 LinkedList and ArrayList 其实很相似 - 所有的method都一样. 如果我们需要写一个需要用到数组的类比如WordUtils class, public class WordUtils { /** Returns the length of the longest word. */ public static String longest(LinkedList<String> list) { ... return list.get(maxDex); } } 我们如何让longest方法也适配ArrayList?简单的方法及时写两个同名不同参数的methods。即所谓method overloading。 public static String longest(LinkedList<String> list) public static String longest(ArrayList<String> list) ...

2017-02-23 · 2 min · Cong Chan