随笔 - 1  文章 - 1  trackbacks - 0
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(1)

随笔档案

文章档案

搜索

  •  

最新评论

这是自己的一点笔记和一点初学方法建议,总结的是一些最基础的、容易混淆或是理解错误的地方,适合像我一样的菜鸟;有错误或是不正确的地方,希望大家不吝赐教
CU真的是一个非常好的学习平台,希望自己可以尽早地有能力为它的壮大与前进做点贡献

很难说现在类似这样的认证还有多少说服力或者分量
但是我觉得,有一个东西放在那里,给自己一个阶段性的刺激与总结,也不失为一种学习方法
所以自己初学java的定位就是,多读几本书,多读些代码,然后用这样一个考试给自己一个暗示,可以算是初窥门径了

祝大家节日快乐


============笔记===============

一.        声明与访问控制
Javabean命名规则:set、get、boolean is、add/remove监听器
类的修饰符:默认、public、final、abstract、strictfp
方法修饰符:默认、public、protected、private、final、abstract、static、strictfp、synchronized、native(不能有方法体)
变量修饰符:volatile仅可用于实例变量
接口修饰符:默认、public
组合使用final与abstract、private与abstract、static与abstract是常见的错误
局部(方法内)变量能携带的唯一修饰符是final,其他的修饰一律导致编译错误
方法参数(等价于局部变量)设定为final意味着方法不能修改它
公共类中的protected可以被:1、同一包中的所有类(包级访问权限)与2、自己的子类(无论在不在同一个包当中)看到。包外子类访问protected域时,是通过继承从父类继承到了该域,而无法通过调用父类实例引用来访问该域——.运算符将导致编译错误;并且,包外子类继承过protected成员之后,该成员在这个子类内实际上成为了私有的,因此只有该子类与其子类可以访问
抽象
抽象方法必须显示地声明;抽象类可以包含非抽象方法;但倘使一个类中含有哪怕只是一个抽象方法,该类也必然是抽象的
接口
接口只能有抽象方法,隐式为public abstract;域全部是public static(隐式地),也即常量(而非实例变量);接口继承的只能是接口;实现接口的抽象类可以选择性地实现一部分方法,而被非抽象类实现时则必须实现全部方法,且全部方法显示声明为public
Var-arg:作为参数,只能出现一次,且只能作为最后一名参数出现,表示收到的参数放入一个数组
构造方法永远不能有返回值;做了带参构造器,则不会再有默认的无参构造器,此时调用默认构造器时会造成编译错误
变量:
由小到大:byte——short——int——long,double大于float;数值类型全部是有符号的
实例变量会得到默认值(包括类的对象实例,赋为null)
局部变量在栈上,但如果变量是对象引用,该对象将会被创建在堆上。只有栈变量,没有栈对象;局部变量使用前必须初始化先;将局部变量声明为final是合法的,表示方法期间不能改变他的值;声明与实例变量同名的局部变量是合法的,称作隐藏
声明数组时指定长度是常见的错误
没有最终对象,只有最终引用:对象属性是可修改的,但声明为final的引用变量不可再修改引用的对象
静态
Static用于变量与方法,这些变量和方法独立于为类创建的任何实例:static的成员存在于实例被创建之前,无论类有多少实例,static的成员只有一套副本(所有static成员共享它们看到的一套值);方法本地内部类不能为static,内部类方法和实例变量不能为static,局部变量不能为static
Enum
枚举不是简单的字符或者整数,可以视为一个类
枚举可以1.声明为独立的类,2、在类中声明为类成员;不可在方法中声明;可用修饰符只有public与默认修饰符
一旦声明了一个枚举,他就是不可扩展的:在运行时,无法创建而外的枚举常量

二、面向对象
封装
思路:保护实例变量,提供公共的访问器方法
IS-A与HAS-A
IS-A:通过继承或实现而实现,可通过instanceof测试(只要在同一继承树之中,instanceof即可通过);HAS-A:一个类中的代码有对另一个类实例的引用
Overload 与 override
Overload:重载时只有参数表可以做为标准,修饰符可以向宽松的方向修改
Override:重写时修饰符与返回值类型必须精确匹配
也即:修改了修饰符与/或返回值类型,而参数表未加变动,既不是重写也不是重载,产生编译错误
强制转换
向下强制转换时,父类引用引用父类实例,使用子类显示强转可以通过编译,但运行时发生cast异常(可以编译通过);向上强转时隐式与显示皆可
静态
总有这样的错误:在main()中以各种形式(如在循环条件中)访问非静态实例变量。记住一点,运行main()的是类,而不是某一个类的实例
静态方法不能访问实例(非静态)变量/方法;静态方法不可被重写:尝试以重写的语法在子类中声明一个方法会造成一个新方法的定义(可称隐藏),调用时发生的是父类的static方法
耦合讲述了一个类了解另一个类的程度,内聚体现一个类设计目标明确、功能专一的程度

三、赋值
初始化的顺序就是执行的顺序
一个占用int或更短长度的表达式,其结果总是int:byte+byte,int*short,short/byte
数组声明时不可加长度(编译错误);注意索引范围(运行时异常)
初始化块
静态块执行一次,在类被加载时(main());当静态块中有错误时,编译时不会报错
包装器类、装箱
目的:使基类具备object类的特质;分类、转换的方法
每当有一个实例产生,实例块被执行一次,在构造器super()之后被执行
因此最终的顺序:静态块——>super()——>实例块——>构造器
对于任何指定对象,finalize()至多只会被垃圾收集器调用一次;调用实际上能够导致对象免于被删除

四、运算符
对于复合赋值运算符,赋值号右侧总是先被计算
“+”的连接从左向右运行,操作对象中任一个为String则“+”身份为连接符;取消装箱与连接一起作用
==与equals
对于基类,数值相等时==的判断将是true;若==两边类型不兼容编译器将报错;equals用于比较内容且不可用于基类,类型不兼容时可以编译,得到false
枚举的相等性可用==与equal两者验证
若对象的任何一个超类实现了某一个接口,我们就说该对象属于这种接口:可以通过instanceof测试
三目运算符连接时,顺次检查求值
&&与||被称作短路运算符,是因为他们的“测试优化”能力,&与|不具备这种特质;短路运算符视其前后为两个独立的表达式

五、流程控制、异常与断言
开关语句:switch表达式的结果必须为char。Byte、short或可隐式提升为int的enum——总之就是能放进int容器的类型;case常量必须与开关里的类型一直,且必须是编译时常量;在比int小的变量上使用switch且case常量大于变量范围,导致编译错误;从第一个匹配进入,没有break时发生直落,default与其它case有着等同的地位(直落同样会发生)
do expression while();不要漏掉分号
for循环提前结束的方法:return——跳转回调用方法;break——跳转至for后第一句;continue——跳出此次迭代;system.exit()——jvm关闭
Try、catch与finally
看见try时先寻找catch或者finally,孤立的try导致编译错误
将具体子类异常置于父类异常之上书写catch(相反时编译错误);兄弟异常顺序随意
存在return时,finally先于return——finally必然被执行(除非在try外的异常导致编译错误),因而在将异常传回调用方法时,需要finally——它先执行,之后return
在finally之后的语句将不被执行
除非异常是运行时异常,方法声明它抛出的异常(或者catch它),据此抛出的异常,属于方法的公共接口

六、字符串、IO、格式化与解析
1)String、StringBuffer与StringBuilder
String类被标识成了final,所有方法不可重写
String一旦创建,无法修改
String s = new String(“abc”);//常规内存生成一个新的String对象,s引用了它;同时常量abc被放入String常量池
StringBuilder的方法是非同步的
考试讨论的所有StringBuffer与StringBuilder方法都操作调用该方法的对象的值
带有两个索引参数的方法,第一个参数从零0开始计数索引,第二个从1开始
String没有delete
Replace(’char old’,’char new’);与replace(start, end, String);
StringBuffer与StringBuilder返回String的方法:toString();
文件导航与IO
看到stream字样的api,可知其与文件或io无甚关联,可能是关于串行化的
创建reader或者writer时,若文件不存在,则将自动创建它;但目录不同,将会导致找不到文件/目录异常
串行化
1、        仅能保存非静态成员变量
2、        保存的仅是变量的值,任何修饰符都无法保存
3、        某些对象的值是瞬时的(thread、fileinputstream等),无法保存其状态,必须用transient关键字标注;这样的标注导致恢复时赋值为默认
4、        要串行化的对象必须实现serializeable
5、        要串行化的对象对应的类必须是public
6、        欲串行化的类若has-a不能串行的成员(如未声明为serializable或是一个私有成员),将会导致运行时错误
一般的过程
串行化:创建FileOutputStream,用ObjectOutputStream包装,对对象进行writeObject()操作,close()
反串行化:创建FielInputStream,用ObjectInputStream包装,使用readObject()获得Object类对象并执行强转
不能串行化的成员用transient标注,但反串行时这些成员将恢复默认值。对它们的保存引入了书写private void write/read:注意第一句总是显示调用defaulWrite/Read


七、泛型与集合








八、内部类
一些固定的形式
(1)静态方法访问非静态内类:
                方法为:
                Outer myouter = new Outer();//这里的myouter是创建的外部类的对象
                Outer.Inner myinner = myouter.new Inner();//myinner是内类的对象
                然后再myinner.showName();//showName()是外类中的非静态方法
(2)非静态方法访问非静态内类
                直接创建该内部类的对象:new Inner().showName();
(3)静态方法访问静态内类:
                也是直接创建该内部类的对象,即Inner myinner = new Inner()
或Outer.Inner myinner = new Outer.Inner()
静态内部类相当于一个静态成员,不可以访问非静态的对象,这里一定特别小心,多加注意
匿名内部类存在的意义与应用的场合

九、线程
start()对我们唯一的保证:每个线程都将运行,每个线程都将运行至结束
一旦start(),就永远不能重新start()哪怕是它已经死去,否则导致运行时异常
需要熟悉的方法:
静态yield(),大多数情况下使当前线程转入可运行状态,本意是使得具有相同优先级的其他线程获得运行机会,这同样无法得到保证
静态sleep(),转入可运行状态休眠一段时间,不放任何锁;用法Thread.sleep(long),必须包围在try-catch中
join(),保证在调用join()的线程结束前,当前进程停止运行,也即当前执行线程内join()之后的语句保证在指定线程run()完之后运行
静态Thread.currentThread(),返回对当前执行线程的引用
isAlive(),已经启动,未结束run()
start()的调用需要Thread的实例,不可以是runnable
使一个实现runnable接口的类的实例启动,可以做一个Thread,也可以直接调用run方法
Runnable只有一个run方法,public void run();若没有重写这样一个方法,将在声明实现接口的地方报错:未能实现该接口
线程的启动应调用start(),若直接调用run()则表示从当前正在运行的类调用一个普通的方法,run()进入当前调用栈,而不会启动新的线程;重载的run()只能作为一般方法手动调用
语法上,将线程传递给线程的构造器是合法的
对线程进行setPriority()是没有保证的。默认的优先级是5
保护数据的操作:变量标识为private,同步访问这些变量的方法
在java中,每一个对象都有一个内置的锁,锁表现出作用的唯一情况是:对象具有同步方法代码。当使用一个实例调用非静态同步方法时,就会索取该实例的锁
对一个实例,某一时刻只能有一个线程锁定它;拿到锁的线程可以访问该实例的任意同步方法/块,其他线程可以任意访问非同步方法
为了减少同步对并发的影响,可以只将方法的一部分代码放入同步块中实现同步——同步块应当指定这部分代码执行时要锁定的对象是谁:当指定this时可以写成一个普通的同步方法的形式;对于静态方法,在外围声明为synchronized或在block中使用LockTargetClass.class的形式指示锁定对象,因为静态成员只有一份拷贝,要将整个类所有静态成员声明为同步
当对象的锁被取走之后,其他试图访问同步方法的线程被阻塞在锁上(进入阻塞状态)。他们在某个特定的池等待对象的锁被释放,返回可运行状态
关于线程在同步上的互相阻塞:
引用同一实例访问非静态同步方法的线程彼此阻塞
访问同一类中静态方法的线程彼此阻塞——他们都在索取同一个Class实例的锁
访问同一类静态与非静态同步方法的两个线程不会彼此阻塞——一个在锁定this,一个在锁定class
同步不同对象的两个方法不会彼此阻塞
保持锁的方法:join(),sleep(),yield(),notify()
放弃锁的方法:wait()
Access to static fields should be done from static synchronized methods. Access
to non-static fields should be done from non-static synchronized methods
线程安全类:不要把同步放在较高的级别上
两个线程互相等待对方拿到的锁——死锁
Wait()、notify()等方法是Object类的方法,它们只能放入同步块,这就保证了在获得同步对象的锁之前,不能在对象上调用这些方法
每一个对象都可以有一个表,放置等待它信号的线程;一旦线程调用该对象的wait(),他们就进入这个列表之中,在目标对象调用notify()之前,这些线程什么都不做——也就是说,看到wait()但找不到notify(),则wait()之后的东西永远不会发生(假如可以正确编译的话)在wait时,线将程释放锁
a waiting thread will not return to runnable when the lock is released, unless a notification occurs
考虑:有时notify()可能会先于wait()而发生调用。这样notify()不会再发生,而后开始的wait()等不到结果。所以在等待之前,应当检查notify()是否已经发生。
阻止线程运行总结:
睡眠:睡眠指定的时间,醒来时是可运行状态,也即不保证醒来就是运行状态;sleep()是一个静态方法,因此在不能有一种做法可以让一个线程使另一个线程睡眠——当前运行线程的代码看到sleep()时,即刻睡去
等待:
因为需要一个对象的锁定而被阻塞

============一点建议===============

初学的几本书
mcgraw hill的scjp5 guide。这本书总结了很多容易犯错误或者难以真正理解的地方,当然这一点跟它“考试辅导”的身份有着密切关联,一些地方会专门为考试来讲解。但它仍然是一本很好的初学手册,顺利地读完并理解之后,就可以有比较充分的准备迈进java的大门了。要注意的是应当读英文原版而不是中文版,除非你对自己阅读逻辑混乱文不搭义的语句的能力充分自信,并且不在乎这样那样的翻译错误
o'reilly的java 1.5 tiger。配合tij来看吧,大家读的tij大多都是3rd edition不是么
java puzzlers。能够全部弄清的话,很多概念就彻底理解了吧
最后,自然是thinking in java。我读了一遍,正准备重修一遍
其他如java 线程、java io等等具体领域的转本,不妨有一个全面的基础之后有选择地浏览

要注意的地方
我觉得java也好cpp也好,都要对体现语言特性的地方做到真正透彻的理解
对于java,诸如初学最容易轻视的引用、初始化与声明、值传递与引用传递、静态成员等地方,都不要留下疑惑
posted @ 2007-05-11 15:45 沧佰 阅读(170) | 评论 (1)编辑 收藏
仅列出标题