异常处理
- finally:try或catch有return语句时,finally也会在执行return之前执行
- 异常是对象,具有多态性,可只声明或catch父类来处理多个异常;为每类异常单独写多个catch块时,要从子类到父类(从小到大)排catch块
- 有风险方法的调用方式:try/catch;duck
- duck:踢皮球式处理异常,自己也声明要抛出相同异常,将捕获到的异常从自己抛出,main()抛出的异常由java虚拟机处理。
- 异常处理规则:不能没有try;try,catch之间不能有程序;try一定要有catch或finally;只有finally的try必须声明异常
GUI
垃圾中文版丢了关键的一句变得误解:这段本意是要说指向子类的父类引用只能调用二者都有的方法(子类重写),而不能调用自己没有,只有子类有的方法(重载、新定义),就是子类能做的事情比父类多。对比可以看到中文版少了第二个画线句子,这让我一开始以为书写错了,而且中文版第一句标题还把graphics拼写错了,书上面也是错的。。。
保存对象
存储状态:
实现过Serializable接口的类其对象才能序列化。
将序列化对象写入文件:
- 创建FileOutputStream:FileOutputStream fileStream=new FileOutputStream(“myfile.ser”);
- 创建ObjectOutputStream:ObjectOutputStream os=new ObjectOutputStream(fileStream);
- 写对象:os.writeObject( myobject );
- 关闭ObjectOutputStream:os.close();
读取对象,解序列化:
- 创建FileInputStream:FileInputStream fileStream=new FileInputStream(“myfile.ser”);
- 创建ObjectInputStream:ObjectInputStream os=new ObjectInputStream(fileStream);
- 读取对象:Object one=os.readObject(); //readObject()返回值是Object类型
- 转换对象类型:MyClass myone=(MyClass) one;
- 关闭ObjectInputStream:os.close();
写文本文件:FileWriter (打开/建立文件、写入、关闭文件)
- FileWriter writer=new FileWriter(“myfile.txt”);
- writer.write(“hello”);
- writer.close();
读文本文件:FileReader (关联文件、读、关闭文件)
- File myFile=new File(“MyText.txt”);
- FileReader fileReader=new FileReader(myFile);
- BufferedReader reader=new BufferedReader(fileReader);
- String line=null;
- while((line= reader.readLine())!=null){ //通常是循环读入
- System.out.println(line);
- }
- reader.close();
PS:输入输出相关操作都有包含在try/catch块中
缓冲区BufferedWriter, BufferedReader
- BufferedWriter:BufferedWriter writer=new BufferedWriter(new FileWriter(aFile));
- BufferedReader:BufferedReader reader=new BufferedReader (new File (aFile));
File类代表磁盘上的文件这个概念,类似于文件路径,而非具体文件的内容。File可用于创建文件对象、新目录(列出目录内容)、取得文件或目录绝对路径、删除文件
socket连接
- socket是代表两台及其支架网络连接的对象,连接就是两台机器之间的一种关系
- 客户端通过建立Socket来连接服务器,建立socket连接需要IP地址(或网域名称)和TCP端口号,连接的建立代表双方存有对方的信息(IP,TCP端口号)
- TCP端口号(16bits):识别服务器上的特定程序
- InputStreamReader是转换字节成字符的桥梁,注意用来连接BufferedReader与底层的Socket输入串流。
使用串流通过socket连接进行沟通,读服务器数据
- Socket chat=new Socket (“127.0.0.1”, 5000);
- InputStreamReader stream=new InputStreamReader (chat.getInputStream());
- BufferedReader reader=new BufferedReader (stream);
- String message=reader.readLine ();
PrintWriter连接Socket输出串流写数据给服务器
- Socket chat=new Socket (“127.0.0.1”,5000);
- PrintWriter writer=new PrintWriter(chat.getOutputStream());
- writer.println (“message1”);
编写服务器程序需要一对Socket:等待用户请求的ServerSocket、与用户通信用的Socket
- 服务器应用程序对特定端口创建ServerSocket,让应用程序开始监听来自4242端口的客户端请求:ServerSocket serverSock=new ServerSocket(4242);
- 客户端对服务器应用程序建立Socket连接:Socket sock=new Socket(“127.0.0.1”,4242);
- 服务器创建于客户端通信的新Socket:Socket sock=severSock.accept(); accept()方法只等待用户的Socket连接时处于闲置状态,当用户连上来时,此方法返回一个Socket与客户端通信。Socket与ServerSocket的端口不同,因此ServerSocket可以空出来等待其他用户。
线程
- 线程代表独立的执行空间,记录目前线程空间执行到哪里
启动新线程:
- 建立Runnable对象(线程的任务):Runnable threadJob=new myRunnable();
- 建立Thread对象(执行者)并赋予Runnable:Thread myThread=new Thread(threadJob);
- 启动Thread:myThread.statr();
synchronized关键字修饰的方法具有原子性,一次只能被单一线程存取
死锁:出现了循环等待资源
数据结构
TreeSet | 有序、不重复 |
HashMap | 用成对的name/value来保存取出 |
LinkedList | 用于经常删除、插入元素的集合 |
HashSet | 防止重复的集合,可快速找到相符的元素 |
LinkedHashMap | 类似HashMap,但可记住元素插入顺序,可按元素上次存取顺序排序 |
- a.equals(b)为true是a,b对象相等的充要条件;hashcode相等是两个对象相等的必要条件
- a,b对象相等 <=> a.equals(b)==b.equals(a)==true => a.hashCode()==b.hashCode。
HashSet检查重复:
把对象加入HashSet时,用hashcode判断对象加入的位置,同时将其与已经加入的对象比较hashcode,相同则表示重复。所以hashCode()必须被覆盖过,因为hashCode()的默认行为是对堆上的对象产生独特的值,如果没有覆盖,则值相同的两个对象无法产生相同的hashcode;equals()也必须被覆盖过,因为equals()的默认行为是执行==比较,即测试两个引用是否指向堆上同一个对象,如果没有覆盖,则两个对象永远不会被视为相等。
public <T extends Animal> void takeThing1 (ArrayList <T> list1)
- takeThing1() 方法的参数list1可以是元素为任意Animal及其子类对象的ArrayList
public void takeThing2 (ArrayList <Animal> list2)
- takeThing2() 方法的参数list2只能是元素为Animal对象的ArrayList。此时不能用Animal数组的多态思想来考虑Animal的ArrayList,即list2,因为ArrayList还有其他类似于add()的方法,如果给list2赋予的是 Dog的ArrayList,则当takeThing()里面有类似list2.add(new Cat) 的操作时,编译不通过。
通配符<?>:在方法参数中使用通配符时,编译器会阻止任何可能破环引用参数所指集合的行为,即不能加入元素。
另一种等效的类型参数声明方式:在返回类型前声明类型参数
- public <T extends Animal> void takeThing(ArrayList<T> list) //与下一句效果一样
- public void takeThing(ArrayList<? extends Animal> list)
发布程序:JAR、JWS、RMI、Servlet
-d:指定存储编译过的文件的路径
JAR文件:把一组类文件包装成pkzip格式。创建带有JAR信息的manifest文件后,程序就可以在类文件保存在JAR的情况下执行
创建可执行的JAR:
- 确定所有类文件都在classes目录下
- 创建manifest.txt来描述那个类带有main()
- 执行jar工具来创建带有所有类和manifest的JAR文件
用包创建可执行的JAR:
- 确定所有类文件都放在class目录下正对相对应的包结构中
- 创建manifest.txt文件来描述那个类带有main(),以及确认有使用完整的类名称
- 执行jar工具创建带有目录结构与manifest的JAR文件
把类包进包中:在源程序最前面加上包指令package
Java Web Start(JWS)工作方式:
- 客户端点击某网页上JWS应用程序的链接( .jnlp文件:描述应用程序可执行JAR文件的XML文件)
- Web服务器收到请求发送.jnlp文件给客户端浏览器
- 浏览器启动Java Web Start,JWS的helper app读取.jnlp文件,向服务器请求JAR文件
- Web服务器发送.jar文件
- JWS取得JAR并调用指定main()启动应用程序
远程程序调用Remote Method Invocation,RMI——业界用的不多
- 客户端和服务器都是与各自的辅助设施打交道,辅助设施之间通过Socket连接传输信息。
客户端调用服务端方法的过程:
- 客户端对象对辅助设施对象调用方法
- 客服段辅助设施把调用信息打包通过网络送到服务器辅助设施
- 服务端的辅助设施解开来自客户端辅助设施的信息,以此调用真正的服务
Java RMI提供客户端辅助设施对象 (stub) 和服务器端的辅助设施对象 (skeleton),提供执行期所需的全部基础设施(感觉像是调用远程对象的方法,但其实不是)。因为辅助设施通过网络发出调用,网络输入/输出有风险,因此使用RMI是必须决定协议:JRMP或IIOP
创建远程服务:
1、创建Remote接口。接口定义了客户端可以调用的方法,stub和服务器都会实现此接口
- 继承java.rmi.Remote:public interface MyRemote extends Remote
- 所有声明的方法都要抛出异常RemoteException
- 确定参数和返回值都是primitive类或Serializable,因为需要打包通过网络序列化传输
2、实现Remote接口。实现出定义在该接口的方法,是真正执行的类,是客户端会调用的对象
- 实现Remote:public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote
- 继承UnicastRemoteObject,使对象具有与远程相关的功能
- 编写声明RemoteExpection的无参构造函数。因为UnicastRemoteObject的构造函数会抛出RemoteExpection,因此在接口实现中也要声明一个构造函数抛出RemoteExpection
- public MyRemoteImpl() throw RemoteException{ }
- 用java.rmi.Naming的rebind()向RMI registry注册服务,RMI系统吧stub加到registry中,让远程用户可以存取远程服务
3、用rmic产生stub、skeleton。
- JDK的rmic工具利用服务的实现产生stub和skeleton两个类
4、启动RMI registry。rmiregistry就像电话簿,用户从此取得代理(客户端的stub helper)
5、启动远程服务。实现服务的类实例化对象并向RMI registry注册,注册后才能对用户提供服务
code:
(创建远程服务后) 客户端如何取得stub对象:
- 客户端查询RMIregistry:Naming.lookup(“rmi://127.0.0.1/Remote Hello”);
- RMI registry返回解序列化的stub对象。(客户端必须要有由rmic产生的stub类,否则stub类不会在客户端解序列化)
- 客户端就像调用真正服务一样调用stub上的方法
Servlet——多多关注
servlet是放在HTTP Web服务器上运行的Java程序,用户通过浏览器与网页进行交互式,request会发送给网页服务器,若request需要servlet,服务器会执行或调用servlet,得到用户所请求的结果
创建并执行servlet
- 找出可以存放servlet的地方。方便服务器存取servlet文件。
- 取得servlets.jar并添加到classpath上。servlet不是Java标准库的一部分,需要servlets.jar文件中的servlet相关包才能编译出servlet
- 通过extend类HeepServlet来编写servlet类。servlet是个extend过HttpServlet的类
- 编写HTML调用servlet。当用户点击引用到servlet的网页链接时,服务器会找到servlet并根据HTTP的GET、POST等命令调用适当方法
- 给服务器设定HTML网页和servlet。