java入门笔记
2015-08-10 15:35 truenight 阅读(191) 评论(0) 编辑 收藏 举报(一)基本概念
java代码被编译成bytecode,然后在JVM上运行,与目标机器的架构无关,从而达到”write once ,run anywhere”的目的。 一些目标架构相关的功能如图形,线程,网络由标准库提供统一的接口。
JIT,bytecode虽然拥有可移植性,但是解释执行的性能欠佳,引入Just-in-Time(JIT)编译器用于在运行时将bytecode翻译成机器码,会将翻译过的代码缓存起来以降低性能损耗,绝大多数的java实现都依赖于JIT。
JVM,jvm是一个实现了虚拟机规范,运行在目标机器上的一个进程,用于执行java bytecode。
JRE 包括jvm,Java核心类库和支持文件
JDK 编译器,调试器和其他开发工具。
(二)编译和运行
(1)javac命令用于编译java源文件
javac [options][sourcefiles][@files]
sourcefiles 一个或多个要编译的java文件 如果要编译的源文件数量较多,可以新建一个文件,将要编译的原文件列在这个文件中,以空格或回车来进行分隔,然后用@file的方式传入刻文件.
编译产生的类文件默认在源文件相同目录下,可以使用-d选项指定目标目录.
-cp or –classpath or CLASSPATH环境变量
指定用户类路径(可以是目录,JAR archives,ZIP archives),用于查找类文件,如果-sourcepath没有指定,classpath也会用于搜索源文件。通过classpath找到的classes如果找到源文件会重新编译。
-d 目录
设置输出类文件的位置。
(2)打成可运行的jar包
编写MANIFEST.MF文件
Manifest-Version: 1.0
Main-Class: classname (主类,包含main方法的类,定义java虚拟机入口点位置)
Class-Path: jar1-name jar2-name directory-name/jar3-name (引用其他包的类)
打包命令 jar-cvfm xxx.jar MANIFEST.MF *.class
(3)运行java程序
java命令
重要参数 -classpath,-cp 告知虚拟机搜索目录名、jar文档名、zip文档名,之间用分号;分隔。
虚拟机在运行一个类时,需要将其装入内存,虚拟机搜索类的方式和顺序如下:
Bootstrap classes,Extension classes,User classes。
Bootstrap 中的路径是虚拟机自带的jar或zip文件,虚拟机首先搜索这些包文件,用System.getProperty("sun.boot.class.path")可得到虚拟机搜索的包名。
Extension是位于jre"lib"ext目录下的jar文件,虚拟机在搜索完Bootstrap后就搜索该目录下的jar文件。用System. getProperty("java.ext.dirs”)可得到虚拟机使用Extension搜索路径。
User classes搜索顺序为当前目录、环境变量 CLASSPATH、-classpath。
直接运行class文件 java <包名>.CLASS文件名
运行jar java –jar xxx.jar
(三)常用数据结构
(1)Enumeration
1: Enumerations contents = vec.elements();
2:
3: while(contents.hasMoreElements())
4: {
5: Object obj = contents.nextElement();
6: }
(2)BitSet
1: //
2: BitSet bits1 = new BitSet(16);
3: BitSet bits2 = new BitSet(16);
4:
5: bits1.set(10,true);
6: bits1.and(bits2);
7: bits1.or(bits2);
8: bits1.xor(bits2);
(3)Vector / ArrayList
两个都是随机访问动态数组,当需要扩充时 Vector扩充size为原来的两倍,ArrayList扩充50%.考虑到性能可以一开始就设置capacity。
Vector是线程安全的,ArrayList不是。如果不考虑线程安全性,使用ArrayList不用付出synchronized的负担。
1: // initial capacity is 3, increment is 2
2: Vector v = new Vector(3, 2);
3: v.add(new Interger);
4: ArrayList<Integer> arr = new ArrayList<>();
5: arr.add(3);
(4)Hashtable/HashMap
1: Hashtable dict = new Hashtable();
2:
3: dict.put(“xxx”,new Double(1.0));
4:
5: Enumeration names = dict.keys();
6:
7: while(names.hasMoreElements())
8:
9: {
10:
11: String str = (String)names.nextElements();
12:
13: }
Hashtable是线程安全的,HashMap不是
LinkedHashMap遍历顺序是predictable的,Hashtable不是
Hashtable只是在get put contains等操作上是线程安全的,但是像检查集合中是否包含元素然后插入这个过程不能确保线程安全,可以用ConcurrentHashMap替代。
(7)Properties
1: public void ReadConfig()
2: {
3: File file = new File("netgame.config");
4: FileInputStream is = new FileInputStream(file);
5: Properties pro = new Properties();
6: pro.load(is);
7: String ip = pro.getProperty("serverip", DEFAULT_IP);
8: String port = pro.getProperty("port", Integer.toString(DEFAULT_PORT));
9: }
(四)CheckException 和 UnCheckException
exception的好处在于简化代码,替代将非法情况通过返回值层层往上传层层处理这种头痛的编写函数模块的方式。
checked exception是指开发者可以从异常中恢复,而unchecked exception是指无法恢复的程序错误。checked exception会通过编译器强制开发者用try/catch blocks处理异常或者rethrow异常(在函数声明的后面加上 throws Exception声明,或者用try/catch捕获后抛出new Exception),当你想要API的使用者考虑某种异常情况时可自定义checked exception.
捕获到一个异常时可以做几种处理
log it
rethrow it
construct a new exception and rethrow it.一种惯用法就是你觉得不该出现或者无法处理的checkedException可以new一个runtimeexcetption抛出。
other handler 比如捕获到FileNotFoundException可以弹出对话框要求用户重新输入路径.
异常不能超过package的边界。
(五)Byte Stream 和 Character Stream
stream提供了顺序访问文件的方式,byte stream一个字节一个字节的访问,character stream以字符为单位访问文本,跟字符编码有关,如unicode编码一个字符两个byte.
character tream:Reader/Writer ,byte stream:InputStream/OutputStream
BufferedReader/BufferedWriter 缓冲模式
BufferedReader流能够读取文本行,通过向BufferedReader传递一个Reader对象,来创建一个BufferedReader对象,之所以这样做是因为FileReader没有提供读取文本行的功能.
BufferedReader reader = new BufferedReader(new FileReader(xxx.txt));
InputStreamReader 将字节流转换为字符流,解码过程使用平台默认字符编码.
(六)线程 synchronized关键字
当一个线程发生以下情况时会进入not runable状态
a sleep方法被调用
b thread调用 wait方法
c I/O阻塞
当一run方法退出时线程死掉。
java的线程调度是priority-preemptive,当一个高优先级的线程苏醒,而低线程处于运行状态,则高优先级的线程会立即运行。
(1)synchronized(this)
当两个并发线程访问同一个对象的object中的synchronized(this)同步代码块时,一个时间内只有一个线程得到执行。
当一个线程访问object中的synchronized(this)时,另一个线程仍然可以访问该object中的synchronized(this)代码块,对该object中的所有其他synchronized(this)代码块不能访问。
(2)synchronized方法/代码块
每一个类实例对应一把锁,所有声明为synchronized的成员函数中至多只有一个处于可执行状态,避免了类成员变量的访问冲突。
每一个类也对应一把锁,所以synchronized修饰的static方法也如此。
synchronized的粒度应该尽量小,比如如果把线程类的方法run()声明为synchronized,由于线程整个生命周期都在运行,导致对本类其他synchronized调用都不成功。
可以将需要同步的部分代码提取出来单独成为函数,或者使用synchronized代码块。
(七)线程工具 BlockingQueue
调用put(Object)如果队列已满会阻塞线程。take(Object)如果队列为空会进入阻塞状态等待有数据。
ArrayBlockingQueue, 基于数组的有界阻塞队列
LinkedBlockingQueue,基于链表的阻塞队列
ArrayBlockingQueue的put和take操作共用同一个锁对象,而linkedBockingQueue采用分离锁,所以生产者和消费者可以并行运行。linkedBlockingQueue在插入和删除元素的同时会产生额外的node对象。
PriorityBlockingQueue 按优先级排序
(八)定时器
(1)timer类
1: public class Test{
2: Timer timer;
3: public static void main(String[] args)
4: {
5: System.out.println("timer begin....");
6: timer = new Timer();
7: timer.schedule(new TestTask(), 3* 1000);
8: }
9: }
10:
11: public class TestTask extends TimerTask
12: {
13: public void run()
14: {
15: System.out.println("Time's up!!!!");
16: }
17: }
timer类的一个缺陷是TimerTask如果抛出未检查的异常将导致Timer线程终止,其他已经被安排但尚未执行的TimerTask将不会再执行。
(2)ScheduledExecutorService类
1:
2: Runnable runnable = new Runnable()
3: {
4: public void run()
5: {
6: //send heartbeatmsg to all
7: HeartbeatMsg msg = new HeartbeatMsg();
8: heartBeatOrder++;
9: msg.order = heartBeatOrder;
10: SendToAll(msg);
11: }
12: };
13:
14: ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
15: service.scheduleAtFixedRate(runnable, 0,3, TimeUnit.SECONDS);
16: //0 initialDelay,3 period,TimeUnit.MILLISECONDS