Friday, February 27, 2009

Object类

在java中所有的对象都扩展自java.lang.Object类。Object类是Java程序中所有类的父类,每个类都直接或间接继承自Object类。

由于Object类是Java中所有类的父类。所以使用Object声明的名称,可以参考至任何的对象而不会发生任何错误,因为每个对象都是Object的子对象。

可以制作一个简单的集合类,并将一些自定义的实例加入其中

public class SimpleCollection {
private Object[] objArr;
private int index=0;

public SimpleCollection(){
objArr=new Object[10];
}
public SimpleCollection(int capacity){
objArr=new Object[capacity];
}
public void add(Object o){
objArr[index]=o;
index++;
}
public int getLength(){
return index;
}
public Object get(int i){
return objArr[i];
}

}



public class Foo1 {
private String name;
public Foo1(String name){
this.name=name;
}

public void showName(){
System.out.println("foo1 名称:"+name);
}

}


public class Foo2 {
private String name;
public Foo2(String name){
this.name=name;
}

public void showName(){
System.out.println("foo2 名称:"+name);
}

}

public class SimpleCollectionDemo {


public static void main(String[] args) {
SimpleCollection simpleCollection=new SimpleCollection();
simpleCollection.add(new Foo1("num.1 Foo1"));
simpleCollection.add(new Foo2("num.2 Foo2"));

Foo1 f1=(Foo1) simpleCollection.get(0);
f1.showName();

Foo2 f2=(Foo2) simpleCollection.get(1);
f2.showName();
}

}










在程序中,SimpleCollection对象可以加入任何类型的对象置其中,因为所有对象都是Object的子对象。从SimpleCollection指定索引取回对象时,要将对象的类型从Object转换为原来的类型,这样就可以实现对象上的方法

Object类定义了几个方法,包括
protected的 clone()、finalize()
public的equals()、toString()、hashCode()、notify()、notifyAll()、wait()、getClass()等
其中,notify()、notifyAll()、wait()、getClass()等方法被声明为final,所以无法重写






Object的toString()方法是对对象的文字描述,它会返回String实例。在定义对象之后可以重写toString()方法,为对象提供特定的文字描述,Object的toString()会默认返回类名称和十六进制的编码也就是返回:

getClass.getName()+’@’+Integer.toHexString(hashCode())

getClass()方法是Object中定义的方法,它会返回对象于执行时期的Class实例,再使用Class实例的getName()方法可以取得类名称;

hashCode()返回该物件的哈希码,哈希码由哈希函数计算得到,在数据结构上可用于数据的寻址。

equals()本身是比较对象的内存地址是否相等,可以定义自己的对象在什么条件下可视为相等的对象。在重写equals()方法时,建议同时重写hashCode()方法,因为在以哈希码为基础的环境中,需要比较两个对象是否为相同的对象时,除了使用equals()之外,还会依hashCode()方法来作判断

import java.util.Date;
public class Cat {
private String name;
private Date birthday;

public Cat(){}

public void setName(String name){
this.name=name;
}

public String getName(){
return name;
}

public void setBirthday(Date birthday){
this.birthday=birthday;
}

public Date getBirthday(){
return birthday;
}

public boolean equals(Object other){
if(this==other)
return true;

if(!(other instanceof Cat))
return false;
final Cat cat=(Cat) other;

if(!getName().equals(cat.getName()))
return false;
if(!getBirthday().equals(cat.getBirthday()))
return false;
return true;
}

public int hashCode(){
int result=getName().hashCode();
result=29*result+getBirthday().hashCode();
return result;
}

}

继承&多态

继承
在扩展某个类之后,可以一并初始化父类的构造函数,以完成相对应的初始化工作,这可以使用super()方法来达到,它表示调用基底类的构造 函数。super()必须在构造函数一开始就调用,在子类的构造函数中,如果不用super()指定使用父类中的哪个构造函数来初始,则默认会调用父类中 无参数的构造函数。

protected
保护的意思是表示存取该成员是有条件限制的。当将类的成员声明为受保护的成员之后,继承的类就可以直接使用这些成员,但这些成员仍然受到保护,不同包的对象不可以直接调用使用protected成员。




重写方法

从J2SE 5.0 开始,再重写方法时,可以重写返回值的类型。

不能重写static方法,一个方法要被重写,必须是非static的,如果子类中定义一个有同样签署的static成员,那不是重写,而是定义一个属于该类的static成员

Thursday, February 26, 2009

GarbageCollection

在C++中,使用new配置的对象,必须使用delete来清除对象,以释放对象所占据的内存空间。如果没有进行这个动作,若对象不断的产生,内存就会不断的被对象耗用,最后使得内存空间用尽。在C++中有析构函数,它会在对象被清除前执行,通常delete会在这个方法中被执行,然而如果不小心清除了尚在使用中的对象,则程序就会发生错误甚至整个崩溃

在Java中,使用new配置的对象,基本上也必须清楚以回收对象所占用的内存空间,Java提供垃圾回收机制,在适当的时候,Java执行环境会自动检查对象,看看是否有未被参考的对象,如果有 就清除,回收对象所占据的内存空间

在Java中无法得知垃圾回收的时间,它可能会在内存资源不足的时候,或是在程序执行空闲的时候,可以建议执行环境进行收集,但收集并不一定会马上执行。

Java中 没有析构函数,但有finalize()方法,它被声明为protected,finalize()方法会在对象被回收时执行,但不可以将它当做析构函数来使用,因为不知道对象资源何时被回收,所以也就不知道finalize()真正被执行的时间,也就无法立即执行所指定的资源回收动作。但可以使用finalize()来进行一些相关资源的清除动作,如果这些动作与立即性的收尾动作没有关系的话。

如果确定不再使用某个对象,可以参考在该对象的名称上指定null,表示这个名称不再参考至任何对象,不被任何名称参考的对象将会被回收。
可以使用System.gc()建议程序进行垃圾收集,如果建议被采纳。则对象资源会被回收,回收前会执行finalize()方法。

递归

Recursion 是在方法中调用自身同名方法,而调用者本身会先被置入内存堆栈中,等到被调用者执行完毕之后,再从堆栈中取出之前被置入的方法继续执行。

辗转相除法求最大公因子:
package Encapsulation;
import java.util.Scanner;
public class TestRecursion {

public static void main(String[] args) {
Scanner s=new Scanner(System.in);

System.out.println("输入两个数:");
System.out.print("m= ");
int m=s.nextInt();
System.out.print("n= ");
int n=s.nextInt();

System.out.println("GCD: "+gcd(m,n));

}

private static int gcd(int m,int n){
if(n==0)
return m;
else
return gcd(n,m%n);

}

}




可以使用递归求解的程序,实际上也可以用循环来求解。
由于递归本身有重复执行与内存堆栈的特性,所以若在求解时需要使用到堆栈性的数据结构时,使用递归在设计的逻辑会比较容易理解,程序代码设计出来也会比较简洁。然而递归会有方法调用的负担,因而有时会比使用循环求解时效率低,但循环求解时若使用到堆栈,通常在程序代码上会比较复杂。

不定长度参数

J2SE 5.0 之后开始支持不定长度参数

会当作数组来处理
注意,声明的参数必须设置在参数行的最后一个。

编译器在处理重载方法、装箱问题和不定长度参数时,会依下面的顺序来寻找符合的方法
1. 寻找在还没有装箱动作前可以符合参数个数与类型的方法
2. 尝试装箱动作后可以符合参数个数与类型的方法
3. 尝试设有不定长度参数并可以符合的方法
4. 编译器找不到合适的方法,报告编译错误。

static

静态成员属于类所有,可以在不使用名称参考下,直接使用类名称加上“.”运算符来存取静态域成员,不过静态域成员同样遵循public、 protected 、private的存取限制。所以要想直接存取静态域成员,必须注意它的权限。

静态数据与静态方法的作用通常是为了提供共享的数据或工具方法方法

由于静态成员属于类而不属于对象,所以当调用静态方法时,并不会传入对象的参考,即静态方法中不会有this参考名称。由于没有this名称,所以在java的静态方法中不允许使用非静态成员。因为没有this来引用至对象,也就无法辨别要存取的是哪一个对象成员。

Java在使用到类时才会加载类至程序中。如果在加载类时,希望先进行一些类的初始化动作,可以使用static定义一个静态区块,并在当中编写类载入时的初始化动作。
在类被加载时,预设会先执行静态区块中的程序代码,且只会执行一次

this

使用引用名称来调用对象的方法成员时,程序会将对象的引用告知方法成员,而在方法中所编写的每一个域成员其实会隐含一个this引用名称,这个this名称引用自调用方法的对象。

每一个类的方法成员都会隐含一个this引用名称,可用来指向调用它的对象。当在方法中使用域成员时,都会隐含的使用this名称,当然也可以明确的指定

参数名称与域成员名称相同时,必须明确的使用this名称来指定,但如果参数名称与域成员名称不相同时则不用特别指定。

This 除了用来引用自调用方法的实际对象之外,还有一种可以带参数的用法,只要用于调用构造函数,而避免直接以构造函数的名称来调用。

Regular Expression

public class RegularExpressionT1 {

public static void main(String[] args) {
String test="abcdebcadxbc";
String[] tokens=test.split(".bc");
for(String token : tokens){
System.out.print(token+" ");
}
System.out.println();

tokens = test.split("..cd");
for(String token : tokens){
System.out.print(token+" ");
}
System.out.println();

}

}

Saturday, February 21, 2009

StringBuilder

一个String对象的长度是固定的,不能改变它的内容,或者附加新的字符至String对象中。虽然可以使用“+”来达到附加的目的,但这种方法会产生新的String实例

自J2SE 5.0 开始提供java.lang.StringBuilder类,使用这个类所产生的对象默认会有16个字符的长度,但也可以自行指定初始长度。如果附加的字符超过可容纳的长度,则StringBuilder对象会自动增加长度以容纳被附加的字符。StringBuilder被设计为与StringBuffer具有相同的操作接口。在单机非多线程(Multithread)的情况下使用StringBuilder会有较好的效率,StringBuffer则会处理同步问题,如果在多线程下操作,则要改用StringBuffer,让对象自行管理同步问题。

如果有频繁作字符串附加的需求,使用StringBuilder会让程序的执行效率大大提高
toString()、length()、capacity()、insert()、deleteChar()、reserve()、

使用String的split()来分隔数据
public class TestSplit {

public static void main(String[] args) {
String[] s={"j\tu\ts\tt\t","d\to\t","i\tt"};
for(String ss:s){
String[] tokens=ss.split("\t");
for(String token:tokens){
System.out.print(token+"\t");
}
System.out.println();
}
}

}

Ps:StringTokenizer——Legacy Class

String

1. 字符串的本质是字符类型的数组,也是String类的一个实例
2. 用“+”连接
3. length()、equals()、toLowerCase()、toUpperCase()
4. Byte.parseByte(Str)、Short.parseShort(Str)、Integer.parseInt(Str)、Long.parseLong(Str)、Float.parseFloat(Str)、Double.parseDouble(Str)
5. char charAt(int index)、int indexOf(int ch)、int indexOf(String str)、int lastIndexOf(int ch)、String substring(int beginIndex)、String substring(int beginIndex,int endIndex)、char[] toCharArray()
6. endsWith()
7. immutable
一个字符串对象一旦被设置,它的内容就是固定不可变的
在java执行时会维护一个String池,对于一些可以共享的字符串对象,会先在pool中查找是否存在相同的String内容,如果有就直接返回,而不是直接创造一个新的String对象,以减少内存的耗用。



8. String intern()



Eg:

Friday, February 20, 2009

Array

1. 数组的索引值为什么由0开始

索引值表示的是:所指定的数组元素相对于数组第一个元素内存位置的位移量。索引为0表示位移量为0,因此指的是第一个元素。



2. “=”运算用于基本数据类型时,是将值复制给变量,但当它用于对象时,则是将对象指定给引用名称来引用。
Eg:

public class TestArray {

public static void main(String[] args) {
int[] arr1={1,2,3,4,5};
int[] arr2=arr1; //不是将数组进行复制,而是将其名称与指定的对象绑定

arr1[0]=7;
for(int i=0;i
System.out.print(arr2[i]);

}

}


输出:

72345



3. 数组复制のSystem.arraycopy()

System.arraycopy(来源,起始索引,目的,起始索引,复制长度)



4. 数组复制のcopyOf()
Eg
package Array;
import java.util.*;
public class TestCopyOf {

public static void main(String[] args) {
int[] arr1={1,2,3,4,5};
int[] arr2=Arrays.copyOf(arr1, arr1.length);

arr1[0]=0;
for(int i=0;i
System.out.print(arr2[i]);
}

}


copyOf方法返回的是新的数组对象



5.Arrays类

equals()
sort()
binarySearch()
fill()



6.foreach

for(type element : array){
System.out.print(element);
}

autoboxing & unboxing

Primitive类型的autoboxing、unboxing是自J2SE 5.0 开始提供的功能

在Java中,所要处理的东东几乎都是Object,然而Primitive数据类型不是对象(int、double、boolean)

有时候需要将基本数据类型转换为对象,此时就要用到打包类型(Wrapper Types)
使用一下语句将int包装为一个Integer对象:
Integer integer = new Integer(100);
在J2SE 5.0 之后提供了自动装箱的功能,以上语句可简化成:
Integer integer = 100;
同样的动作可以适用于boolean、byte、short、char、long、float、double等基本数据类型,分别会使用对应的打包类型Boolean、Byte、Short、Character、Long、Float、Double。
也可以使用更一般化的java.lang.Number类来完成自动装箱:
Number number = 3.14f;
3.14f 会先被自动装箱为Float,然后指定给number

从I2SE 5.0 开始可以自动装箱和拆箱
eg:
Integer numInteger = 100;
int numPrimitive = numInteger;

设置path & classpath

一、 设置path

在JDK安装目录(假设是C:\Program Files\Java\jdk1.6.0_12)下的bin目录中
该目录会提供一些开发Java程序时必备的工具程序

设置方法の设置系统变量中的path环境变量:
在Windows XP下,可选择桌面上的“我的电脑”图标 —— 单击鼠标右键 —— 选择“属性”选项卡 —— 然后切换至“高级”页面 —— 单击下方的“系统变量”按钮,在系统变量中单击“新建”编辑path变量




变量值里填入JDK bin目录的路径(假设是C:\Program Files\Java\jdk1.6.0_12\bin)后跟一个分号,作为路径设置的分隔——即C:\Program Files\Java\jdk1.6.0_12\bin;
单击“确定”





值得注意的是:
1. 若不是第一次设置path变量(原系统变量中本身就存在path变量),那么当你再次设置时,要将新的path路径写在最前面。因为操作系统在搜索path路径位置时,会从最前方开始读取,如果在路径下找到指定的程序,就会直接执行。当您的系统中装有两个以上JDK时,path路径中的设置顺序,将决定执行哪个JDK下的工具程序
2. 设置path变量后要重新打开命令提示符窗口(如果你要在命令提示符下操作程序的话)使系统重新读取path变量的内容

我们可以打开一个命令提示符窗口,(“开始”——“运行”——输入“cmd”——回车)执行javac命令 ,来检验一下我们的path变量是否已经生效
应该能看到下图的画面:






二、 设置 Classpath

设置classpath的目的在于让java执行环境找到指定的java程序(即 .class文件)
其实,JDK 6 默认就会到当前工作目录,以及JDK的lib目录中寻找Java程序。所以,如果java程序是在这两个目录中,则不必设置Classpath变量也可以找到,如果您的java程序没有放在这两个目录中,那么就需要设置Classpath了

设置方法の设置系统变量中的Classpath的值
类似于path的设置,
变量名为:Classpath,
变量值为java类文件的位置


总的来说,
设置Classpath的目的是通知java执行环境,在哪些目录下可以找到您所要执行的java程序,对于Windows系统而言,path是让系统可以找到.exe执行程序的所在,
对于java执行环境而言,Classpath是让JVM可以找到.class执行程序的所在。

Thursday, February 19, 2009

了解JDK

其实JDK本身也有自己的JRE,假设JDK安装至 C:\Program Files\Java\jdk1.6.0_12
这个JRE就位于JDK安装目录的jre目录下,及C:\Program Files\Java\jdk1.6.0_12\jre
JDK本身所带的JRE主要用于测试开发的java程序,它与公用JRE差不多,可以比较C:\Program Files\Java\jdk1.6.0_12\jre\bin 与 C:\Program Files\Java\jre6\bin (假设公用JRE安装至C:\Program Files\Java\jre6)其主要差别在于JDK本身所带的JRE比公用JRE多了个server 选项

(JDK本身所带的JRE——图1)

(公用JRE——图2)

server 与 client两者的差别在于所使用的VM不同,执行Java程序时默认会使用client VM。如果使用server VM会花比较长的启动时间,并消耗掉较多的内存——为使该程序获得较好的执行效果。


简单的介绍一下目录中的一些重要文件(我知道的也不多)





bin —— 提供JDK工具程序,包括javac、java、javadoc、等程序
demo —— 一些使用java 编写好的范例程序
jre —— 如前所述
db —— 纯Java编写的数据库,支持JDBC 4.0
lib —— 在执行javac.exe等程序时,会调用lib中的tools。jar中的对应类。
scr.zip —— API类源代码的压缩文件

JDK的安装

双击下载后的JDK安装文件,假设是jdk-6u12-windows-i586-p.exe ,点击运行,同意使用条款,然后开始安装。

开发工具是必须的
演示程序及样例——可供以后写程序时参考
源代码——指的是API源代码,使使用者了解API是如何编写的
公共JRE——主要是为开发好的java程序提供执行的平台,是执行程序所必要的
Java DB——支持JDBC 4.0 的一系列新功能和属性(java se 6 的新增功能)

安装到——显示了JDK默认的安装目录,请留意此目录,因为以后在改环境变量时需要用到这个信息,也可点击“更改”按钮来改变安装目录。
点击“下一步”进行JDK的安装。






再点击“下一步”
进行公共JRE的安装

最后,出现成功安装界面,点击“完成”





Wednesday, February 18, 2009

JDK的下载

下载地址:

http://java.sun.com/javase/downloads/index.jsp

可以看出最新版本是JDK 6

Sun公司会在必要时候公布修正版本,以修正一些bug,修正版本将以Update为前缀,后续号码来表示修正的版本号。

JDK 6 中包括了公用JRE安装选择,所以不必额外下载JRE 6

按下 JDK 6 Update 12 Download 的链接

选择您的操作平台,勾选 I agree to the Java SE Development Kit 6 License Agreement



点击Continue


可以直接点击 jdk-6u12-windows-i586-p.exe 下载

也可以使用网站提供的下载工具下载