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 ?...

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没有处理死锁的机制. Volatile 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`....

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) { ....

2017-02-23 · 2 min · Cong Chan

Python之奇技淫巧

FBI WARNING 这不是python入门 函数 Fundamentally, the qualities of good functions all reinforce the idea that functions are abstractions. 函数作为一种机制, 提供了用于抽象数值运算的模式, 使其独立于所涉及的特定值。 文档 code is written only once, but often read many times. docstring def pressure(v, t, n): """Compute the pressure in pascals of an ideal gas. Applies the ideal gas law: http://en.wikipedia.org/wiki/Ideal_gas_law v -- volume of gas, in cubic meters t -- absolute temperature in degrees kelvin n -- particles of gas """ >>> help(pressure) Python docstring guidelines...

2017-02-22 · 2 min · Cong Chan

Java 11 | 测试 Testing

测试 如何知道自己的程序是否真的在工作?在现实世界中,程序员相信他们的代码,因为代码通过了他们自己编写的测试。常用的测试有 Ad Hoc Testing, Unit test 和 Integration Testing。 Ad Hoc Testing,是指没有计划和记录的软件测试,除非发现缺陷,不然一般只运行一次。 Unit test 程序可分解为单元(或程序中可测试的最小部分),Unit test 严格测试代码的每个单元,最终确保项目正确运行。 Unit test 好处: Unit test 保证良好的代码结构(每个 method “只打一份工”),帮助我们较好地解析任务, 允许我们考虑每个方法的所有边界情况,并单独测试它们。 让我们每次只专注于一个单元,进行测试,debug,对准确度有信心后,再进行下一个单元的开发。相比于一次性写完所有代码,再测试debug,Unit test 减少了 debugging 时间。 坏处: 测试也要花时间 测试本身也是有可能出错的,测试可能不全面,不规范,或者有bug 有些单元是依赖于其他单元的 Unit testing 无法保证各个模块的交互,无法保证整个系统作为一个整体是否正常工作。 JUnit JUnit是一个给Java做测试的框架,由Erich Gamma(Design Patterns)和Kent Beck(eXtreme Programming)编写。 JUnit使用Java的 reflection 功能(Java程序可以检查自己的代码)和注释。 JUnit允许我们: 定义并执行测试和测试套件 使用测试作为规范的有效手段 使用测试来支持重构 将修改的代码集成到构建中 JUnit可用于多个IDE,例如BlueJ,JBuilder和Eclipse在一定程度上具有JUnit集成。 import org.junit.Test; import static org.junit.Assert.*; @Test public void testMethod() { assertEquals(<expected>, <actual>); } assertEquals测试一个变量的实际值是否等于它的期望值。 JUnit test 各个测试方法,必须是非静态的(JUnit的设计人员设计规定的)。...

2017-01-29 · 1 min · Cong Chan

Java 10 | 数据结构 - LinkedList 还是 ArrayList

Java 提供了 ArrayList, ArrayDeque 和 LinkedList 几个API. 队列 queue, 通俗的含义, 就是不能插队, 只能在末尾插入. 双端队列 Double Ended Queue (Deque) 是具有动态大小的序列容器,可以在两端(前端或后端)扩展或收缩 –http://www.cplusplus.com/reference/deque/deque/ CS61b的project 1a需要实现两种双端队列(array based 和 linkedklist based). 不同的API, 在考虑什么时候应该用哪个时, 我们需要考虑它们的性能差异: 搜索/定位:与LinkedList相比,ArrayList搜索更快。 ArrayList的get(int index)性能是O(1)的,而LinkedList的性能是O(n)。因为ArrayList基于array数据结构,可以直接用 array index 定位元素。 删除/插入:LinkedList 操作性能是O(1),而ArrayList的性能从O(n)(删除/插入第一个元素)到O(n)(最后一个元素)都有可能。因为LinkedList的每个元素都包含两个指向其相邻前后元素的指针(地址),因此仅需要改变,被删节点的prev和next指针位置。而在ArrayList中,需要移动剩余元素,来重新填充array空间。 内存开销:LinkedList的每个元素都有更多的内存开销(额外的指针), 而ArrayLists没有这个开销。但是,ArrayLists需要占用初始容量。一般ArrayList的默认初始容量非常小(Java 1.4 - 1.8使用10)。但是,往ArrayLists添加元素时, 它可能会适当地增大容量,所以如果添加了很多元素,则必须不断调整数组的大小,那样也可能会导致元素频繁挪动位置。 综上所述: 如果在应用中需要频繁插入和删除,那么选择LinkedList。 假如一开始,就知道后面要添加大量元素,那就使用较高的初始容量来构造ArrayList。 大部分用例中, 相比LinkedList, 人们更偏爱ArrayList以及ArrayDeque。如果你不确定应该选哪个, 那么就直接考虑ArrayList吧(参考 https://stackoverflow.com/questions/322715/when-to-use-linkedlist-over-arraylist).

2017-01-28 · 1 min · Cong Chan