最近看 java 基础,偶然在图书馆看到 scjp 的书,何不趁复习基础的时候把 scjp6 证书拿下来,也验证一下自己复习的结果。上网搜索考试中心, 24 号打电话联系,本打算学习一个月左右去考试,没想到考试中心的说如果月底 12 月 1 号之前考试可以买到 600 元的考试券,超过了 11 月份考试费用按正常 1250 元交。于是决定在 11 月 30 号晚上参加考试,一方面节省考试复习时间,另一方面节省了考试费用。复习了短短 6 天,拿到 96 分,虽然是奔着 100 分去的, 60 题里面还是错了两道题。考试题目虽然不难,但是复习的过程却让用了两年多 java 的我对 java 基础知识有了进一步的加强。为巩固复习结果,特写以下一系列 java 基础知识相关内容。
Java 基础(一)
标识符:以 $,_ ,字母开始,不能以数字开始,长度任意。允许出现字符: $,_, 字母,数字。
编码约定:类,接口:首字母大写;方法,变量:首字母小写。常量:全大写
Java 源文件:
( 1 )有且仅有一个 public 类,若有 public 类,类名必和文件名相同,否则文件名可任意。
( 2 )注释可以随处出现。
( 3 ) if( 有 package){
package 必须在第一行
}else if (有 import ) {
Import 必须在第一行
}.
(4) 一个文件中允许有多个非 public 类
类
类修饰符:访问修饰符( public ,默认)和非访问修饰符( abstract , final , strictfp )
类访问: (1) 可以创建这个类的实例, (2) 可以继承这个类, (3) 访问类中的方法和变量。默认访问的类只能被同一个包中的类访问。
abstract 类不能被实例化, abstract 方法和 abstract 类必须同时标识。 Abstract 方法没有方法体。
Final 类不能被子类化。
Strictfp 类意味着类中的所有方法都是 strictfp 的。
abstract 和 final 修饰符不能同时出现。
接口
接口中的方法默认是 public abstract 的。接口中的变量默认是 public static final 的。
接口方法不能标识为:, private , protected ,static , final, strictfp, native 。
接口只能 extends 接口,并且可以 extends 多个接口。不能 implement 或者 extends class ,不能 implement 接口。
接口可以被 abstract 修饰。
类成员
类的成员访问:两种方式:( 1 )通过类的实例访问( 2 )子类是否可以拥有父类成员;成员访问修饰符:
public :( 1 )和( 2 )都可以。
private :( 1 )和( 2 )都不可以。 Private 方法不存在 override ,这点和 final 类似。
protected :( 1 )子类和父类在不同包中,子类不能通过父类的实例访问父类的 protected 成员 (2) 子类和父类在不同包中,子类可以通过继承直接访问父类的 protected 成员。 (3) 父类和子类在不同包中,第三个类不能通过子类的实例访问从父类继承的成员。
默认:子类和父类在同一个包中,子类可以访问父类的默认成员。子类和父类不在同一个包中,子类不能访问父类的默认成员。
局部变量不能有访问修饰符。
非成员访问修饰符
final 修饰方法:方法不能被 override 。
abstract 修饰方法:方法为抽象方法,方法所在类不能被实例化,必须被 override 。 Abstract 方法不能同时是 final 或者 private 的,也不能是 static 的。
synchronized 修饰方法:同步。
native 修饰方法: native 只能修饰方法,方法没有方法体。
Strictfp 修饰方法: strictfp 只能修饰类和非抽象方法。
可变参数: var-arg 参数必须是方法签名中的最后一个,且一个方法中只能有一个 var-arg 参数。类型 + 。。。 + 空格 + 形参名,其中空格可以省略。
构造函数
类没有显示创建构造函数,编译器默认为其创建一个无参数构造函数,否则编译器不会创建默认无参构造函数。构造函数不能有返回类型,必须和类同名。构造函数可以有访问控制修饰符,但是不能使用 static , final , abstract 修饰构造函数。可以创建与构造函数同名的方法。
构造函数第一句必须是 super 或者 this 。没有 this 不显示调用 super ,编译器自动插入 super() 调用。
接口没有构造函数,抽象类有。
构造函数只能通过 this 在构造函数中调用。构造函数名称必须和 new 一块用来创建对象。如果超类提供构造函数但不是默认的,子类构造函数必须显式 super 调用超类构造函数,否则超类必须提供无参构造函数。
初始化块
静态初始化块和静态变量在第一次类加载的时候执行,按照静态初始化块出现的顺序会运行一次静态初始,同时初始化静态变量。初始化块,实例变量初始化,构造函数是在创建类对象的时候运行,在调用了基类构造函数的 super 之后,初始化实例变量和初始化块(按照初始化块出现的顺序),最后是运行类的构造函数。如果在静态初始化块中出现错误, jvm 抛出 ExceptionInInitializationError 。静态初始化块和初始化块可以出现在方法和构造函数以外的任何地方。
垃圾收集
垃圾收集只涉及到堆。垃圾收集器目的收集不可达对象,运行时间不确定。当一个对象没有任何引用的时候符合垃圾收集条件,隔离岛也符合垃圾收集。通过 System.gc() 或者 Runtime.getRuntime.gc(), 来建议垃圾回收。
finalize :垃圾收集器删除对象的时候会自动执行 finalize 方法,由于删除对象的时间不定因此 finalize 方法何时执行也不能保证,不建议重写 finalize() 。对于每一个对象, finalize 方法将只执行一次,还可以导致该对象免于被删除。不能自动调用 super 的 finalize 方法。
变量
Java 中有两种类型变量:基本变量 char ( 2 个 byte ,无符号), boolean(1 个 byte) , byte(1 个 byte) , short(2 个 byte) , int(4 个 byte) , long(8 个 byte) , float ( 4 个 byte ), double(8 个 byte) ,引用变量:可以引用所声明类型和其子类型的任意对象。
变量的域:
静态变量:类中声明为 static 的变量,类加载的时候初始化。只能使用 final ,访问控制符修饰。
实例变量:类中没有声明为 static 的变量,对象创建的时候初始化。只能使用 final , transient , volatile 和访问控制符修饰。
局部变量:声明在方法中的变量。局部变量总是在栈上。只能使用 final 修饰。局部变量在使用之前必须初始化否则编译出错,局部变量没有默认值。局部变量可以隐藏实例变量,需在方法中使用 this 来解决命名冲突。
方法参数:声明在方法参数中的变量。
块变量:
变量修饰符
Final :变量的值一旦设定将不再修改。可以修饰静态,实例,局部,参数。
Transient :修饰实例变量。表明不被序列化。
Volatile :修饰实例变量。线程将实例变量的副本和主存中的副本保持一致。
Static 修饰符 :
修饰:静态方法,静态变量,静态类,静态初始化块。
静态方法不能访问实例方法或者实例变量,只能通过实例来访问。
不能修饰:接口,外部类,构造函数,方法内部局部类,内部类中的方法和实例变量,局部变量。
枚举
可以在类外,类中,但不能在方法中。可以把枚举看成一个类。类外枚举不能是 abstract , final , static 的。枚举的值是类中的 public static final 变量,这些变量的类型是枚举名称。因此枚举中存在构造函数,实例方法,实例变量。可以通过类似匿名内部类的方式重载实例方法。
方法重写
两小一大:访问修饰 >= 父类方法。返回类型《 = 父类方法。声明 exception 《 = ,少于等于父类方法。重写可以抛出任何运行时异常。重写只能是实例方法而不是 static 方法。
相同:方法名称同,方法签名同,返回类型同或者是父类方法返回类型的子类。
Private , final 方法不是重写。重写 final ,非 private 方法编译错误。 ” 重写 ”private 方法(或未从父类继承的方法),不叫重写,只是碰巧相似。
注意:基类引用子类对象,若基类定义了 check exception ,子类中没有定义,则基类引用调用方法时需要放在 try 中进行检查。
方法重载:
(1) 非重写,方法名相同的方法叫方法重载。
(2) 方法可以在一个类及其子类中重载。
(3) 方法匹配:加宽》装箱》 var-arg 。引用加宽依赖继承。包装器类型不存在加宽。编译器不可以将一个基本类型先加宽然后装箱。但是可以装箱后依赖引用加宽使用 Object 参数。 wide(long...x) , wide(Integer...x) , int i=5 ; wide(i) 将编译错误。
引用类型赋值:
(1) 向上转换永远正确。可以显式也可以隐式。
(2) 向下转换编译不会出现错误,运行时可能会出现 ClassCastException 。必须显示转换
(3) 不在同一个继承树上类型的引用转换出现编译错误。
(4) 引用赋值使两个引用指向同一个对象,可以通过传递引用改变对象状态, String 例外,因为 String 对象的状态永远不变。传递 String 类似传递基本变量,不能修改其值。
基本类型赋值:
(1) 任何字面整数总是 int 。编译器计算时可以决定的 int 值可以直接赋值。如: byte b=7 。或者 final byte b=3; final byte c=4; byte d=b+c; (ok) 。非编译器计算得到的 int 值赋值需要显示转换。如: byte b=3; byte c=4; byte d=b+c;(error) 。因为一个占用 int 或更短长度表达式的结果总是 int 。 b+c 将在运行时进行,赋值给 byte 需要显示转换。
(2) b+=c 和 b=b+c 不一样,前者不需要显示转换。
(3) 基本类型赋值。加宽可以隐式转换,收缩必须显示转换。
(4) 字面值为小数的类型自动为 double ,将其赋给 double 以外的基本类型必须显示转换。
(5) 字面值大于基本类型所能表达的最大值必须显示转换。
包装器和装箱
(1) 包装器构造函数:除了 Character 外,所有的包装器都提供两个构造函数,一个带要构造的基本类型。一个带要构造的 String 标识。注意: Boolean 中只有字符串是“ false ”忽略大小写或 null 时,值为 false 。否则任意字符串都是 true 。
(2) Static : valueOf 函数:除了 Character 外,所有包装器都提供 valueOf 函数,接受一个 string 参数。 4 种整形还提供带基数的 valueOf 。返回值为包装器类型。
(3) Static : parseXxx 函数,返回 6 中数值类型的 xxx 基本类型。四种整形还提供带基数的转换。
(4) Non-static : xxxValue : 6 种数值类型都有 6 种 xxxValue ,返回对应的 xxx 基本类型。
(5) Non-static : toString(), 继承自 Object 。将包装器类型转换为 String
(6) Static : toString ,将基本类型转换为 String 。 6 中数值类型提供。 Integer 和 Long 还提供基于基数的 toString 和 toXxxString()
(7) 装箱和取消装箱
使用装箱和取消装箱会自动在需要引用类型的时候装箱,需要基本类型的时候取消装箱。 Boolean , Character , Byte , Integer(-128-127) ,当他们的类型相同且值相同时他们总是 == 。
初始化 :
静态变量在类加载时候会自动初始化,实例变量在对象创建时候自动初始化,数组对象在创建之后,数组元素会自动初始化。自动初始化的规则:所有值类型为 0 , boolean 为 false ,引用为 null 。局部变量不会被自动初始化,必须被显式赋值,如果局部变量有条件显示赋值也会编译出错。
数组
数组声明不能有长度。初始化的时候必须指定长度。
创建数组:采用 new 类型 [length]; 创建数组。数组中的元素会被默认初始化。数组有一个 public 成员变量: length 。
数组初始化:( 1 )采用 for , length 循环,或者 jdk1.5 的 for 循环,初始化数组。( 2 )采用 {} 初始化数组 .(3) 使用 new type[ ]{ } 创建匿名数组,并赋值给数组,匿名数组不指定长度。
数组元素赋值:可以将任何可以隐式转换成数组声明类型的元素赋值给数组元素。
数组引用赋值:长度可以不一样。对于基本类型数组,数组声明类型必须一致。对于引用类型数组,可以将一个子类类型的数组引用赋值给一个父类类型的数组引用。数组维数必须一致。
运算符
赋值运算符:复合赋值运算符右边先运算
比较运算符: >,>=,<,<= 用于比较整数,浮点数,字符的任意组合。
== , != ,只涉及两个 bool 值,两个数值,或者相同类型的两个引用值。
不要将 == 和 = 混淆。 boolean 和 0,1 ,数值等不能够转换。比如 if(0) 不行。
枚举的相等性:只有当两个枚举变量的值一样时候才相等。
Instanceof 运算法:只有左边的对象和右边的类或接口有 is-a 关系时候才为 true ,并且他们之间符合继承关系,否则编译出错。 Null instanceof type 总是返回 false 。
+ , - , * , / 。 + 可以用来连接字符串。如果两个操作数有一个是字符串则结果为字符串,如果两个操作数都是数字,执行加法。
++ , -- ;
条件运算符
逻辑运算符: & , | , && , || , ^,! 。 && , || :短路运算符,只能使用 boolean 操作数。
true | true=true. True | false=true; false| false=false;
true&true=true; true&false=false; false&false=false;
true^true=false; false^true=true; false^false=false;
!true=false; !false=true;
流程控制
If else : 判断表达式结果必须是 boolean 或 Boolean 的。否则编译出错。
Switch case default break : default 不一定放在最后。 Case 后面的值必须编译的时候可以确定,是一个常量表达式。 Switch 表达式结果必须是 char , byte 。 short , int 或者枚举。 Case 常量必须和 switch 类型一致,而且值必须在 switch 类型能够表示的范围内,否则编译出错。
While , do while , for , for each , break , continue ,标签。
异常
try , catch , finally 。
Check exception : 编译器检查语句是否抛出 check exception ,必须放在 try , catch 中或者在函数前面声明 check exception ,否则编译出错。自定义的异常 extends Exception 都为 check exception 。如果从 catch 中抛出检查异常,必须在方法中声明该异常。
Runtime exception : 编译器不会检查,运行时 jvm 抛出异常。编译器不强制声明或者使用 try catch 处理。常见 Runtime exception : NullPointerException , ArrayIndexOutOfBoundsException , NumberFormatException , ClassCastException , IllegaArgumentException 。
异常通常由 jvm 抛出或者程序员 api 抛出。
断言
通常用来检查希望发生或者不希望发生的事情,主要用于 debug 。非常简单版本和简单版本。 Assert 后面必须是 boolean 值,第二个表达式是一个字符串,产生调试信息。
默认禁用断言。启用断言: java –ea ;禁用断言: java –da ;可以有选择的启用或者禁用断言。
不要使用断言对程序产生副作用。
String , StringBuffer , StringBuilder
String 是不可改变的对象,和基本类型相似。是 final 的,不可以被继承。创建 String 时首先会 check 常量池中是否已经有,如果有则将引用指向已经存在的字符串,否则在常量池中创建字符串,引用指向新字符串。
String s=”hello”; // 创建一个对象,一个引用
String s=new String(“hello”); // 创建两个对象 ( 一个在堆中,一个在常量池中),一个引用。
StringBuiler :非线程安全。 StringBuffer :线程安全。建议多使用 StringBuilder ,这样性能更加好。
文件
File
字符读写类
FileReader/FileWriter :构造函数 File , String
BufferReader/BufferWriter: 构造函数: Writer
PrintWriter :构造函数 File , String , OutputStream , Writer
串行化
ObjectOutputStream.writeObject();
OjbectInputStream.readObject();
串行化会自动串行化被引用的变量。如果引用变量的类型没有实现序列化则会有运行时异常: NotSerializableException 。如果引用变量的类型实现了序列化,引用类型被自动序列化。
标识为 transient 字段不被序列化,反串行化时被默认初始化赋值。 Static 字段不被序列化。
使用 readObject ()和 writeObject ()自己实现串行化操作。反串行化不会调用构造函数。
继承和串行化:
父类没有实现 Serializable 。子类反串行化时,继承的父类变量将被默认赋值而不是串行化期间所具有的值,因为父类的默认构造函数将会被调用,因此父类一定要定义默认无参数构造函数,否则反串行化不成功 。