奉陪了

博客园 首页 联系 订阅 管理

java初学者实践教程1-配置环境变量

    实践:

    鼠标单击 开始――>运行――> cmd,进入了DOS的窗口。我们在任意目录下敲QQ.会出现  “ 'QQ' 不是内部或外部命令,也不是可运行的程序或批处理文件。”这段话

    其实也是啊,在当前的目录根本就没有QQ这个文件啊。我的QQ程序安装在 D:\Tencent\QQ 下了。你们做的时候找到这个目录。在dos下进入这个目录,再敲QQ.就会发现弹出了QQ的登陆窗口。那么怎样能使,我们在任何目录下都可以敲QQ就可以 执行呢。那就是设置环境变量了。

    实践:

    我们现在桌面上,右键单击 我的电脑――>属性――>选择“高级”选卡――>环境变量。

    现示的结果如图1-1

 
 
 
     图  1-1

    环境变量分为两类,一个是上半部分区域用户变量,另一个是下半部分系统变量。用户变量是只适用于当前用户使用,换了用户就不管用了。而系统变量则是任何用 户都可以使用。呵呵,这样说可以理解吧。  我们现在在用户变量里面按“新建”。在变量名里面输入path(不区分大小写)

    变量值里面输入你QQ的安装路径,我的QQ安在了 D:\Tencent\QQ 所以你们按照自己的来做哦。

 

    图 1-2

    然后一路按“确定”按钮。接着,新打开一个DOS窗口。切记,一定要新打开一个DOS窗口,用原来的是不行的。这回在任意的目录下,敲QQ 回车。就会发现弹出窗口了。大家做出来了吗?

    所以现在我来做一下总结性陈词:环境变量相对于给系统或用户应用程序设置的一些变量, 具体起什么作用这当然和具体的环境变量相关。 象path, 是告诉系统, 当要求系统运行一个程序而没有告诉它程序所在的完整路径时, 系统除了在当前目录下面寻找此程序外, 还应到那些目录下去找。当然还有很多的变量啊!以后我们会慢慢的学到。

    说了这么多,我们开始开始正式的配置jdk吧!马上就可以敲出java代码了。

    实践:

    1、在sun公司的官方网站下载jdk.或者在百度或 google搜索jdk下载。安装jdk;

    2、在“用户变量”中,设置3项属性,JAVA_HOME,PATH,CLASSPATH(大小写无所谓),若已存在则点击“编辑”,不存在则点击“新 建”;

    3、JAVA_HOME设为JDK的安装路径(如C:\Program Files\Java\jdk1.5.0_11),此路径下包括lib,bin,jre等文件夹(此变量最好设置,因为以后 运行tomcat,eclipse等都需要依靠此变量);

    Path使得系统可以在任何路径下识别java命令,设为:%JAVA_HOME%\bin

    CLASSPATH为java加载类(class or lib)路径,只有类在classpath中,java命令才能识别,设为:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib(要 加。表示当前路径) %JAVA_HOME%就是引用前面指定的JAVA_HOME.形如 图1-1

    4、打开一个DOS窗口,输入“java -version”。

    看看出现了,一大堆的版本信息就说明已经配置成功了。配置已经成功了,我们如何使用jdk呢?

java初学者实践教程2-jdk的使用

通过上一节的学习,相信大家已经能够学会如何配置环境变量了。如果还有问题请联系“百家拳软件项目研究室”或者到我们的论坛交流 bbs.100jq.com.接下来,我们继续进行吧!

    这节我们首先体验一下用java编写的程序。也让大家过把代码瘾,呵呵。目前世界上大部分的软件教程有一个习惯,最开始时总要输出一个字符串 “HelloWorld”。我们也是不能免俗啊,也要输出这么一段话。

    实践:

    1、单击“开始”――>运行――>CMD,进入DOS系统。

    2、用cd命令进入一个你容易找到的目录。如图2-1

 
 
     图2-1

    3、输入命令notepad Hello.java 用记事本创建并打开一个java文件。如图2-2

 
 
     图 2-2

    4、在里面输入下列代码

    /*
    简单的 HelloWorld 程序
    */

    public class  Hello{
    //main方法
    public static void main (String args[]) {
    System.out.println ("Hello World!"); //输出字符串“Hello World!”
    }
    } 

    本例子源代码,点击此处下载

    5、在DOS的界面里,敲javac  Hello.java 编译这个文件。会发现文件夹里多了一个Hello.class的文件。如图2-3

 
 
     图 2-3

    6、最后一步,还是在DOS的界面里,敲 java Hello 观察结果。

    相信你已经看到结果了吧!

    总结

    通过上述几个步骤我们体验了java代码原来是这么编写和运行的啊。那么具体这些东西是什么意思呢?

    javac是jdk的编译器,刚才我们输入javac  Hello.java的时候意思是把把Hello.java这个源文件编译成了字节码,就是Hello.class这个文件。

    Java命令是 java的解释器 java Hello的意思是将编译后的字节码放在解释器上执行。 从中我们也可以看到java语言的执行过程,是先编译后解释的。

    JDK里面还有许多命令呢!下面我们来全面了解一下JDK.JDK的命令为4类。有基本命令,RMI命令,国际化命令,安全控制命令。在这里我只介绍些,有代表性的命令。刚才那两个javac和java已经说过了。

    他们是基本命令,基本命令里还有jar命令,也是很常用的。Jar命令是java类的归档命令。Jar命令可将多个文件合并为单个JAR归档文件。Jar 是个多用途的存档及压缩工具,它基于zip和zlib压缩格式。说的通俗一点就是它是把java的类文件,即*.class文件打包用的。我们来做个例 子,

    实践:

    1、在刚才那个目录的DOS窗口里敲jar  cvf  hello.jar Hello.class

    2、观察结果。如图2-4

 
 
     图 2-4

    看看有没有生成一个叫做hello.jar的文件,用winrar打开有没有Hello.class这个文件呢?如果有的话就好了,其实jar命令还可以 打很多格式的包哦。上一节我们配置JDK的时候,是不是把CLASSPATH里面配置了一个lib的目录,那里面也有很多jar包。所以说jar命令,是 大家要掌握的一个命令。

    下一个介绍国际化的命令,JDK里只有一个这样的命令native2ascii,该命令将本地编码字符(既非Latin-1,又非Unicode字符)的 文件,转换为Unicode编码字符文件。这是一个处理多国语言字符的命令,都转换为Unicode编码了,就容易处理了。这样开发国际化的软件,是非常 方便的。

    实践:

    1、在任意目录里面建立两个文件,一个叫gb2312.txt,另一个叫ascii.txt

    在gb2312.txt里面输入“百家拳软件项目研究室”这段话。之后保存。

    2、在dos里面进入文件所在的目录。敲 native2ascii -encoding gb2312 gb2312.txt ascii.txt .

    3、打开ascii.txt看看是什么结果呢?里面的有很多符号吧

    \u767e\u5bb6\u62f3\u8f6f\u4ef6\u9879\u76ee\u7814\u7a76\u5ba4 这些就是

    “百家拳软件项目研究室”这段话的Unicode编码。

    好了这节课介绍了java代码的编写和jdk的一些命令。相信大家应该有所了解了吧!但是我们要学习一门技术的话,也不能只会编hello world啊。下一节我们将介绍java语言的基础

java初学者实践教程3 - 基本语法1

上回课,我们学习了并实践操作了一个Hello World的例子,大家显然是没有解渴。不过,回过头来有些同学问了。“你写了一大堆,是出字了。不过我不明白是什么意思啊!

    这个不用着急。下面我为大家解释一下这段程序。

 

    1 /*
    2 简单的 HelloWorld 程序
    3 */
    4 public class  Hello{
    5  //main方法
    6  public static void main (String args[]) {
    7  System.out.println ("Hello World!"); //输出字符串“Hello World!”
    8  }
    9 } 

 

    程序中的1-3 行是注释行

    /*
    简单的 HelloWorld 程序
    */

    “/*……*/”是多行注释,而“//”是单行注释的意思。

    第4行

    声明类名为Hello,保存时要以Classname.java保存。类名(Classname)是在源文件中指明的,源文件编译后可在源代码所在的目录 里生成一个classname.class 文件。在本例题中,编译器创建了一个称为Hello.class 的文件, 它包含了公共类Hello 的编译代码。

    public class Hello{

    第5行是一个单行注释

    第6行

    是程序执行的起始点。Java 技术解释器必须发现这一严格定义的点,否则将拒绝运行程序。C和C++语言,也采用main()做为程序的起 点。但是与java有些不同,以后的课程会介绍的。

    第7行

    声明如何使用类名、对象名和方法调用。它使用由System 类的out 成员引用的PrintStreamout对象的println()方法,将字串“Hello World!”打印到标准输出上。

    System.out.println (“Hello World!”);

    分号“;”是java语言语句的分隔符

    第8-9行

    那两个花括号是分别和第4行和第6行的花括号配对

    数据类型的概述

    数据类型对于任何一门计算机语言来说都是重要的,因为变量的数据类型决定了如何将代表这些值的位存 储到计算机的内存中。在java语言里,数据类型分为两大类:

    一、基本数据类型。
    二、复合数据类型(对象数据类型)。

    基本数据类型又分4类8种。如下:

    u 逻辑型:boolean.

    u 文本型:char.

    u整 型:byte,short,int和long.

    u浮 点型:double和float.

    复合数据类型就有很多种了,他们都是从Object这个类继承下来的。

    下面我想重点的讲一个问题:

    文字类型的char和String,这两个都是文本类型。但是不同之处,

    1、char是基本数据类型,而String不是,但是String是非常有用的。

    2、char是一个16位的unicode(国际码)字符,用单引号引上。例如,

    char c = '100jq’;

    String是一个类。字符串在java里是对象。在java SE 5中有三个类可以表示字符串:

    String,StringBuffer和StringBuilder.StringBuilder是jdk1.5的特性,在jdk1.5之前的版本中没 有。字符串要放在双引号中。字符串中的字符也是Unicode .String对象表示的字符串是不能修改的。如果要对字符串修改,应该使用StringBuffer和StringBuilder类。

    实践:

    public class Assign {
    public static void main (String args []) {

    // 声明整数型变量
    int x,y;

    // 声明并赋值给一个单精度浮点数变量
    float z = 3.414f;

    // 声明并赋值给一个双精度浮点数变量
    double w = 3.1415;

    // 声明并赋值给一个布尔类型的变量
    boolean truth = true;

    // 声明字符型变量
    char c;

    // 声明字符串型变量
    String str;

    //声明并赋值给一个字符串型变量
    String str1 = "bye";

    // 为字符型变量复值
    c = 'A';

    // 给字符串型变量赋值
    str = "Hi out there!";

    // 给整型变量赋值
    x = 6;
    y = 1000;
    }
    } 

    错误的赋值举例:

    y = 15.454; //y是个整型数

    w = 456;   //w是个双精度数

    将这个程序用上节课的方法,编译执行。就可以看到结果了。

    这是基本数据类型的例子 点击此处下载

    这节课,我们基本了解了java的数据类型的知识。也知道了基本数据类型的概念。但是对象型的数据呢?java是面向对象的语言啊,光靠基本数据类型也无 法描述客观的世界啊。因为我们不可能说,桌子、椅子是整数,还是字符。所以对象型的数据类型是非常必要的,也是理解面向对象概念的基础之一。请看下节

java初学者实践教程4- 基本语法2

上节课给大家留下一个问题,计算机要描述的是现实世界。光有基本数据类型,是不能满足我们的需要的。在这个大千世界里,任何东西都可以看做成对象,它们当 然不能都是整数和文字了。现在学习java的同学,一般会看到一些java的教程里写的一个日期的例子。这个例子是个典型的例子。你们想啊,日期里面有很 多属性啊,像是年,月,日。基本类型的数据就不能很好的描述它。就像是人,是一个类型。人有很多属性,头,躯干,四肢,这样的话,我们就更难用基本类型来 描述了。

    我们还是看看这个日期的例子吧!

    public class MyDate {
    private int day; //日
    private int month; //月
    private int year;  //年
    public MyDate(int day,int month,int year){
    this.day   = day;
    this.month = month;
    this.year  = year;
    }

    public MyDate(MyDate date) {
    this.day   = date.day;
    this.month = date.month;
    this.year  = date.year;
    }

    public int getDay() {
    return day;
    }

    public void setDay(int day) {
    this.day = day;
    }

    public MyDate addDays(int more_days) {
    MyDate new_date = new MyDate(this);
    new_date.day = new_date.day + more_days;
    return new_date;
    }

    public void print() {
    System.out.println("MyDate: " + day + "-" + month +    "-" + year);
    }
    } 

    在上次课的那个例子里我们已经看到了,class关键字后面是个类名。这个类名就是MyDate.MyDate 这个类里面定义了3个属性,4个方法,2个构造函数。因为还没有讲到这些概念,目前说还是有点超前。我还是先来讲些理论的东西。

    理论阐述:

    类描述了同一对象都具有的数据和行为。Java语言中的类将这些数据和行为 进行封装,形成了复合数据类型。创建一个新类,就是创建了一种新的数据类型。在程序中,类只定义一次,而用new运算符可以实例化同一个类的一个或多个对 象。比如人是一个类,每一个人就是一个对象。那当然是人定义一次,对象可以new出很多对象了。但是这些具体的人,都具有同样的特征(数据和行为)。

    Java的类里面有3个东西,看下面:

    class 类名 {
    声明属性;
    声明构造函数;
    声明方法;
    }

    刚才讲了,类不是要描述现实的数据和行为吗?在这里属性就是要描述封装的数据,方法就是描述行为。构造函数嘛,是在new的运算符后面的,当然是构造对象 的了,要不怎么能叫构造函数呢!

    顺便说一下,那两个属性的前面有一个private 那是权限修饰符。意思是私有的也就是别人不能用。Java语言用这种权限修饰符实现封装。不想C语言的结构体,都是公有的属性,那样是不安全的。就像是人有五脏六腑,那些东西就是私有的。怎么能让谁都碰呢?这就是面向对象的一个重要的概念叫做封 装。面向对象一共有三个重要特征(封装,继承,多态)我们以后会学到的。

    所以,刚才MyDate那个类里面,有3个属性 int类型的day,month,year .4个方法

    setDay(int day),getDay() , addDays(int more_days), print()。还有两个构造函数。

    看下面的例子如何调用这个类的方法的:

    public class TestMyDate {
    public static void main(String[] args) {
    MyDate my_birth = new MyDate(22, 7, 1964); //通过第一个构造函数new了一个叫my_birth的对象,并在参数里面赋值

    MyDate the_next_week = my_birth.addDays(7); //这个对象调用了addDays(int more_days)的方法,赋值给the_next_week的变量
    the_next_week.print(); //调用print()方法
    }
    } 

  点击此处下载源码

    调用一个类的方法,实际上是进行对象之间或用户与对象之间的消息传递。

    实践:

    1、  编译上述两个类 ,直接编译TestMyDate.java就行。还记得怎么做吗?进入DOS界面,到你存放这两个文件的目录下,敲javac TestMyDate.java

    2、  然后敲 java TestMyDate 就OK了。

    观察结果

    总结:

    今天我们理解了对象类型的数据类型,也知道了对象和对象之间的调用方式。

    再为大家提供些代码吧。点击此处下载

java实践教程5-基本类型和引用类型变量

  上两次课我们知道了,java语言中的两种数据类型。这节课呢,我们对上两次课做一个补充,也加深一下理论知识的学习。理论的东西是很有用的啊。这节课介 绍基本类型变量和引用类型变量。

    Java中数据类型分为两大类,上次课已经讲完了,是基本类型和对象类型。相应的,变量也就有两种类型:基本类 型和引用类型。基本类型自然不用说了,它的值就是一个数字,一个字符或一个布尔值。引用类型,可是引用类型呢?它是一个对象类型的啊,值是什么呢?它的值 是指向内存空间的引用,就是地址,所指向的内存中保存着变量所表示的一个值或一组值。很好理解吧,因为一个对象,比如说一个人,不可能是个数字也不可能是 个字符啊,所以要想找它的话只能找它的地址了。

    罗唆:

    我们在学习计算机的过程中,所谓的难的东西,就是以前没有听过的概念,和不常用的思想。像是这个引用类型的概念就是以前不常用的,基本类型当然好理解不讲 大家也知道。所以我们对于这样陌生的概念我们只要多琢磨一下就会明白的。

    我们废话少说,接下来看看这两种类型变量的不同处理吧。基本类型自然是简单,声明是自然系统就给它空间了。例如,

    int baijq;  
    baijq=250; //声明变量baijq的同时,系统给baijq分配了空间。

    引用类型就不是了,只给变量分配了引用空间,数据空间没有分配,因为谁都不知道数据是什么啊,整数,字符?我们看一个错误的例子:

    MyDate today;

    today.day = 4; //发生错误,因为today对象的数据空间未分配。

    那我们怎么给它赋值啊?引用类型变量在声明后必须通过实例化开辟数据空间,才能对变量所指向的对象进行访问。举个例子:

    MyDate today;            //将变量分配一个保存引用的空间

    today = new MyDate();     //这句话是2步,首先执行new MyDate(),给today变量开辟数据空间,然后再执行赋值操作。

    小总结:

    刚才说了一大堆,其实就是一件事。如果是引用类型的变量,必须先得new一个对象出来。不new哪来的对象啊,不new哪有数据空间啊?没有数据空间怎么 能访问呢?这回明白了吧!

    我们还有个问题没有说,引用类型变量怎么赋值?这个就不是很难了。举个例子:

    MyDate a,b;                       //在内存开辟两个引用空间

    a  =  new MyDate();    //开辟MyDate对象的数据空间,并把该空间的首地址赋给a

    b  =  a;                      //将a存储空间中的地址写到b的存 储空间中

    如图5-1

 
 
 

全新java初学者实践教程6(Java SE5.0版)---- 基本语法3

java初学者实践教程6--程序流程控制

这节课我们又要讲语法了,这是“百家拳软件项目研究室”这部教程的第6节课,我们这个教程侧重的是实践的内容和语言的重点。在java语言中还有很多细节 的东西,请参考sun公司的官方培训教程。我们这里不能一一讲述。这节课我们来给大家提供一些程序流程控制的一些例子供大家学习。计算机怎么做事情,是我 们教给他的。我们用它解决实际生活中的问题,所以计算机要描述现实生活中的流程。

    Java语言中提供了4类程序控制语句,来描述流程:

    1.循环语句:while,do-while,for

    2.分支语句:if-else,switch,

    3.跳转语句 break,continue,label: 和return

    4.异常处理语句:try-catch-finally,throw

    实践:

    1.循环语句

    while 语句

    class While {
        public static void main(String args[]) {
            int n = 10;
            while(n > 0) {
                System.out.println("tick " + n);
                n--;
            }
        }
    }

    do…while 语句

    class DoWhile {
        public static void main(String args[]) {
            int n = 10;
            do {
                System.out.println("tick " + n);
                n--;
            } while(n > 0);
        }
    }

    二者区别,do…while至少循环一次,而while的表达式要是为flase的话可以一次也不循环。再通俗一点,do…while就算是括号里的是 flase,人家最少也能do一次。

    for语句

    class ForTick {
        public static void main(String args[]) {
            int n;
            for(n=10; n>0; n--)
                System.out.println("tick " + n);
            }
    }

    与上面那两个的区别,for循环执行的次数是可以在执行之前确定的。通俗一点说吧,看这个例子 for(n=10; n>0;n--)就是在括号里的时候,就已经知道要循环10次了。

    还有啊,for循环的部分可以为空的

    class ForVar {
        public static void main(String args[]) {
            int i;
            boolean done = false;
            i = 0;
            for( ; !done; ) {
                System.out.println("i is " + i);
                if(i == 10) done = true;
                i++;
            }
        }
    }

   下载 href="http://java.chinaitlab.com/download/07070418157115.rar" target=_blank>循环语句的例子下载

    2.分支语句

    if/else语句

    class IfElse {
        public static void main(String args[]) {
            int month = 4; // April
            String season;
            if(month == 12 || month == 1 || month == 2)
                season = "Winter";
            else if(month == 3 || month == 4 || month == 5)
                season = "Spring";
            else if(month == 6 || month == 7 || month == 8)
                season = "Summer";
            else if(month == 9 || month == 10 || month == 11)
                season = "Autumn";
            else
                season = "Bogus Month";
            System.out.println("April is in the " + season + ".");
        }
    }

    //这段程序输出:

    //April is in the Spring.

    // 注意 “||”是或运算 

    switch语句

    class Switch {
        public static void main(String args[]) {
            int month = 4;
            String season;
        switch (month) {
        case 12:
        case 1:
        case 2:
            season = "Winter";
            break;
        case 3:
        case 4:
        case 5:
            season = "Spring";
            break;
        case 6:
        case 7:
        case 8:
            season = "Summer";
            break;
        case 9:
        case 10:
        case 11:
            season = "Autumn";
        break;
    default:
            season = "Bogus Month";
        }
    System.out.println("April is in the " + season + ".");
        }
    }

  下载 href="http://java.chinaitlab.com/download/07070418161030.rar" target=_blank>分支语句代码下载

    switch语句适合于条件非常多的逻辑

    请看上述语句可以混合使用,请看下载例子

java初学者实践教程7-跳转语句

上一节我们说有4类程序控制语句,但是才讲了2个。今天讲跳转语句。异常处理语句我们找一节专题来讲。

    循环跳转语句 :

    break [label]  //用来从语句、循环语句中跳出。

    continue [label]  //跳过循环体的剩余语句,开始下一次循环。

    这两个语句都可以带标签(label)使用,也可以不带标签使用。标签是出现在一个语句之前的标识符,标签后面要跟上一个冒号(:),标签的定义如下:

    label:statement;

    实践:

    1  break语句

class Break {

public static void main(String args[]) {

boolean t = true;

first: {

second: {

third: {

System.out.println("Before the break.");

if(t) break second; // break out of second block

System.out.println("This won't execute");

}

System.out.println("This won't execute");

}

System.out.println("This is after second block.");

}

}

    // 跳出循环

class BreakLoop {

public static void main(String args[]) {

for(int i=0; i<100; i++) {

if(i = = 10) break; // terminate loop if i is 10

System.out.println("i: " + i);

}

System.out.println("Loop complete.");

}

下载 href="http://java.chinaitlab.com/download/07070515349394.rar" target=_blank>5个break跳出循环的例子下载

    //跳出switch

class SampleSwitch {

public static void main(String args[]) {

for(int i=0; i<6; i++)

switch(i) {

case 0:

System.out.println("i is zero.");

break;

case 1:

System.out.println("i is one.");

break;

case 2:

System.out.println("i is two.");

break;

case 3:

System.out.println("i is three.");

break;

default:

System.out.println("i is greater than 3.");

}

}

 

这个在昨天的分支语句中,我们就已经学到了。

    2、  continue语句

class Continue {

public static void main(String args[]) {

for(int i=0; i<10; i++) {

System.out.print(i + " ");

if (i%2 = = 0)  continue;

System.out.println("");

}

}

    //带标签的continue

class ContinueLabel {

public static void main(String args[]) {

outer: for (int i=0; i<10; i++) {

for(int j=0; j<10; j++) {

if(j > i) {

System.out.println();

continue outer;

}

System.out.print(" " + (i * j));

}

}

System.out.println();

}

下载 href="http://java.chinaitlab.com/download/07070515403787.rar" target=_blank>此例子打包下载

java初学者实践教程8—jdk5的拆箱与装箱

前几次课的讲解,我们了解了这样几个问题。Java的两种数据类型,和一些程序 控制语句。今天,我们还是要通过一些例子。对上述东西有一个更深的理解。

    我们现在知道了,所有对象型的数据类型的基类是java.lang.Object .而写java程序的时候非常多的工作都是在写这些类,和实现里面的方法。而偏偏就有那么8种基本类型和他们不一样。以至于让你来回在这两种之间转换,这 是很让人头疼的事情。Java中int,long,char这样的类型不是对象型。因此java里提供了一种叫做包装类 (wrapper)的东西,使基本类型,有着相应的对象类型Integer,Long,Character等。这样就可以,先把基本类型的东西,转成对象 来用,然后再转回去。来来回回,千锤百炼。

    到了jdk5.0的时候呢,就不用了。看下面的例子:

实践:

public class Test1 {

    public static void main(String[] args) {

        // 装箱

        int i = 0;

        Integer integer = i;//i这么一个 基本类型的数,可以赋值给Integer型的变量

        // 简单的拆箱

        int j = integer; //integer这种原始 类型的数,也能赋值给j这个原始类 型的变量

 

        Integer counter = 1;        // 装箱

        int counter2 = counter;     // 拆箱

 

        while (counter < 100) {

          System.out.println("计数 "+counter++);  //看啊,counter这个对象 型的数,还能自动增加

        }

    }

    在幕后JVM已经自动执行了转换,同理Boolean和boolean之间也可以,自动拆箱装箱。但是,Integer和int毕竟还是有着不同的。

    看下面例子:

public class Test2 {

    public static void main(String[] args) {

       Integer i1 = 256;

        Integer i2 = 256;

        if (i1 = = i2)

        System.out.println("相等!");

        else

        System.out.println("不相等!");

    }

 

    结果输出的是“不相等!”,两个对象比较,它们在内存中开辟的是两个地址怎么能相等呢?

    警告:你可千万不能依赖这个结果,请把i1和i2的值,改成100.(请看Test3.java)看看什么结果,令人惊讶的是改了个数,居然输出了“相 等!”。

    这是因为JVM可以选择要尝试这段代码的最佳优化,并对两个Integer对象使用一个实例,这样的话“= =”就会返回true了。在自动装箱时对于值从–128到127之间的值,使用一个实例。

    这种装箱与拆箱机制对,程序流程控制语句,也有很大影响:

public class Test4 {

    public static void main(String[] args) {

        Boolean arriving = true;

        Integer peopleInRoom = 0;

        int maxCapacity = 100;

 

        while (peopleInRoom < maxCapacity) {

          if (arriving) {

            System.out.printf("很高兴见到你.%d号先生\n",peopleInRoom);

            peopleInRoom++;}

          else {

            peopleInRoom--;

          }

      }}} 

    另外一个从unboxing获得好处的语句是switch.在jdk5.0之前的JVM,switch接受int、short、character或者 byte值,而在unboxing的操作中,你现在也可以为它赋予新引入的enum之外的Integer,Short,Char以及Byte值。Enum 的值,我们在后面的教程会详细讲述。

下载 href="http://java.chinaitlab.com/download/07070611056052.rar" target=_blank>上述例子打包下载

java初学者实践教程9-数组

今天我们讲个不一样的概念――数组,数组也没什么不好理解的,就是一组数。不过这组数有点特性。今天 我们的任务就是,了解这个有特性的这组数。下面我们具体讲一下它有哪些特性:

1、数组中的元素是同一类型。数组的长度在创建 时确定,并且在创建后不变。解释一下 声明一个数组 int i[5]; 这就是int类型,名字叫i的数组。里面的数都必须是int类 型。并且长度在创建时确定了是5。

     2、在java语言中,数组就是一个对 象,所以创建数组与创建对象一样也是用new关键字来创建。举个例子,s = new char[20]; p = new Point[50];

     3、数组在被创建后,其元素被系统自动初始化了。 字符元素被初始化为'\u0000’,而对于对象数组都被初始化为null。 如果你不初始化的 话,在内存是找不到它的位置的。

     4、数组中的第一元素记做第0个,i[0]是数组i 的第一个元素。

     说了这么些,我们还是得练练啊

实践:

public class TestArrays {

  public static void main(String[] args) {

    // 第1,2步: 声明并初始化数组变量

    int[]  array1 = { 2, 3, 5, 7, 11, 13, 17, 19 };

    int[]  array2;

 

    // 第3步: 显示数组初始化值

    System.out.print("array1 is ");

    printArray(array1);

    System.out.println();

    // 第4步: array2引用array1

    array2 = array1;

    // 更改array2

    array2[0] = 0;

    array2[2] = 2;

    array2[4] = 4;

    array2[6] = 6;

    // 打印array1

    System.out.print("array1 is ");

    printArray(array1);

    System.out.println();

    // 第5步: 声明一个整数类型的二维数组

    int[][] matrix = new int[5][];

    // 第6步: 将这个矩阵构成三角形

    for ( int i = 0; i < matrix.length; i++ ) {

      matrix[i] = new int[i];

      for ( int j = 0; j < i; j++ ) {

       matrix[i][j] = i * j;

      }

    }

    // 第7步打印矩阵

    for ( int i = 0; i < matrix.length; i++ ) {

      System.out.print("matrix[" + i + "] is ");

      printArray(matrix[i]);

      System.out.println();

    }

  }

  public static void printArray(int[] array) {

    System.out.print('<');

    for ( int i = 0; i < array.length; i++ ) {

      // 打印一个元素

      System.out.print(array[i]);

      // 输出最后一个元素的时候不输出逗号

      if ( (i + 1) < array.length ) {

       System.out.print(", ");

      }

    }

    System.out.print('>');

  }

}  

 

    在jdk5.0中,我们发现了一些更 简单的方法,打印一维数组时,用toString(array)方法,

打印二维数组时,用deepToString(array)方法。这样的话就剩了我们又是循环又是判断的。我们看个例子吧:

实践:

import java.util.Arrays;

public class ArraysTester {

  private int[] ar;

 

  public ArraysTester(int numValues) {

    ar = new int[numValues];

    for (int i=0; i < ar.length; i++) {

      ar[i] = (1000 - (300 + i));

    }

  }

  public int[] get() {

    return ar;

  }

  public static void main(String[] args) {

    ArraysTester tester = new ArraysTester(50);

    int[] myArray = tester.get();

    // 比较两个数组

    int[] myOtherArray = tester.get().clone();

    if (Arrays.equals(myArray, myOtherArray)) {

      System.out.println("这两个数组是相等的!");

    } else {

      System.out.println("这两个数组是不相等的!");

    }

    // 填上一些值

    Arrays.fill(myOtherArray, 2, 10, new Double(Math.PI).intValue());

    myArray[30] = 98;

    // 打印数组

    System.out.println("这是一个未排序的数组...");

    System.out.println(Arrays.toString(myArray));

    System.out.println();

    // 数组排序

    Arrays.sort(myArray);   

    // 打印被排序的数组 用toString()

    System.out.println("这是一个被排序的数组...");

    System.out.println(Arrays.toString(myArray));

    System.out.println();

 

    // 得到特殊值的索引

    int index = Arrays.binarySearch(myArray, 98);

    System.out.println("98 被定位在第 " + index + "个位置上");

 

    String[][] ticTacToe = { {"X", "O", "O"},

                             {"O", "X", "X"},

                             {"X", "O", "X"}};

    //打印二维数组用deepToString()

    System.out.println(Arrays.deepToString(ticTacToe));

    String[][] ticTacToe2 = { {"O", "O", "X"},

                              {"O", "X", "X"},

                              {"X", "O", "X"}};

    String[][] ticTacToe3 = { {"X", "O", "O"},

                              {"O", "X", "X"},

                              {"X", "O", "X"}};

    if (Arrays.deepEquals(ticTacToe, ticTacToe2)) {

      System.out.println("Boards 1 和 2 相等.");

    } else {

      System.out.println("Boards 1 和 2 不相等.");

    }

    if (Arrays.deepEquals(ticTacToe, ticTacToe3)) {

      System.out.println("Boards 1 和 3 are 相等.");

    } else {

      System.out.println("Boards 1 和 3 are 不相等.");

    }

  }

此源码和其它例子打包下载

java初学者实践教程10-集合类

上次课我们学过了数组,知道它只是一组数(或是对象),但是有些自己的特性。在java里还有一类东西与数组类似,也是有着特性的一组数(或是对象),叫 做集合类。我们上节课讲到了,数组的长度在创建时已经确定了,但是有时候我们事先根本不知道长度是多少啊,比如我们做电子商务网站时,有个购物车程序。你 总不能用数组规定,人家只能买5样东西吧。你就是把长度定为10000也不行,万一遇上个特别有钱的呢!呵呵,这只是开玩笑的。我们会使用集合类解决这个 问题。

    集合类是放在java.util.*;这个包里。集合类存放的都是对象的引用,而非对象本身,为了说起来方便些,我们称集合中的对象就是指集合中对象的引 用(reference)。引用的概念大家不会忘了吧,在前边我们讲数据类型时讲的。

    集合类型主要有3种:set(集)、list(列表)、map(映射)和Queue(队列)。//队列为jdk5中的加上的

    (1)    Set

    集(set)是最简单的一种集合,它的对象不按特定方式排序,只是简单的把对象加入集合中,就像往口袋里放东西。对集中成员的访问和操作是通过集中对象的 引用进行的,所以集中不能有重复对象。我们知道数学上的集合也是Set这个,集合里面一定是没有重复的元素的。

    (2)List

    列表(List)的主要特征是其对象以线性方式存储,没有特定顺序,只有一个开头和一个 结尾,当然,它与根本没有顺序的Set是不同的。它是链表嘛,一条链肯定有顺序这个顺序就不一定了。

    (3)Map

    映射(Map),这个在java里不是地图的意思,其实地图也是映射哈。它里面的东西是键-值对(key-value)出现的,键值对是什么呢?举个例 子,比如我们查字典,用部首查字法。目录那个字就是键,这个字的解释就是值。键和值成对出现。这样说可以理解吧。这也是很常用的数据结构哦。

    (4)Queue

    在jdk5.0以前,通常的实现方式是使用java.util.List集合来模仿Queue.Queue的概念通过把对象添加(称为enqueuing 的操作)到List的尾部(即Queue的后部)并通过从List的头部(即Queue的前部)提取对象而从 List中移除(称为dequeuing的操作)来模拟。你需要执行先进先出的动作时可以直接使用Queue接口就可以了。

    这4个东西,有时候功能还不太完善,需要有些子类继承它的特性。Set的子接口有TreeSet,SortedSet,List的有ArrayList 等,Map里有HashMap,HashTable等,Queue里面有BlockingQueue等。我们来看看例子吧:

    实践:

Set举例

       import java.util.*;

public class SetExample {

                           public static void main(String[] args) {

                         Set set = new HashSet();  //HashSet是Set的子接口

                         set.add("one");

                         set.add("second");

                         set.add("3rd");

                         set.add(new Integer(4));

                         set.add(new Float(5.0F));

                         set.add("second");

                         set.add(new Integer(4));

                         System.out.println(set);

                           }}  

List举例:

           import java.util.*;

public class ListExample {

                                  public static void main(String[] args) {

                                List list = new ArrayList();

                                list.add("one");

                                list.add("second");

                                list.add("3rd");

                                list.add(new Integer(4));

                                list.add(new Float(5.0F));

                                list.add("second");

                                list.add(new Integer(4));

                                System.out.println(list);

                           }} 

Map举例

import java.util.Map;

import java.util.HashMap;

import java.util.Iterator;

import java.io.FileReader;

 

public class MapExample {

                    public static void main(String[] args)  throws java.io.FileNotFoundException {

                                Map word_count_map = new HashMap();

                                FileReader reader = new FileReader(args[0]);

                                Iterator  words = new WordStreamIterator(reader);

 

                                while ( words.hasNext() ) {

                                      String word = (String) words.next();

                                      String word_lowercase = word.toLowerCase();

                               Integer frequency = (Integer)word_count_map.get(word_lowercase);

if ( frequency == null ) {

                                   frequency = new Integer(1);

                               } else {

                                   int value = frequency.intValue();

                                          frequency = new Integer(value + 1);}

                                      word_count_map.put(word_lowercase, frequency);

                                }

                                System.out.println(word_count_map);

                                  }} 

Queue举例:

import java.io.IOException;

import java.io.PrintStream;

import java.util.LinkedList;

import java.util.Queue;

 

public class QueueTester {

  public Queue<String> q; //发现了一个奇怪的语法,这个尖括 号是泛型声明

                      public QueueTester() {q = new LinkedList<String>();}

public void testFIFO(PrintStream out) throws IOException {

                                q.add("First");

                                q.add("Second");

                                 q.add("Third");

                                Object o;

                         while ((o = q.poll()) != null) {

                               out.println(o);}}

             public static void main(String[] args) {

                  QueueTester tester = new QueueTester();

           try {  tester.testFIFO(System.out);

                         } catch (IOException e) {

                               e.printStackTrace(); } }} 

    下载 href="http://java.chinaitlab.com/download/07070811002751.rar" target=_blank>上述例子和一些相关例子(共6个例子)打包下载

    总结:

    刚才我们看了上述例子了,对集合类有了一个初步的认识,它们跟数组的区别不只是长度问题,在集合类里面放进去的类型可以是任意的。不像数组,数组里面的类 型是一样的。这样的话,对于集合类来说即使好事,也是坏事。因为你不考虑类型可以随意的放,但是你放进去什么就不知道了不容易找。

    还有啊,什么叫泛型声明啊?我们下次课就告诉你。这可是jdk5的酷炫之处哦。

java初学者实践教程11-泛型声明

 上节课我们留下了一个泛型声明的概念,这个概念乍一听起来是很陌生的,不过不要紧,听我细细道来。 泛型声明就是泛泛的声明类型。我们用其它的语言做一个比较:

   Javascript声明变量: var i= 1;var c = 'char ’

   VB 声明变量:      dim i=1;dim c=’char’

   Perl 声明变量:      $i = 1; $c = 'char’

     这些脚本语言,在声明变量的时候,根本就不想java那样还得声明类型。他们的类型已经自己声明完了,是泛泛的声明的,这些语言本身就是泛型。因为数据类型可能会改变,所以用不着像java定的那么死。但是数据类型可不是说变就变的,java的 强类型机制,保证了逻辑的严谨性,而且确保着程序员犯错误,这是java的 优点。同时使得它开发起来没有上述语言那样简单,一点小事上做起来都很笨拙。这是其中一个方面,另一个方面如我们上节讲的java的集合类里面的类型是不确定的,放什么都行啊。这样的话你明明自己放进去的类型,也就是说你自己已经知道类型了,拿出来的时候,还 得不断的转换。我们在介绍拆箱与装箱机制的时候已经说过这个类型的问题了。拆箱与装箱确实能解决不少问题但那是不够的。

    所以接着上节课学集合类的劲头,趁热打铁。我们讲一下刚才说的第二个方面,关于集合类的问题。我们刚 才说,java这种类型安全之下的破绽,我们要用泛 型的方式来弥补。我们来实践一个例子。

实践:

import java.io.IOException;

import java.io.PrintStream;

import java.util.HashMap;

import java.util.Iterator;

import java.util.LinkedList;

import java.util.List;

import java.util.Map;

public class GenericsTester {

  public void testTypeSafeMaps(PrintStream out) throws IOException {

    Map<Integer, Integer> squares = new HashMap<Integer, Integer>();

 

    for (int i=0; i<100; i++) {

      squares.put(i, i*i);

    }

    for (int i=0; i<10; i++) {

      int n = i*3;

      out.println(n + "的平方是" + squares.get(n));

    }

  }

//测试安全的链表

  public void testTypeSafeLists(PrintStream out) throws IOException {

    List listOfStrings = getListOfStrings();

    for (Iterator i = listOfStrings.iterator(); i.hasNext(); ) {

      String item = (String)i.next();

    }

    List<String> onlyStrings = new LinkedList<String>();

    onlyStrings.add("Legal addition");

    /**

     * Uncomment these two lines for an error

    onlyStrings.add(new StringBuilder("Illegal Addition"));

    onlyStrings.add(25);

     */

  }

  public void testTypeSafeIterators(PrintStream out) throws IOException {  //初始化迭代

    List<String> listOfStrings = new LinkedList<String>();

    listOfStrings.add("Happy");

    listOfStrings.add("Birthday");

    listOfStrings.add("To");

    listOfStrings.add("You");

 

    for (Iterator<String> i = listOfStrings.iterator(); i.hasNext();) {

      String s = i.next();

      out.println(s);

    }

    printListOfStrings(getListOfStrings(), out);

  }

//得到普通链 表

  private List getList() {

    List list = new LinkedList();

    list.add(3);

    list.add("Blind");

    list.add("Mice");

    return list;

  } 

  //得到安全的链表

  private List<String> getListOfStrings() {

    List<String> list = new LinkedList<String>();

    list.add("Hello");

    list.add("World");

    list.add("How");

    list.add("Are");

    list.add("You?");

    return list;

  }

  public void testTypeSafeReturnValues(PrintStream out) throws IOException {

    List<String> strings = getListOfStrings();

    for (String s : strings) {

      out.println(s);

    }

  } //接受参数化类型的链表

  private void printListOfStrings(List<String> list, PrintStream out)

    throws IOException {

    for (Iterator<String> i = list.iterator(); i.hasNext(); ) {

      out.println(i.next());

    }

  }

  public void printList(List<?> list, PrintStream out) throws IOException {    for (Iterator<?> i = list.iterator(); i.hasNext(); ) {

      out.println(i.next().toString());

    }

  }

  public static void main(String[] args) {

    GenericsTester tester = new GenericsTester();

    try {

      tester.testTypeSafeLists(System.out);

      tester.testTypeSafeMaps(System.out);

      tester.testTypeSafeIterators(System.out);

      tester.testTypeSafeReturnValues(System.out);

 

      List<Integer> ints = new LinkedList<Integer>();

      ints.add(1);

      ints.add(2);

      ints.add(3);

      tester.printList(ints, System.out);

    } catch (Exception e) {

      e.printStackTrace();

    }

  }

 此例子打包下载

在List和Map类的后面有个<>的参数,这个参数表示集合类里面的元素类型。List<String>就是表示,List里面的元素都是String类型的。这样我们就可以在事先确定List的类型了,省着大家一起做项目的时候。只知道List里面有什么还得问写的那个人,你 同事写完了还得给你讲那里面是什么。这回你看着方法名就全知道了。关于泛型的概念还有很多我们不能一下子讲完,以后的教程我们会详细讲解。

java初学者实践教程13-面向对象之多态

上节课我们了解了比较重要的概念面向对象,和java的OOP有封装、继承、多态的特征。但是什么叫做多态,是很多初学者不容易理解的问题。对于继承来 说,很容易理解因为你就看字面的意思就知道它是继承着父类的特性。多态字面不容易理解了。下面我们具体讲一下吧!

    类之间的继承关系使子类具有父类的所有变量和方法,=> 父类所具有的方法也可以在它所有子类中使用,发给父类的消息也可以发送给子类 => 子类的对象也是父类的对象=>子类的对象既可以做本身的类型,也可以做父类的类型。 呵呵,上述推导公式好像绕口令似的。我们举个例子理解上述概念。举例:

    public class 动物 //动物是父类

    public class 猫 extends 动物 //猫是子类

    动物的所有特性在猫中可以使用,发给动物的信息猫也能收到=>猫的对象new 猫();既可以作为本身的类型 猫 a=new 猫(); 也可以作为父类的类型 动物 b = new 猫();这样说理解了吗?如有疑问请访问我们的技术论坛。

    如果大家明白了的话,我们就可以从上述公式推导出结论,所有的子类都可以作为父类的类型(同一种类型)来对待。像刚才那个动物有很多子类啊,可以有很多对 象。动物 a=new 猫();动物 b=new 狗(); 动物 c=new 猪();。这样的将子类型的对象引用转换成父类型的对象引用,叫做上溯造型(upcasting)。

    我们再来引伸一下,我们在数组那节课里讲了,数组存放的元素是相同类型的数据,但是上溯造型使得java允许创建不同类型对象的数组。例如:

    Employee[] staff = new Employee[3];

    staff[0] = new Manager();

    staff[1] = new Secretary();

    staff[2] = new Employee(); 

    夷?这是怎么回事啊,数组里面不是相同类型吗?对啊,因为Sectetary和Manager是Employee的子类,所以也可以通过上溯造型变成 Employee啊。以前我们还学到了所有对象都是从java.lang.Object 继承下来的。如果数组要是 Object型的话 Object[] obj=new Object[];那就是里面放什么对象都行了。因为什么对象都可以是Object型的。

    实践:

// java中的多态

class Shape {

  void draw() {}

  void erase() {}

}

//圆形

class Circle extends Shape {

  void draw() {

    System.out.println("Circle.draw()");

  }

  void erase() {

    System.out.println("Circle.erase()");

  }

}

//正方形

class Square extends Shape {

  void draw() {

    System.out.println("Square.draw()");

  }

  void erase() {

    System.out.println("Square.erase()");

  }

}

//三角形

class Triangle extends Shape {

  void draw() {

    System.out.println("Triangle.draw()");

  }

  void erase() {

    System.out.println("Triangle.erase()");

  }

}

public class Shapes {

  public static Shape randShape() {

    switch((int)(Math.random() * 3)) {

      default:

      case 0: return new Circle();

      case 1: return new Square();

      case 2: return new Triangle();

    }

  }

  public static void main(String[] args) {

    Shape[] s = new Shape[9];

    // 向数组里添加类型

    for(int i = 0; i < s.length; i++)

      s[i] = randShape();

    // 用多态的方法调用

    for(int i = 0; i < s.length; i++)

      s[i].draw();

  }

 下载 href="http://java.chinaitlab.com/download/07071111096057.rar" target=_blank>上述源码下载

    Java的多态性,有什么意义呢?它的突出优点是使程序具有良好的扩展性。它通过继承,可以派生出任意多个新类 型,或向基类增加更多方法时,无须修改原有对基础类进行处理的相关程序。就是扩展性好。

    我们返回再看面向对象(专指OOP)的这三个特性封装、继承、多态三者的关系。没有封装就没有继承,没有继承就没有多态。

java初学者实践教程14-垃圾收集器

用过C++编程的人知道,编的时候总是要跟踪所创建的对象,并且需要显示地删除不用的对象。这种方式太麻烦了,容易 出错。写了那么多代码,能记住吗,要是把有用的给删了怎么办,要是有没用的忘删了怎么办?这些问题是很严重的。在java语言中采用的垃圾收集器这种方式 管理内存,就很方便也很安全了。垃圾收集器,可以自 动确定哪个对象不再被利用,它可以自动将它删除。这也是java语言的一大优势。

    我们要想显示的删除一个对象的引用也很简单,将该引用的变量赋值为null不就行了吗?对于垃圾收集器来说,当程序员创建对象时,垃圾收集器就开始监控这 个对象的地址、大小以及使用情况。通常,垃圾收集器采用有向图的方式记录和管理堆(heap)中的所有对 象。通过这种方式确定哪些对象是“可用的”,哪些对象是“不可用的”。当垃圾收集器确定一些对象为“不可用”时,垃圾收集器就回收这些内存空间。

    可是垃圾收集器却以较低的优先级在系统空闲周期中执行,通俗一点说就是它级别低,别人不运行时候才轮到它,因此垃圾收集器的速度比较慢。有些时候我们会使 用System.gc()。手动回收。这样来提高性能。

    对于垃圾收集器来说还有一个值得一提的是finalize()这个方法,每一个对象都有一个finalize( )方法,这个方法是从Object类继承来的。它用来回收内存以外的系统资源,就像是文件处理器和网络连接器。该方法的调用顺序和用来调用该方法的对象的 创建顺序是无关的。换句话说,书写程序时该方法的顺序和方法的实际调用顺序是不相干的。这只是finalize( )方法的特点。还有,每个对象只能调用finalize( )方法一次。如果在finalize( )方法执行时产生异常(exception),则该对象仍可以被垃圾收集器收集。那是一定了,不能说用到finalize()了。垃圾收集器就什么也不做 了啊。finalize()的工作量是很大的哦

    总结:

    Java用了垃圾收集器的内存管理方式,并不是说它完全的好。有的时候会影响它的性能,我们还是要手动来收集 的。但是要是像C++那样完全手动来收集的话,那也实在是太麻烦了而且不是很安全

    根据垃圾收集器的工作原理,我们可以通过一些技巧和方式,让垃圾收集器运行更加有效率。

    1.最基本的建议就是尽早释放无用对象的引用。

    大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null.

    2.尽量少用finalize函数。finalize函数是Java提供给程序员一个释放对象或 资源的机会。但是,它会加大垃圾收集器的工作量,因此尽量少采用finalize方式回收资源。

    3.当程序有一定的等待时间,程序员可以手动执行System.gc(),通知垃圾收集器运行,但是Java语言规范并不保证垃圾收集器一定会执行。

java初学者实践教程15-方法的重载与重写

  Java语言中 的概念就是多,这回又有两个概念,重载和重写。这是两个新概念,也是两个令初学者容易混淆的概念。他们的概念截然不同,只不过都有个“重”字,就以为是很 像的。

 

下面解释一下这两个概念:

    方法重载(overloading method) 是在一个类里面,方法名字相同,而参数不同。返回类型呢?可以相同也可以不同。

    方法重写(overiding method) 子类不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。如果还是搞混的话,就把“重写覆 盖”,这个词多念几遍吧。知道是覆盖的话,就知道是子类覆盖父类的方法了。

 

实践: 重载的例子

public class MethodOverloading { 
void recieve(int i) { 
     System.out.println("接收一个int数据"); 
     System.out.println("i="+i); 
     } 
void recieve(float f) { 
     System.out.println("接受一个float型的数据"); 
     System.out.println("f="+f); 
     } 
     void recieve(String s) { 
     System.out.println("接受一个String型数据"); 
     System.out.println("s="+s); 
     }

public static void main(String[] args){

    MethodOverloading m = new MethodOverloading();

    m.recieve(3456);

    m.recieve(34.56);

m.recieve(“百家拳软 件项目研究室“);

}

   大家看到了上面的例子方法receive()有三个,名字相同参数不同。这样的话,在main()调用的时候,参数用起来就很方便了。重写的例子似乎不用举了,记不住的话,就和“覆盖”。一起念。 

    有时候,重载和重写的方式有些复杂,在jdk5里 面。有一些方式能简化一些。我们来看看吧,jdk5的可变参数。 如果把相同参数类型的方法重载好几遍真的是很烦。就一个方法,pri(String args), pri(String arg0 ,String arg1), pri(String arg0,String arg1,String arg2), pri(String arg0,String arg1,String arg2,String arg3)。这样的话会写很多烦琐的代码。现在jdk5可 以,用“…”来代替这些参数。

 

实践:

 

 public class overload {

//若干个相同类型的参数,用“...”代替

   public void pri(String... strings ){

       for (String str : strings)   //for这个循环语句也有迭代的意思

       System.out.print(str);

   }

   public static void main(String[] args){

       new overload().pri("100jq"," 百家拳软件项 目研究室"," www.100jq.com");

   }

 

   jdk5的方法重写,比以前多了一个叫做协变返回的概念。在以往jdk的版本中,还有一个比较让人讨厌的地方。方法重写确实是比较不错的机制,如果想用父类的方法,写个super就可以了,如果不想用父类的方法就重写覆盖。但是重写覆盖的返回类型不能覆盖,父类的类型不够用怎么办,我们想在子 类重写它的类型可以吗?现在可以了。

 

看下面的例子:

 

class Point2D { //定义二维的点

  protected int x, y;

  public Point2D() {

    this.x=0;

    this.y=0;}

  public Point2D(int x, int y) {

    this.x = x;

    this.y = y;

  }}

//定义三维的点,继承二维

class Point3D extends Point2D {

  protected int z;

  public Point3D(int x, int y) {

    this(x, y, 0);

  }

  public Point3D(int x, int y, int z) {

    this.x = x;

    this.y = y;

    this.z = z;

  }}

//定义二维的位置

class Position2D {

  Point2D location;

  public Position2D() {

    this.location = new Point2D();

  }

  public Position2D(int x, int y) {

    this.location = new Point2D(x, y);

  }

  public Point2D getLocation() {

    return location;

  }}

//定义三维的位置,继承二维的位置

class Position3D extends Position2D {

  Point3D location; //在这里已经变成Point3D的类型了

  public Position3D(int x, int y, int z) {

    this.location = new Point3D(x, y, z);

  }

  @Override  //注释是重写方法

  public Point3D getLocation() {

    return location; //返回是子类的类型而不是原来的类型了

  }

 代码打包下载

java初学者实践教程16-static关键字

这已经是本系列教程的第16次课了,在我们前几次课的基础上,我们继续学习一下java的语法。这回我们,讲static关键字。

 

    static关键字可以用来 修饰类的变量,方法和内部类。static是静态的意思,也是全局的意思它定义的东西,属于全局与类相关,不与具体实例相关。就是说它调用的 时候,只是ClassName.method(),而不是new ClassName().method()。new ClassName()不 就是一个对象了吗?static的变量和方法不可以这样调用的。它不与具体的实例有关。

 

实践:

 

 

class Count {

    private int serialNumber;

    public static int counter = 0; //一个静态变量counter

    public Count() {

       counter++;   //创建Counter的时候递增

       serialNumber = counter;}

    public int getSerialNumber(){

       return serialNumber;

    }}

class OtherClass {

    public int increment(){

       return Count.counter++;//静态的变量不属于任何实例只能直接用类调用

    }}

public class TestStaticVar {

    public static void main(String[] args){

       Count[] cc = new Count[10];

       OtherClass o = new OtherClass();

       for (int i=0;i<cc.length;i++){

           cc[i] = new Count();

           System.out.println("cc["+i+"].serialNumber = "+cc[i].getSerialNumber());

           System.out.println(o.increment());

       }}} 

查看结果

 

    类的方法中带有static关键字,这个方法就是静态方法。静态方法也是要通过类名,而不是实例访问。

 

实 践:

 

class GenerealFunction {

    public static int add(int x,int y){

       return x+y;

}}

public class UseGeneral {

    public static void main(String[] args){

       //调用时还是用类直接调用

       int c = GenerealFunction.add(19,18);

         System.out.println("结果是"+c);

}} 

    注意:子类不能重写父类的静态方法哦,也 不能把父类不是静态的重写成静态的方法。想隐藏父类的静态方法的话,在子类中声明和父类相同的方法就行了。

 

    前一阵子有同学问了,main()是什么意思啊?main()的前面不是也有一个static吗,它也是静态方法。它是程序的入口点,就是说java的程序是由java虚拟机执行的,java语言和虚拟机的入口就是main()。因为它是static的,这可以使JVM不创建实例对象就可以运行该方法。因此我们在main()中调用别的类的非静态方法,就要 创建实例。像上面的例子:OtherClass o = new OtherClass();

System.out.println(o.increment()); 不用实例o去调用是不行的。

前面我们已经见到很多这样的例子了。

 

大家看一个错误的例子:

int x;

public static void x() {

    x = 15; //这个是错误的,x是非静态变量

}

static 还可以修饰程序块 用{}括起来,用法与上述两种方法相同

public class StaticInit {

  public static int count = 1;

  static {

    count = Integer.getInteger("myApplication.counter").intValue();

  }

 

 上述源码下载

java初学者实践教程17-final关键字

  上一节学了static关键字,这一节接着学习final关键字。final关键字有三个东西可以修饰的。修饰类,方法,变量。

    详细解释一下:

    1、在类的声明中使用final

    使用了final的类不能再派生子类,就是说不可以被继承了。有些java的面试题里面,问String可不可以被继承。答案是不可以,因为 java.lang.String是一个final类。这可以保证String对象方法的调用确实运行的是String类的方法,而不是经其子类重写后的 方法。

    2、在方法声明中使用final

    被定义为final的方法不能被重写了,如果定义类为final的话,是所有的方法都不能重写。而我们只需要类中的某几个方法,不可以被重写,就在方法前 加final了。而且定义为final的方法执行效率要高的啊。

    3、在变量声明中使用final

    这样的变量就是常量了,在程序中这样的变量不可以被修改的。修改的话编译器会抱错的。而且执行效率也是比普通的变量要高。final的变量如果没有赋予初 值的话,其他方法就必需给他赋值,但只能赋值一次。

    总结:

    这个关键字并不是很难理解,final的英文意思是“最终的”。他修饰了什么东西都是最终的。不可以改变的。效率也比较高。通常在java的优化编程中往 往会提及到这一点。

java初学者实践教程18-抽象类和接口

  Java语言中允许有一种叫做抽象方法的东西,他只是一个名字没有具体的实现。像是这样: public abstract void abc(); 使用了abstract关键字,结尾用“;”结束。与前几节我们用的方法都是具体方法,是有实现的。哪怕方法体中什么也不写public void abc() { } 也是具体方法。概念:包含一个或多个抽象方法的类称为抽象类。抽象类也必须声明abstract关键字。抽象类的使用有着一些限制,不能创建抽象类的实 例。如果子类实现了抽象方法,则可以创建该子类的实例对象。要是子类也不实现的话,这个子类也是抽象类,也不能创建实例。

    接口是什么东西呢?接口是比抽象类更抽象的类。举例: public interface Name { }接口里面的方法全都是抽象的,里面的变量全都是final的常量,而且实现接口的类必须将所有的抽象方法全部实现。抽象类里也可以有具体的方法。所以 说,接口是最抽象的,其次是抽象类,而具体类本身就是对现实世界的抽象。软件开发本身就是将现实世界抽象成计算机世界。

    因为抽象类和接口比具体类抽象,所以使用时他们总是被继承而被实现的。不过继承他们的类不只是一个,有很多类实现他们的抽象方法。一个方法有多种实现方 式,这里用到了OOP中的多态性。这使得设计变得非常清晰。因为基类是抽象类或是接口做一个描述,底下继承的类有若干个,我们只需要对接口或抽象类操作, 也用不着管有多少个实现。如果是多人共同开发的项目的话,是非常有意义的。你自己写个东西,怎么实现的也不用告诉别人,别人看个接口就够了。

    接口的实现用关键字implement 而不是extends.如果用了extends的那就是继承这个接口。那么那个子类也是接口,是原来的子接口。举个接口的例子吧:

    实践:

//声明一个接口

    public interface Say {

        public void sayMessage();

}

    //两个实现类

       public class SayHello implements Say {

        public void sayMessage() {

       System.out.println("hello");

    }}

       public class SayHi implements Say {

        public void sayMessage() {

       System.out.println("Hi");

    }}

    //这是一个测试

       public class TestSay {

        public static void main(String[] args) {

//同样都是用Say这个接口类型实例,却可以输出两个结果

       Say say = new SayHello();

       say.sayMessage();

       Say say1 = new SayHi();

       say1.sayMessage();

    }} 

   下载 href="http://java.chinaitlab.com/download/07071509452353.rar" target=_blank>上述源码打包下载

    接口还有一个重要的作用,我们在面向对象那节课里提过一个概念,java语言中只有单继承,就是说只能从一个父类继 承。单继承的好处是,一旦继承的太多了,改了一个类子类就都变了。牵一发,而动全身。那么如果我们想继承多个父类的特性怎么办呢?就用接口吧,这个类可以 先继承一个类,再去实现其它的接口,接口里面都是抽象方法,不会造成,牵一发,而动全身的效应。改变多继承的特性,也是对C++语 言的一项改进

    业界有一种说法说,与其说java是面向对象编程,还不如说它是面向接口编程。强调的方面是接口的抽象描述性。它也是对C++的 一种改进,C++里面没有接口。所以说java语言适合多人团队合作的大项目,看一个接口就可以了,后面怎么实现的可以不管。

java初学者实践教程19-访问控制和内部类

今天我们再来学习一下java语言的基本语法,这节我们讲访问控制和内部类。

    访问控制这种语法在前面的学习中,已经经常见过了。像是public(公有的),private(私有的)。大家按照字面理解就能知道了,公有的就是谁都 可以用,私有的就是只有自己的类内部可以用。不过访问控制一共有4个,public(公有的),protected(受保护的),default(默认 的,就是没有修饰符),private(私有的)。我们用一个图表示他们的权限:

 

    权限修饰符,可以修饰类,方法和属性。而表达的意思与上表一致。有些注意的地方:类的权限不可以用private,你们想如果写一个类是private, 谁也不让用写它干嘛;抽象方法的权限不可以是private和default.因为抽象方法一定要子类来实现的,子类都不可以用,抽象方法当然也没有意义 了。

    内部类是我们以前没有提过的概念,就是在类中又写了一个类。注意内部类是可以使用private权限的,而且还可以是static的呢。内部类可以正常调 用其它类的方法,属性。别人也正常调用它。它的使用用和普通的方法,属性一致,我们就把它看做一个普通的方法就行了。不过它可是可以创建对象的哦。

    下载 href="http://java.chinaitlab.com/download/07071609586953.rar" target=_blank>本节课的例子下载

    我们把测试内部类的源码给大家,不过 有一个地方大家要注意。

public class TestInnerStatic {

/*只有声明成static的内部类,才可以是里面的成员声明成static。否则错误

如果,声明成static的类,不就是全局的了吗?它就相当放在外面了已经不再是内部类了,并 且它的对象中将不包含指向外包类对象的指针,所以不能再引用外包类了*/

  public static class InnerClass {

    public static int classVar = 0;

    public static void doSomething() {

      System.out.println("TestInnerStatic.InnerClass.doSomething");

    }

  }

 

  public static void main(String[] args) {

    InnerClass.doSomething();

  }

java初学者实践教程20-异常处理

  异常处理是个很重要的概念,很多语言中都对异常处理下了很大的功夫。如果你的语法没有写错,编译器是不会报错,而且编译成功。如果编译成功后,运行时发生 了错误该怎么处理呢?例如我要加载一个类,而这个类被删了。这种情况就是异常。我们采用try……catch……finally语句作为处理方式。举个异 常处理的例子吧。

实践:

public class TestExceptions {

  public static void main(String[] args) {

    for ( int i = 0; true; i++ ) {

      System.out.println("args[" + i + "] is '" + args[i] + "'");

    } }} 

    在这里面main方法的参数args是个字符串型的数组,在执行的时候要输入java TestExceptions 100jq 后面的就是参数args[0]就是第一个参数。我们输入java TestException是出现了错误。如图20-1所示,

 
 
 

 

    这上说的是数组边界溢出异常,第0个产生错误,因为根本就没有args[0],这个元素。

    我们再敲一下java TestExceptions 100jq 如图20-2所示,

 
 
 

 

    输出了args[0]没有异常了,并且输出了。而循环到i=1时,又发生异常。我们再输入两个参数java TestExceptions chinaitlab  www.chinaitlab.com 这回两个参数了。同样的道理,args[2]发生异常。

    那么我们如何来捕捉这个异常呢,我们对上述代码做一下简单的修改。

实践:

public class TestExceptions1 {

  public static void main(String[] args) {

    try {

      for ( int i = 0; true; i++ ) {

       System.out.println("args[" + i + "] is '" + args[i] + "'");

      }

    } catch (ArrayIndexOutOfBoundsException e) {

      System.out.println("异常捕捉: " + e);

      System.out.println("退出...");

    } }}  

     这回输入刚才那两个参数的话,就不会出现那一堆难懂的英文了。异常已经在我们的掌控之中。否则,有很多异常是足够使内存导毁的。

    这里面我们只使用了try…catch 哪个地方你觉得它有毛病,你就try哪。但是try然后,要catch(捕捉)的。如果事先你想不出它会发生什么异常的话,就用finally.

实践:

class FinallyDemo {

static void procA() {

try {

System.out.println("inside procA");

throw new RuntimeException("demo");

finally {

System.out.println("procA's finally");

}

}

// 从try程序块内返回

static void procB() {

try {

System.out.println("inside procB");

return;

} finally { //结束

System.out.println("procB's finally");

}

}

// 执行一个try程序块

static void procC() {

try {

System.out.println("inside procC");

} finally {

System.out.println("procC's finally");

}

}

public static void main(String args[]) {

try {

procA();

} catch (Exception e) {

System.out.println("异 常捕捉");

}

procB();

procC();

}

     下载 href="http://java.chinaitlab.com/download/07071612079028.rar" target=_blank>上述源码打包下载

    如果将方法里抛出异常抛出,使用throws关键字 public void abc() throws exception 也是要用catch来捕捉的。

实践:

class ThrowDemo {

static void demoproc() {

try {

throw new NullPointerException("demo");

} catch(NullPointerException e) {

System.out.println("Caught inside demoproc.");

throw e; //重新抛出异常 }}

public static void main(String args[]) {

try {

demoproc();

} catch(NullPointerException e) {

System.out.println("Recaught: " + e);

}}}  

     下载 href="http://java.chinaitlab.com/download/07071612067809.rar" target=_blank>19个源码打包下载

    异常类除了jdk提供我们的那些之外,我们自己还可以自定义的。Jdk提供的刚才我们已经见过几个了 ArrayIndexOutOfBoundsException(数组边界溢出),NullPointerException(空指针异常)。要是jdk 没有的,我们只有自己定义了。比如说我们现在要用XML开发,那么jdk没有写这方面的异常类,我们就得自己写一个关于XML的异常了。我们下节课讲自定 义异常类。

java初学者实践教程21-自定义异常类

上节课留下了一个概念,自 定义异常类。为什么要自己编写异常类,上节课做了简要的说明。如果jdk里 面没有提供的异常,我们就要自己写。我们常用的类ArithmeticException,NullPointerException,NegativeArraySizeException,ArrayIndexoutofBoundsException,SecurityException这些类,都是继承着RuntimeException这 个父类,而这个父类还有一个父类是Exception。 那么我们自己写异常类的时候,也是继承Exception这个类的。

实践:

class MyException extends Exception { //继承了Exception这个父类

private int detail;

MyException(int a) {

detail = a;}

public String toString() {

return "MyException[" + detail + "]";

}}

class ExceptionDemo {

static void compute(int a) throws MyException {

System.out.println("调用 compute(" + a + ")");

if(a > 10)

throw new MyException(a);

System.out.println("常规退出 ");

}

public static void main(String args[]) {

try {

compute(1);

compute(20);

catch (MyException e) {

System.out.println("捕捉 " + e); //这样就可以用自己定义的类来捕捉异常了

}}} 

 

 

像是上节课我们说了,如果你开发程序用到好多组件,或其它厂商的东西。那么出现的异常会是莫明其妙的,这样的话会给 调试带来很大的不便。往往在开发的过程中会写很多自定义的异常类。

 

总结:

 

   异常处理机制是保证java程序正常运行、具有 较高安全性的重要手段。对于开发良好的编程习惯是非常重要的。

java初学者实践教程22-输入/输出

   输入/输出(I/O)是每一项计算机语言,必须 有的东西。不让人输入数据的话,计算机怎么处理数据呢?在java语言中,I/O的方式是流的方式。流(stream)这是个学习java输入输出的最基本的概念。流是字节从源到 目的的有序序列。一方面是字节,一方面是有序的。流描述的是一个过程,顺序严格。一个需要键盘输入的程序可以用流来做到这一点。两种基本的流是:输入流和输出流。你可以从输入流读,但你不能对它写。要从输入流读取字节,必须有一个与这个流 相关联的字符源。这些东西都放在java.io.*这个包里了。io是java的第一大包。在java.io 包中,有一些流是结点流, 即它们可以从一个特定的地方读写,例如磁盘或者一块内存。其他流称作过滤流。一个 过滤器输入流是用一个到已存在的输入流的连接创建的。此后,当你试图从过滤输入流对象读时,它向你提供来自另一个输入流对象的字符。

   常见的几种流:

u       字 节流:传字节的。以8位字节为单位进行读写,以InputStream与OutputStream为基础类

u       字 符流: 传字符的。以16位字符为单位进行 读写,以Reader与Writer为基础 类

u       文 件流: 传文件的。属于节点流,对文件读写,传输。里面的类很多。

u       序 列化:传对象的。一个对象怎么读啊,只有变成二进制才可以读,这就是序列化。

 实践:

 //这是一个字节流的例子,以InputStream与OutputStream为基础类

import java.io.*;

class ByteArrayOutputStreamDemo {

    public static void main(String args[]) throws IOException {

    ByteArrayOutputStream f = new ByteArrayOutputStream();

    String s = "This should end up in the array";

    byte buf[] = s.getBytes();

    f.write(buf);

        System.out.println("Buffer as a string");

        System.out.println(f.toString());

        System.out.println("Into array");

    byte b[] = f.toByteArray();

 

    for (int i=0; i<b.length; i++) {

        System.out.print((char) b[i]);}

        System.out.println("\nTo an OutputStream()");

        //输出到文件test.txt中

        OutputStream f2 = new FileOutputStream("test.txt");

        f.writeTo(f2);

        f2.close();

        System.out.println("Doing a reset");

        f.reset();

    for (int i=0; i<3; i++)

    f.write('X');

        System.out.println(f.toString());}}

//字 符流的例子,以Reader与Writer为 基础类

import java.io.*;

public class CharArrayReaderDemo {

   public static void main(String args[]) throws IOException {

 

   String tmp = "abcdefghijklmnopqrstuvwxyz";

   int length = tmp.length();

   char c[] = new char[length];

   tmp.getChars(0, length, c, 0);

   CharArrayReader input1 = new CharArrayReader(c);

   CharArrayReader input2 = new CharArrayReader(c, 0, 5);

  

   int i;

       System.out.println("input1 is:");

   while((i = input1.read()) != -1) {

       System.out.print((char)i);}

       System.out.println();

       System.out.println("input2 is:");

   while((i = input2.read()) != -1) {

       System.out.print((char)i);}

       System.out.println();

   }}

//文 件流的例子

import java.io.*;

class FileInputStreamDemo {

   public static void main(String args[]) throws Exception {

   int size;

   InputStream f =

   new FileInputStream("FileInputStreamDemo.java");

       System.out.println("Total Available Bytes: " +

       (size = f.available()));

   int n = size/40;

       System.out.println("First " + n +

       " bytes of the file one read() at a time");

   for (int i=0; i < n; i++) {

       System.out.print((char) f.read());

       }

       System.out.println("\nStill Available: " + f.available());

       System.out.println("Reading the next " + n +

       " with one read(b[])");

   byte b[] = new byte[n];

   if (f.read(b) != n) {

       System.err.println("couldn't read " + n + " bytes.");

       }

       System.out.println(new String(b, 0, n));

       System.out.println("\nStill Available: " + (size = f.available()));

       System.out.println("Skipping half of remaining bytes with skip()");

   f.skip(size/2);

       System.out.println("Still Available: " + f.available());

       System.out.println("Reading " + n/2 + " into the end of array");

   if (f.read(b, n/2, n/2) != n/2) {

       System.err.println("couldn't read " + n/2 + " bytes.");

       }

       System.out.println(new String(b, 0, b.length));

       System.out.println("\nStill Available: " + f.available());

   f.close();

   }

 12个例子打包下载

代码很多如有不明白 的地方请访问技术论坛, 还有序列化的例子没有举出, 序列化在java中是个很重要的概念哦。我们下节课。具体举例讲解。

java初学者实践教程23-序列化

 上节课我们讲了4种流, 只有序列化的这个没有细讲。它是传对象的,如果想把一个对象保存在硬盘上,就只能使用这种方式。它的关键是将它的状态以一种串行格式表示出来,以便以后读 该对象时能够把它读出来。对象的串行化对于大多数java应用是非常重要的:

u       Java的远程方法调用(RMI), 通过socket通信。这个东西我们会在后面的教程讲到。

u       对象永久化,就是把对象存硬盘上,或外存设备上。以便以后使用。

它的基础类是ObjectInputStream和ObjectOutputStream,这两个流称为对象流。

      实践:

 //这是一个 保存对象的例子

import java.io.*;

import java.util.Date;

public class SerializeDate {

  SerializeDate() {

    Date d = new Date ();

    try {

      FileOutputStream f =

          new FileOutputStream ("date.ser"); //输出到date.ser这个文件 中

      ObjectOutputStream s =

          new ObjectOutputStream (f);

      s.writeObject (d); //写对象,将对象d写成是date.ser文件

      s.close ();        //关闭流

    } catch (IOException e) {

      e.printStackTrace ();

    } }

  public static void main (String args[]) {

    new SerializeDate();

  }} 

如图所示23-1,执行之后

 
 
 

 

图23-1

 

在DOS窗口中没有看到结果,但是在这个文件夹内发现了一个date.ser的文件。它就是对象d写入磁盘的状态。如图23-2

 
 
 

 

图23-2

那么保存了之后怎么在把 这个date.ser文件读出来呢?

实践:

import java.io.*;

import java.util.Date;

public class UnSerializeDate {

  UnSerializeDate () {

    Date d = null;

    try { //使用FileInputStream类

      FileInputStream f =

          new FileInputStream ("date.ser");

      ObjectInputStream s =

          new ObjectInputStream (f);

      d = (Date) s.readObject ();//读对象

      s.close ();

    } catch (Exception e) {

      e.printStackTrace (); }

    System.out.println(

      "从date.ser文件,读取Date对象 ");

    System.out.println("日期是: "+d);

  }

  public static void main (String args[]) {

    new UnSerializeDate();

  }} 

如图23-3所示读出时间

 
 
 

图23-3

上述源码打包下载

对于一个可以被序列化的 类,它会实现一个Serializable的接口。那是个空接口,什么方法也没有只是一个标志而已。这在J2EE,(现在叫java EE)中,使用EJB时是非常重要的。如果大家以后能继续学习学到EJB的时候,再具体了解。

java初学者实践教程24-反射

  还是那样的,java的 概念就是多,有时候多的还没等你反应过来又给你出来一个新的概念。反射是个很重要的概念,这是一种机制,不只是java里面有,很多语言里面都有。这个概念是一个叫Smith的大师,由1982年提出来的。指的是一类应用,它们能够自描述和自控制。这样说太抽象了。我们看个例子,实践:

import java.lang.reflect.*;

public class Refl {

    public static void main(String args[]) {

        try {

                     //Class.forName() 这是反射的一种方式。将类在运行时自动加载进来

            Class c = Class.forName(“java.lang.String”);

                     // getDeclaredMethods()获取这个类 中定义了的方法列表

            Method m[] = c.getDeclaredMethods();

            for (int i = 0; i < m.length; i++)

                System.out.println(m[i].toString());

        } catch (Throwable e) {

            System.err.println(e);

        }}} 

 

执行的时候发现输出了,String 类的所有方法打印了出来。重要的是,Class.forName这句话它是反射 的一种方式。就是在运行时改变Refl类的状态,通过”java.lang.String”改变。

Java语言提 供了一套反射类,java.lang.reflect.*;这些类可以用做:

l         构造新类实例和新数组

l         访问并修改对象(Object)和类的字段(Field)

l         调用对象和类中的方法(Method)

l         访问并修改数组的元素

    反射是一种强大的工具,但也存在一些不足。一个主要的缺点是对性能有影响。使用反射基本上是一种解释 操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。一边执行的时候, 一边加载其它类,肯定会慢的。但是它有很强的扩展性,具有开放性的系统很多都采用这种机制,因为在安全允许的情况下它可以随 意加载类,和调用方法。在windows编程里面的dll与 它几乎是一个意思。

java初学者实践教程25-多线程

Java语言中有一个重要的特性是支持多线程。多线程是java的一项高级技术,它涉及到操作系统里面的知识, 层次贴近系统层面。对于普通程序员一般很少碰它。而且目前就是在java EE(原来的J2EE)的相关框架里,对线程这个东西都是尽量回避。程序员最理想的状态是专注业务逻辑,而不是天天想着线程这个东西怎么写。

    思考一个问题程序的本质是什么?是CPU的指令序列的集合。到底什么顺序是程序员编写的让计算机赋值,它就赋值、写个循环它就循环、写个分支语句它就分 支、写个跳转它就跳转。每个指令流就是一个线程,并发执行多个指令流就是多线程。大家想,只有一个CPU怎么可能同时发出多个指令流呢?是的,并发只是 “逻辑”上的,物理上是不可能的除非是两个以上的CPU.

    多线程和传统的单线程的区别是由于各个线程的控制流彼此独立,使得各个线程之间的代码是乱序执行的,出现了并发访问带来的一切问题。正像是三个和尚的故 事,和尚多了未必是好事。也就是刚才说的,程序员一般都不让他们碰这个东西。

    在java中如何写线程呢,在java中就是很简单了。有两种方法:第一、继承java.lang.Thread第二、实现Runnable接口。

    实践:

//继承Thread而重写了run()方法

public class Hello extends Thread{

    int i;

    public void run(){

       while(true){

           System.out.println("Hello "+i++);

           if(i==10) break;

       }}}

public class HelloThread {

    public static void main(String[] args){

       Hello h1 = new Hello();

       Hello h2 = new Hello();

       h1.start(); //用两个线程执行那10次循环

       h2.start();

}} 上面的例子是第一种方法,下面是第二种方法

public class TestThread {

  public static void main(String args[]) {

    Xyz r = new Xyz();

    Xyz r1 = new Xyz();

    Thread t1 = new Thread(r);

    Thread t2 = new Thread(r1);

    t1.start();//用两个线程执行那50次循环

    t2.start();

 }} //实现Runnable接口

class Xyz implements Runnable {

  int i;

  public void run() {

    i = 0;

    while (true) {

      System.out.println("Hello " + i++);

      if ( i == 50 ) {

    break;

}}}} 

下载 href="http://java.chinaitlab.com/download/07072010579544.rar" target=_blank>多个源码打包下载

    上面两种方法继承Thread类,是比较简单的,代码也比较少。但是我们不提倡使用这种方法。而第二种实现Runnable接口,更符合面向对象思 想,Thread是把虚拟的CPU看成一个对象,封装了CPU的细节。但是Thread的构造线程的子类的方法中与CPU不相关,没有必要把CPU的细节 都继承来。而实现Runnable则不影响java.lang.Thread的体系。而且便于其它类的继承。

    线程并发的代码和数据的执行顺序混乱,我们也需要自己调度和控制它们。请看附加教程,线程调度和并发。

java初学者实践教程26-网络程序

  Java在网络编程这个地方做的很好,java的主要目的也是为了网络而生的,它能方便的访问网络上的资源。我 们这节课来介绍网络通讯的两种机制:URL通信机制,Socket通信机制。

    URL表示了Internet上一个资源的引用或地址。Java网络应用程序也是使用URL 来定位要访问的Internet的资源。在jdk里面java.net.URL也是一个类,它来封装URL的一些细节。目前大家可以把URL理解为网 址,default.aspx 这就是个URL.http是协议名 (超文本传输协议)用 “://”隔开www.chinaitlab.com 是主机名。Default.aspx是文件名。它的端口号没有写,默认是80.

    实践:

import java.net.*;

public class ParseURL {

    public static void main(String[] args) throws MalformedURLException{

       URL url = new URL("http://www.100jq.com:45175/default.aspx");

       System.out.println("协议是 "+url.getProtocol());

       System.out.println("主机是 "+url.getHost());

       System.out.println("文件名是 "+url.getFile());

       System.out.println("端口号是 "+url.getPort());

    }}

/*

   URL这个对象 中提供了很多方法像是

   getProtocol()

   getHost()

   getFile()

   getPort()

*/ 

    我们可以通过URL对文件或资源读取,也可以通过URLConnection读取,也可以通过这个写入数据限于cgi脚本。

    实践:

import java.net.*;

import java.io.*;

public class URLConnectionReader {

    public static void main(String[] args) throws IOException {

       URL google = new URL("");

       URLConnection g = google.openConnection();

       BufferedReader in = new BufferedReader(new InputStreamReader(g.getInputStream()));

       String inputLine;

       while ((inputLine=in.readLine())!=null)

           System.out.println(inputLine);

           in.close();

    }} 

    URL和URLConnection类提供了较高层次的网络访问。有时候需要进行较低层次的访问。编写C/S模型的程序时,就要使用Socket通信机制 了。因为在网络上不一定非得访问文件。

    实践:

//先写个客户端的应用

import java.net.*;

import java.io.*;

public class SimpleClient {

  public static void main(String args[]) {

    try {

      // 在5432端口打开服务器连接

      // 在这里用localhost与127.0.0.1是一个意思

      Socket s1 = new Socket("127.0.0.1", 5432); 

      // 对这个端口连接一个reader,注意端口不能够占用别的

      BufferedReader br = new BufferedReader(

        new InputStreamReader(s1.getInputStream()));

      // 读取输入的数据并且打印在屏幕上

      System.out.println(br.readLine());

      //当完成时关闭流和连接

      br.close();

      s1.close();

    } catch (ConnectException connExc) {

      System.err.println("Could not connect to the server.");

    } catch (IOException e) {

      // ignore

    }}}

//这是服务端 的应用

import java.net.*;

import java.io.*;

public class SimpleServer {

  public static void main(String args[]) {

    ServerSocket s = null;

    // 注册服务端口为5432

    try {

      s = new ServerSocket(5432);

    } catch (IOException e) {

      e.printStackTrace();

    }

   // 运行监听器并接收,永远循环下去。因为服务器总要开启的

    while (true) {

      try {

        // 等待一个连接的请求

        Socket s1 = s.accept();

        // 得到端口的输出流

        OutputStream s1out = s1.getOutputStream();

        BufferedWriter bw = new BufferedWriter(

          new OutputStreamWriter(s1out));

        // 发送一个字符串

        bw.write("百家拳软件项目研究室欢迎您!\n");

        // 关闭这个连接, 但不是服务端的socket

        bw.close();

        s1.close();

      } catch (IOException e) {

        e.printStackTrace();

      }}}} 

下载 href="http://java.chinaitlab.com/download/07072213182935.rar" target=_blank>上述例子打包下载

    执行这个程序和其它的不太一样,先用javac将两个文件编译之后。然后敲start开启另一个窗口。用start命令开启的窗口继承了原来窗口的特性。 如图26-1所示

 
 
 

 

    图26-1

    接着在原来的窗口上执行服务端程序java SimpleServer.在新窗口中执行java SimpleClient 就会看到结果了。注意如果如果在启动服务端的时候抛出bindException则说明5432这个端口已经被别的程序占用着,改成别的端口号就可以了。 通常选用端口的时候,其数字最好不要小于1024,1024一下的端口很多都是专用的端口。

java初学者实践教程27-applet

  现在的java界,很多东西叫××let,××let的意思都是些小程序的意思。例如:applet应用程序的小程序,servlet服务器端的小程序,midlet手机中的小程序,portlet门户容器端的小程序。这节我们介绍 applet.这个东西用的不是很多,但是在java的体系结构中是很有意义的。这个东西是能够在浏览器里运行的,可以潜入到HTML页面里。我们知道普 通的Application要有main()作为入口点运行,而Applet要在浏览器里运行,或者开发时查看的时候用appletviewer运行。举 个例子,实践:

import java.awt.*;

import java.applet.*;

@SuppressWarnings("serial") //抑制警告

//所有的Applet,都继承了java.applet.Applet

public class HelloApplet extends Applet {

    public void paint(Graphics g){

       g.drawString("百家拳软件项目研究室!",30,30);

    }} 

    还需要建立一个html文件,因为刚才说了它可以嵌入在浏览器里面。用记事本建立一个hello.html代码如下:

    <applet code="HelloApplet.class" width=150 height=150></applet>

    之后照样用javac编译刚才那个类。最后在命令行中输入appletviewer hello.html可以看到结果。

    这种小程序弥补了B/S模型的不足,用浏览器可以执行客户端的东西。因为它功能强大,所以是个不错的东西。可是功能太强大了,又引发了一些安全性的问题。所以浏览器也会对applet做了一些安全性的限制。Applet 还有一种叫做沙箱模型的机制,它使得没有访问权限的资源,不能访问。保证了安全性。同时开发时也不是那么方便。Applet又跨平台的特性。

    而且微软的IE浏览器里面在运行applet的时候速度不是很快,不如activex的方便。界面也不是太漂亮。不过它的这种在浏览器中运行的思想还是比 较不错的。

    再看个有意思的例子吧:如图27-1所示

 
 
 

 

    图27-1

    下载 href="http://java.chinaitlab.com/download/07072314183153.rar" target=_blank>上述源码打包下载

Linux系统下JSP服务器配置步骤详解

  接触JSP服务器的人基本上都是从JSP的 安装开始的,因为JSP不像ASP那样几乎不存在什么安装过程,也不像PHP那样有一个自动安装的程序包,JSP的安装是比较麻烦的,手动的步骤非常多, 下面我们就按部就班的讲解一下,如何在linux环境下配置一台jsp服务器

    一、安装Jdk

    cd到你的jdk安装文件目录

   

        cp ./j2sdk-1_4_0-linux.bin /usr/local 

  cd /usr/local 

    chmod a+x j2sdk-1_4_0-linux.bin 

    ./j2sdk-1_4_0-linux.bin

    然后按照安装向导进行,安装后的jdk目录为/usr/local/jdk1.4

    二、安装Apache

    如果您在安装操作系统的时候已经安装了Apache,卸载它。利用RPM管理器卸载Apache及其相关套件,只有源码级编译安装的操作系统才是最彻底的 系统安装,你才能真正控制它。

    cd到你下载的apache源文件目 录

   

 tar xvzf apache*

  ./configure --prefix=/usr/local/apache --enable-module=so

  make;make install

    三、安装Resin

    cd到你下载的apache源文件目 录

   

       tar xvzf resin* /usr/local

  cd /usr/local/resin*

       configure --with-apache=/usr/local/apache

  make;make install

 

    四、设置profile

    vi/etc/profile//你也可以用别的文本编辑器打开它,添加如下变量

   

 vi/etc/profile//你也可以用别的文本编辑器打开它,添加如下变量 

   JAVA_HOME=/usr/local/jdk1.4 

  RESIN_HOME=/usr/local/resin-2.0 

   CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib //如果你有别的系统级的类库或者驱动,继续向下写,用冒号分开 

   PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin 

  export JAVA_HOME RESIN_HOME CLASSPATH PATH

    修改后保存该文件注销,然后重新登陆,打开命令控制台,输入env,如果在返回的输出中看到了您刚才的环境变量,成功。

五、配置DNS

   

 vi/etc/named.conf

    添加如下语句:

   

       zone yesgo.com{ 

  type master; 

  file "yesgo.com"; 
  } 

  zone 1.168.192.in-addr.arpa{ 

  type master; 

  file "192.168.1"; 

  }

    然后建立这两个配置文件:

   

       touch /var/named/yesgo.com //在其中建立www的NS或者CNAME记录 

   touch /var/named/192.168.1 //在其中建立域名指针

    配置完毕之后,运行如下命令:

    

        ndc restat 

  nslookup

    运行nslookup将出现一个交互命令行,输入www.yesgo.com如 果正常返回其IP,该域名成功解析。

    六、配置Apache

    建立站点根目录

   

        mkdir /www 

  mkdir /www/www.yesgo.com 

  vi /usr/local/apache/conf/httpd.conf

    添加如下语句,建立一个虚拟主机,你可以改变你的域名和IP.

   

       NameVirtualHost 192.168.1.1 //机器ip 

  VirtualHost www.yesgo.com 

  ServerAdmin webmaster@yesgo.com 

  DocumentRoot /www/www.yesgo.com 

  ServerName www.yesgo.com 

  ErrorLog logs/www.yesgo.com-error_log 

  CustomLog logs/www.yesgo.com-access_log common 

  /VirtualHost

然后建立这两个配置文件:

   

        touch /var/named/yesgo.com 在其中建立www的NS或者CNAME记录 

   touch /var/named/192.168.1 在其中建立域名指针

    配置完毕之后,运行如下命令:

   

   ndc restat 

  nslookup

    运行nslookup将出现一个交互命令行,输入www.yesgo.com如 果正常返回其IP,该域名成功解析。

    六、配置Apache

    建立站点根目录

   

        mkdir /www 

  mkdir /www/www.yesgo.com 

  vi /usr/local/apache/conf/httpd.conf

    添加如下语句,建立一个虚拟主机,你可以改变你的域名和IP.

   

        NameVirtualHost 192.168.1.1 //机器ip 

  VirtualHost www.yesgo.com 

  ServerAdmin webmaster@yesgo.com 

  DocumentRoot /www/www.yesgo.com 

  ServerName www.yesgo.com 

  ErrorLog logs/www.yesgo.com-error_log 

  CustomLog logs/www.yesgo.com-access_log common 

  /VirtualHost

    九、建立FTP帐号

    至此,jdk、dns、apache、resin全部配置完毕,现在建立FTP

   

   useradd yesgo //帐号名 

  passwd yesgo //输入密码,不能低于六位,大小写敏感

    执行上面命令将建立/home/yesgo目录,删除它,然后运行如下命令

   

   ln -s /www/www.yesgo.com /home/yesgo

    注意:改变/www/www.yesgo.com的文件夹属性,设置Owner为yesgo用户,Group为yesgo组,并赋予user具有读写权 限,Other具有读权限,如果您不这样做,登陆FTP将说您没有权限,而且输入域名站点也不能浏览。

    如果从安全的角度考虑你还要将 yesgo用户加入到ftp的guest组,它将实现yesgo用户以/www/www.yesgo.com为其根目录,防止操作其他目录。 至此,你就可以在客户端用ftp工具登陆你的FTP站点,上传你的站点文件了。

    十、测试站点

    在客户端的网络配置中添加DNS服务器为你的服务器IP,这样你上面设置的域名可以访问。

    如果你用网络配置不行或者与上网的DNS服务器冲突,到c:/windows或者c:/winnt目录查找HOSTS文件,追加如下一 行:192.168.1.1 www.yesgo.com .前面是你服务器的IP,后面是你的域名,中间用TAB分割。 用Ultradev等工具建立一个本地站点,远程设置为上面设置的ftp,然后建立test.jsp文件,内容只有一句:1+1=<%=1+1& gt;.

    将该文件上传到服务器,也就是上传到了/www/www.yesgo.com目录下,在客户端浏览器浏览http://www.yesgo.com/test.jsp,如 果返回1+1=2,测试成功。

JAVA基础知识精华总结

  1 、对象的初始化

    (1 )非静态对象的初始化

    在创建对象时,对象所在类的所有数据成员会首先进行初始化。

    基本类型:int 型,初始化为0.

    如果为对象:这些对象会按顺序初始化。

    ※在所有类成员初始化完成之后,才调用本类的构造方法创建对象。

    构造方法的作用就是初始化。

    (2 )静态对象的初始化

    程序中主类的静态变量会在main方法执行前初始化。

    不仅第一次创建对象时,类中的所有静态变量都初始化,并且第一次访问某
类(注意此时未创建此类对象)的静态对象时,所有的静态变量 也要按它们在类
中的顺序初始化。

    2 、继承时,对象的初始化过程

    (1 )主类的超类由高到低按顺序初始化静态成员,无论静态成员是否为private.

    (2 )主类静态成员的初始化。

    (3 )主类的超类由高到低进行默认构造方法的调用。注意,在调用每一个
超类的默认构造方法前,先进行对此超类进行非静态对象的初 始化。

    (4 )主类非静态成员的初始化。

    (5 )调用主类的构造方法。

    3 、关于构造方法

    (1 )类可以没有构造方法,但如果有多个构造方法,就应该要有默认的构
造方法,否则在继承此类时,需要在子类中显式调用父类的某 一个非默认的构造
方法了。

    (2 )在一个构造方法中,只能调用一次其他的构造方法,并且调用构造方
法的语句必须是第一条语句。

    4 、有关public、private 和protected

    (1 )无public修饰的类,可以被其他类访问的条件是:a.两个类在同一文
件中,b.两个类在同一文件夹中,c.两个类在同 一软件包中。

    (2 )protected :继承类和同一软件包的类可访问。

    (3 )如果构造方法为private ,那么在其他类中不能创建该类的对象。

    5 、抽象类

    (1 )抽象类不能创建对象。

    (2 )如果一个类中一个方法为抽象方法,则这个类必须为abstract抽象类。

    (3 )继承抽象类的类在类中必须实现抽象类中的抽象方法。

    (4 )抽象类中可以有抽象方法,也可有非抽象方法。抽象方法不能为private.

    (5 )间接继承抽象类的类可以不给出抽象方法的定义。

    6 、final 关键字

    (1 )一个对象是常量,不代表不能转变对象的成员,仍可以其成员进行操
作。

    (2 )常量在使用前必须赋值,但除了在声明的同时初始化外,就只能在构
造方法中初始化。

    (3 )final 修饰的方法不能被重置(在子类中不能出现同名方法)。

    (4 )如果声明一个类为final ,则所有的方法均为final ,无论其是否被
final 修饰,但数据成员可为final 也可不是。

    7 、接口interface (用implements来实现接口)

    (1 )接口中的所有数据均为static和final 即静态常量。尽管可以不用这
两个关键字修饰,但必须给常量赋初值。

    (2 )接口中的方法均为public,在实现接口类中,实现方法必须可public
关键字。

    (3 )如果使用public来修饰接口,则接口必须与文件名相同。

    8 、多重继承

    (1 )一个类继承了一个类和接口,那么必须将类写在前面,接口写在后面,
接口之间用逗号分隔。

    (2 )接口之间可多重继承,注意使用关键字extends.

    (3 )一个类虽只实现了一个接口,但不仅要实现这个接口的所有方法,还
要实现这个接口继承的接口的方法,接口中的所有方法均须在 类中实现。

    9 、接口的嵌入

    (1 )接口嵌入类中,可以使用private 修饰。此时,接口只能在所在的类
中实现,其他类不能访问。

    (2 )嵌入接口中的接口一定要为public.

    10、类的嵌入

    (1 )类可以嵌入另一个类中,但不能嵌入接口中。

    (2 )在静态方法或其他方法中,不能直接创建内部类对象,需通过手段来
取得。

    手段有两种:

    class A { class B {} B getB () { B b = new B(); return b ; }
} static void m () { A a = new A(); A.B ab = a.getB(); // 或者
是 A.B ab = a.new B (); }

    (3 )一个类继承了另一个类的内部类,因为超类是内部类,而内部类的构
造方法不能自动被调用,这样就需要在子类的构造方法中明确 的调用超类的构造
方法。接上例:

    class C extends A.B { C () { new A()。super (); // 这一句就
实现了对内部类 构造方法的调用。 } }

    构造方法也可这样写:

    C (A a ) { a.super(); } // 使用这个构造方法创建对象,要写成C
c = new C (a ); a是A 的对象。

    11、异常类

    JAVA中除了RunTimeException类,其他异常均须捕获或抛出。

 

posted on 2013-01-09 15:47  奉陪了  阅读(470)  评论(0)    收藏  举报