| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 5667 人关注过本帖, 18 人收藏
标题:JAVA入门教程(1)
只看楼主 加入收藏
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
Java编码约定
虽然任何一个合法的标识符都可以用来当作变量、类、方法等的名称,但是Java编程语言极力推荐它的编码约定:
n    classes──类名应该是名词,大小写可混用,但首字母应大写。
例如:
class  AccountBook
class  ComplexVariable
n    interface──界面(接口)名大小写规则与类名相同。
interface  Account
n    method──方法名应该是动词,大小写可混用,但首字母应小写。在每个方法名内,大写字母将词分隔并限制使用下划线。例如:
balanceAccount()
addComplex ()
n    Variables──所有变量都可大小写混用,但首字符应小写。词由大写字母分隔,限制用下划线,限制使用美元符号($),因为这个字符对内部类有特殊的含义。
currentCustomer
变量应该代表一定的含义,通过它可传达给读者使用它的意图。尽量避免使用单个字符, 除非是临时“即用即扔”的变量(例如,用i, j, k作为循环控制变量)
n    constant──原始常量应该全部大写并用下划线将词分隔;对象常量可大小写混用。
HEAD_COUNT
MAXIMUM_SIZE

n    control structures──当语句是控制结构的一部分时,即使是单个语句也应使用括号({})将语句封闭。例如:
if  (condition) {
   do something
}else  
   do something else


n    spacing──每行只写一个语句并使用 tab键缩格使你的代码更易读。
n    comments──用注释来说明那些不明显的代码段落;对一般注释使用 //  分隔符, 而大段的代码可使用 /*···*/分隔符。使用 /**···*/将注释形成文档,并输入给javadoc以生成HTML代码文档。

// A comment that takes up only one line.
/* Comments that continue past one line and take up space on multiple lines... */
/**
 * A comment for documentation purposes.
 *
 * @see Another class for more information
 */

你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-19 17:30
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
分支语句
条件语句使部分程序可根据某些表达式的值被有选择地执行。Java编程语言支持双路if和多路switch分支语句。
if,else语句
基本句法:
if ( /* 布尔表达式 */ ){
    // 语句或块;
  else  
    // 语句或块;

在Java编程语言中,if()用的是一个布尔表达式,而不是数字值,这一点与C/C++不同。前面已经讲过,布尔类型和数字类型不能相互转换。因而,如果出现下列情况:
if  ( x )  // x is int
你应该使用下列语句替代:
if  ( x != 0 )
else部分是可选的,并且当条件为假时如不需做任何事,else部分可被省略。
switch语句
基本句法:
switch (expr1){// int 兼容型
case expr2:
    //statements;
    break;
case expr3:
    //statements;
    break;
default:
    //statements;
    break;

注意:
在switch (expr1) 语句中,expr1必须与int类型是赋值兼容的;byte, short或char类型可被升级;不允许使用浮点或long表达式。
当变量或表达式的值不能与任何case值相匹配时,可选缺省符(default)指出了应该执行的程序代码。如果没有break语句作为某一个case代码段的结束句,则程序的执行将继续到下一个case,而不检查case表达式的值。
例:
switch (colorNum) {
case 0:
    setBackground(Color.red);
    break;
case 1:
    setBackground(Color.green);
    break;
default:
    setBackground(Color.black);
    break;
}
for循环
基本句法:
for (init_expr; boolean testexpr; alter_expr){
    //语句或块

例如:
for (int i = 0; i < 10; i++){
    System.out.println("Are you finished yet?");
}
System.out.println("Finally!");        
注意:
Java编程语言允许在for() 循环结构中使用逗号作为分隔符。 例如,for (i= 0, j = 0; j<10; i++, j++)是合法的;它将i值初始化为零,并在每执行完一次循环体后,增加一次它们的值。
while循环
基本句法:
while(布尔表达式){
    //语句或块        

例如:
int i = 0;
while (i < 10){
    System.out.println("Are you finished yet?");
    i++;
}
System.out.println("Finally!");        
请确认循环控制变量在循环体被开始执行之前已被正确初始化,并确认循环控制变量是真时,循环体才开始执行。控制变量必须被正确更新以防止死循环。
do循环
do循环的句法是:
do {
    //语句或块;
} while (布尔测试)

例如:
int i = 0;
do {
    System.out.println("Are you finished yet?");
    i++;
} while (i < 10);
象像while循环一样,请确认循环控制变量在循环体中被正确初始化和测试并被适时更新。
作为一种编程惯例,for循环一般用在那种循环次数事先可确定的情况,而while和do用在那种循环次数事先不可确定的情况。
break和continue
下列语句可被用在更深层次的控制循环语句中:
break [标注];
continue[标注];
label: 语句;    // 语句必须是有效的
break语句被用来从switch语句、loop语句和预先给定了label的块中退出。
continue语句被用来略过并跳到循环体的结尾。
label可标识控制需要转换到的任何有效语句,它被用来标识循环构造的复合语句。
例如:
loop:    while (true){
            for (int i = 0; i < 100; i++) {
                switch (c = System.in.read()) {
                case -1:
                case ' \n ':                  
                    break loop;
                    ....
                }
            } // end for
        } // end while

test:     for (...) {
            ....
            while (...) {
                if (j > 10) {
                    // jumps to the increment portion of
                    // for-loop at line #13
                    continue test;
                }
            } // end while
        } // end for   

计算1到100的合计值。
public class Number    {
    public int sum(){
        int totle = 0;
        for (int i = 1; i <= 100; i++){
            totle += i;
        }
        return totle;
    }
   
    public static void main(String[] args){
        Number obj = new Number();
        int temp = obj.sum();
        System.out.println(temp);
    }
}
输出结果
5050

你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-19 17:33
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
数组

 
数组的描述
数组是我们接触的第一个容器,数组是长度固定的容器。一但定义好大小,将不能改变。由于Java中的数据类型分为两种:基本类型和引用类型。所以数组也有两种类型的:基本类型的数组和引用类型的数组(数组的数组也是引用类型的数组)
数组声明
语法:
<modifier>  <type>  <name>[];

<modifier>  <type>[]  <name>;
说明:
<modifier> 目前可以用private,public或着默认的修饰,private是封装的访问权限。
<type> 可以是任何原始类型(基本类型)或其它类(引用类型)。
<name>:任何合法的标识符。它代表所声明属性的名称。
举例:
char s[ ];
Point p[ ]; // where point is a class
在Java编程语言中,无论数组元素由原始类型构成,还是由类构成,数组都是一个对象。声明不能创建对象本身,而创建的是一个引用,该引用可被用来引用数组。数组元素使用的实际存储器可由new语句或数组动态初始化来分配。
上述这种将方括号置于变量名之后的声明数组的格式,是用于C、C++和Java编程语言的标准格式。但 这种格式会使数组的声明的格式复杂难懂,因而,Java编程语言允许一种替代的格式,该格式中的方括号位于变量名的左边,意思是:声明一类型的数组,这个数组有一个引用名叫什么?:JAVA推荐使用此格式。
char[ ] s;
Point[ ] p;
这样的结果是,你可以认为类型部分在左,而变量名在右。上述两种格式并存,你可选择一种你习惯的方式。创建一组基本数据类型 char 的数组,其引用名为 s
创建一组对象 Point 的数组,其引用名为 p

数组声明不指出数组的实际大小。
注意:当数组声明的方括号在左边时,该方括号可应用于所有位于其右的变量。
char[ ] s1,    s2;        // s1,s2都是字符数组。
char     s1[ ],s2;        // s1是字符数组,s2是字符。

创建数组
语法:
<name> = new <type>[<int>];

<name> = new  <type>[]{};
说明:
<name>:任何合法的标识符。它代表所声明属性的名称。
<type>:可以是任何原始类型(基本类型)或其它类(引用类型)。
<int>: 一个整数值,数组的大小
用来指示单个数组元素的下标必须总是从0开始,并保持在合法范围之内--大于或等于0,并小于数组长度。任何访问在上述界限之外的数组元素的企图都会引起运行时出错。
public int[] createIntArray() {
    int[] k = null;
    k = new int[5];
    for (int i = 0; i < k.length; i++)
        k[i] = i + 1;
    return k;
}
你可以象创建对象一样,使用关键字new 创建一个数组。
k = new int [5];
创建了一个5个int值元素的数组。
内存中数组初始化情形如下:
图片附件: 游客没有浏览图片的权限,请 登录注册


对于应用类型元素的数组,示例如下:
public Point[] createArray() {
    Point[] p= null;
    p = new Point[5];
    for (int i = 0; i < p.length; I++)
        p[i] = new Point(i,i+1);
    return p;
}

数组在内存中的映像则如下:
图片附件: 游客没有浏览图片的权限,请 登录注册

当创建一个数组时,每个元素都被初始化。在上述int数组k的例子中,每个值都被初始化为0;在数组p的例子中, 每个值都被初始化为null,表明它还未引用一个Point对象。在经过赋值 p[0] = new Point(i,i+1)之后,数组的第一个元素引用为实际Point对象。
Java编程语言允许使用下列形式快速创建数组:
String[]  names [ ] = {
“Georgianna”,
   “Jen”,
   “Simon”,
};
其结果与下列代码等同:
String[]  names [ ] ;
names = new String [3];
names [0] = “Georgianna”;
names [1] = “Jen”;
names [2] = “Simon”;
这种”速记”法可用在任何元素类型。例如:
MyDate[]  Dates[ ] = {
new MyDate (22,7,1964),
new MyDate (1,1,2000),
   new MyDate (22,12,1964)
};
适当类型的常数值也可被使用:
Color[] palette  [ ] = {
Color.blue,
Color.red,
Color.white
};

例1
public class TestArray1 {
    public static void main(String[] args) {
        // 声明并初始化一个数组
        int[] num = new int[40];
        // 记录数组下标
        int k = 0;
        // 循环找素数
        for (int i = 2; i <= 100; i++) {
            int j = 2;
            for (; j < i; j++) {
                if (i % j == 0)
                    break;
            }

            if (j == i) // 表示是素数
            {
                num[k++] = i;
            }
        }

        // 输出所有素数,5个一行
        for (int i = 0; i < k; i++) {
            // 如果是小于10的数,多输出个空格,整齐
            if (num[i] < 10)
                System.out.print(num[i] + "   ");
            else
                System.out.print(num[i] + "  ");
            // 够5个数换行
            if ((i + 1) % 5 == 0)
                System.out.println();
        }
    }
}
结果如下:
图片附件: 游客没有浏览图片的权限,请 登录注册


例2
把一个班的名字(String类型,引用类型)保存起来,并进行输出。
public class TestStudents {
    public static void main(String[] args) {
        // 定义3个空间大小的数组
        String[] stu = new String[3];
        // 数组是通过下标来赋值,下标从0开始
        stu[0] = "java";
        stu[1] = "c++";
        stu[2] = "c#";
        // 下面的赋值将产生异常
        stu[3] = "j2me";
        // 输出数据
        for (int i = 0; i < stu.length; i++)
            System.out.println(stu[i]);
    }
}
运行的结果如下:
图片附件: 游客没有浏览图片的权限,请 登录注册


如果把stu[3] = "j2me"; 这句去掉,运行正常,结果如下:
图片附件: 游客没有浏览图片的权限,请 登录注册


例3
保存1到100之间的素数(除了1和它本身不能被其他整数整除的数)。
public class TestArray3 {
    public static void main(String[] args) {
        // 声明并初始化一个数组
        int[] num = new int[40];
        // 记录数组下标
        int k = 0;
        // 循环找素数
        for (int i = 2; i <= 100; i++) {
            int j = 2;
            for (; j < i; j++) {
                if (i % j == 0)
                    break;
            }

            if (j == i) {// 表示是素数
                num[k++] = i;
            }
        }

        // 输出所有素数,5个一行
        for (int i = 0; i < k; i++) {
            // 如果是小于10的数,多输出个空格,整齐
            if (num[i] < 10)
                System.out.print(num[i] + "   ");
            else
                System.out.print(num[i] + "  ");
            // 够5个数换行
            if ((i + 1) % 5 == 0)
                System.out.println();
        }
    }
}
运行结果如下:
图片附件: 游客没有浏览图片的权限,请 登录注册

你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-19 17:40
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
多维数组
Java编程语言没有象其它语言那样提供多维数组。因为一个数组可被声明为具有任何类型,所以你可以创建数组的数组(和数组的数组的数组,等等)。一个二维数组(JAVA中没有二维数组的概念,二维数组其实就是数组的数组)如下例所示:
Int[][]  twoDim [][] = new int [4][];
twoDim[0] = new int[5];
twoDim[1] = new int[5];
首次调用new而创建的对象是一个数组,它包含4个元素,每个元素的类型也是int数组型,必须将数组的每个元素分别初始化。
注意:
尽管声明的格式允许方括号在变量名左边或者右边,但此种灵活性不适用于数组句法的其它方面。
例如: new int [ ][4]是非法的。
因为这种对每个元素的分别初始化,所以有可能创建非矩形数组的数组。也就是说,twoDim的元素可按如下方式初始化:
twoDim[0] = new int [2]
twoDim[1] = new int [4];
twoDim[2] = new int [6];
twoDim[3] = new int [8];
由于此种初始化的方法烦琐乏味,而且矩形数组的数组是最通用的形式,因而产生了一种”速记”方法来创建二维数组。例如:
Int[][]  twoDim [ ][ ]  =  new int [4][5];
可被用来创建一个每个数组有5个整数类型的4个数组的数组。
数组界限
在Java编程语言中,所有数组的下标都从0开始。 一个数组中元素的数量存储在length属性中; 这个值被用来检查所有运行时访问的界限。如果发生了一个越出界限的访问,那么运行时的报错也就出现了。
使用length属性的例子如下:
Int[] list [ ] = new int [10];
for (int i= 0; i < list.length; i++){
System.out.println(list[i]);
}
使用length属性使得程序的维护变得更简单。
例4
存放java班,c++班,j2me班,嵌入式班四个班学生的名字,并打印出来。
public class TestFourClass {
    public static void main(String[] args) {
        // 声明4个空间大小,类型是String数组的数组
        String[][] stu = new String[4][];
        // 初始化java班的6个人
        stu[0] = new String[6];
        for (int i = 0; i < stu[0].length; i++)
            stu[0][i] = "java" + (i + 1);
        // 初始化c++班的3个人
        stu[1] = new String[3];
        for (int i = 0; i < stu[1].length; i++)
            stu[1][i] = "c++" + (i + 1);
        // 初始化j2me班的5个人
        stu[2] = new String[5];
        for (int i = 0; i < stu[2].length; i++)
            stu[2][i] = "j2me" + (i + 1);
        // 初始化潜入式班的4个人
        stu[3] = new String[4];
        for (int i = 0; i < stu[3].length; i++)
            stu[3][i] = "嵌入式" + (i + 1);
        // 打印各个班级的名单
        for (int i = 0; i < stu.length; i++) {
            switch (i) {
            case 0:
                System.out.println("java班:");
                break;
            case 1:
                System.out.println("c++班:");
                break;
            case 2:
                System.out.println("j2me班:");
                break;
            case 3:
                System.out.println("嵌入式班:");
            }
            System.out.print("   ");
            for (int j = 0; j < stu[i].length; j++) {
                System.out.print(stu[i][j] + "  ");
            }
            System.out.println();
        }
    }
}
运行的结果如下:
图片附件: 游客没有浏览图片的权限,请 登录注册


拷贝数组
数组一旦创建后,其大小不可调整。然而,你可使用相同的引用变量来引用一个全新的数组:
iInt[]  myArray[ ] = new int [6];
myArray = new int[10];
在这种情况下,第一个数组被丢弃,除非对它的其它引用保留在其它地方。
Java编程语言在System类中提供了一种特殊方法拷贝数组,该方法被称作arraycopy()。例如,araycopy可作如下使用:
iInt[]  myArray[] = { 1, 2, 3, 4, 5, 6 };      // 原始数组
int[]  hold[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };    // 新的更大的数组

System.arraycopy(myArray, 0, hold, 0, myArray.length); // 从没有Array拷贝所有元素到hold,从下标0开始
这时,数组hold有如下内容:1,2,3,4,5,6,4,3,2,1。
注意:如果数组保存的是基本类型的话直接把值拷贝过来。如果数组存放的是引用类型(类类型,数组类型(多维数组的拷贝)等),那么拷贝的是引用类型的地址,请看下面的例子:
例5
class AA {
    int i;

    public AA(int ii) {
        i = ii;
    }
}

public class TestArrayCopy {
    public static void main(String[] args) {
        // 声明数组并初始化,源数组
        AA str1[] = new AA[] { new AA(1), new AA(2), new AA(3), new AA(4) };
        // 拷贝的目的数组
        AA str2[] = new AA[str1.length];
        // 完全拷贝,array方法参数的介绍看api
        System.arraycopy(str1, 0, str2, 0, str1.length);
        // 改变目的数组
        str2[1].i = 5;
        // 打印原始数组,如果没有改变说明是两个数组
        for (int i = 0; i < str1.length; i++) {
            System.out.print(str1[i].i + "  ");
        }
        
    }
}
输出的结果如下:
图片附件: 游客没有浏览图片的权限,请 登录注册

显然,数组发生了改变,也就是经过拷贝操作后,原始的数组和新拷贝的数组没有分离,因为所拷贝的将是元素的引用。
对于多维数组,由于数组本身是引用类型,所以其拷贝特性与引用类型数组相同。
例6
public class TestMutipleDemensionArrayCopy {
    public static void main(String[] args) {
        // 定义数组的数组
        int[][] source = new int[5][];

        // 定义目的数组
        int[][] target1 = new int[5][];
        int[][] target2 = new int[5][];

        // 给源数组赋值
        for (int i = 0; i < 5; i++) {
            source[i] = new int[i + 1];
            // int temp=i;
            for (int j = 0; j < source[i].length; j++)
                source[i][j] = j + 1;
        }
        // 打印源数组的数据
        System.out.println("-------------源数据-------------");
        for (int i = 0; i < source.length; i++) {
            for (int j = 0; j < source[i].length; j++)
                System.out.print(source[i][j] + "   ");
            System.out.println();
        }
        // 数组的拷贝(浅拷贝)
        System.arraycopy(source, 0, target1, 0, source.length);
        // 改变目的1数组的值
        target1[1][0] = 100;
        // 打印源数组的信息,可以看到值改变,说明没有深拷贝
        System.out.println("-----------浅拷贝后输出-----------");
        for (int i = 0; i < source.length; i++) {
            for (int j = 0; j < source[i].length; j++)
                System.out.print(source[i][j] + "   ");
            System.out.println();
        }

        // 数组的深拷贝,先拷贝”第一维“的
        System.arraycopy(source, 0, target2, 0, source.length);
        // 再深拷贝
        for (int i = 0; i < 5; i++) {
            target2[i] = new int[i + 1];
            System.arraycopy(source[i], 0, target2[i], 0, i + 1);
        }
        // 改变目的2数组的数据
        target2[1][0] = 999;
        // 打印源数组的信息,可以看到值没有改变,说明是深拷贝
        System.out.println("-----------深拷贝后输出未把100改成999-----------");
        for (int i = 0; i < source.length; i++) {
            for (int j = 0; j < source[i].length; j++)
                System.out.print(source[i][j] + "   ");
            System.out.println();
        }
    }
}
输出的结果如下:
图片附件: 游客没有浏览图片的权限,请 登录注册


你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-19 17:44
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
继承

单继承(single inheritance)
在面向对象一章中我们学习了OO的特征之一:继承,是任何面向对象的语言必然实现的特性,java也不例外,但我们应该注意的是,java和某些面向对象语言(如c++)在实现继承的不同之处在于java只支持单继承,不支持多重继承。
即,java中一个类只能继承于另一个类。我们将被继承的类称之为父类(基类),继承类称之为子类(派生类)。在java中用关键字extends来实现单继承,语法如下:
class subclass extends superclass{...}
在前面所讲已知,实现继承关系的类之间有着必然的联系,不能将不相关的类实现继承,就象人类不能继承于鸟类!
那怎么去判断类和类之间是否有着必然联系呢?实际上,在第一章里面,我们已知当某类A和类B之间有着共同的属性和行为时,那么类A和类B之间就可能是继承关系或者有着共同的父类。
下面,假设我们开发某公司的员工管理系统,已知类Manager和类Employee,代码如下:
        
class Employee
        {
            public String f_name;
            public String l_name;
            public float salary = 0.0f;

            public String getEmpDetails()
            {....}
        }

        class Manager
        {
            public String f_name;
            public String l_name;
            public float salary;
            public String dept;

            public String getEmpDetails()
            {....}
        }

通过分析得知,在类Employee和类Manager中存在许多共同的属性和行为,在现实生活中,Manager是公司Employee之一,因此,我们可以将Manager类定义成Employee类的子类,修改类Manager如下:
        class Manager extends Employee
        {
            public String dept;

            public String getEmpDetails()
            {
                return "This is Manager!";
            }
        }
UML中类图表示为:
图片附件: 游客没有浏览图片的权限,请 登录注册


大家可能会质疑:Manager类重新定义后,原有的属性减少了(f_name,f_name,salary),岂不是违背了需求?!
当类A继承于类B时,子类A拥有父类B的所有成员变量和方法,换句话说,子类继承了父类的所有成员属性和方法,在父类中已定义的属性和方法,在子类中可以无需定义(除非方法覆盖)。
所以,在子类Manager中已继承了父类Employee中的属性和方法,无需再定义在父类中已有的属性(f_name,f_name,salary)。
好,我们已经学会了基本的继承语法,下面就来探讨一下继承带来的一些好处:
a.减少代码冗余
从上面的例子就可以看出,类Manager通过继承而无需再定义属性(f_name,f_name,salary),从而减少了代码量,试想一下,当公司员工分为许多不同级别员工时(如定义秘书、工程师、CEO等员工类),如果没有继承,那将是怎样的结果?
b.维护变得简单
假设公司要求给所有员工添加生日这一属性,那么,在没有继承时,我们的维护将变得困难(需修改每一个级别的员工类)。
c.扩展变得容易
当一个新的级别员工类需创建时,我们只需将该类继承所有员工父类Employee,接着再定义属于该员工的特有属性即可。
当然,以上所举例子只是继承带来的好处的部分体现,在下面的学习中我们将逐渐深入体会继承带来的优势。

小测试:以下代码是否正确?
        class B{...}
        class C{...}
        class D{...}
        class A extends B,C,D
        {.....}
java中一个类只能继承一个类,但一个类可以被多个类所继承。如:
        class Engineer extends Employee{...}
        class Secretary extends Employee    {...}

        class Manager extends Employee
        {
            public String dept;
            ...
        }
以上三个不同类分别继承了Employee类,即三个类拥有从父类继承过来的共同属性和方法。但是,请注意:这仍旧是单继承!以UML类图表示为:
图片附件: 游客没有浏览图片的权限,请 登录注册


提醒:构造方法不能被继承!一个类得到构造构造方法只有两种途径:自定义构造方法;使用JVM分配的缺省构造方法。但是,可以在子类中访问父类的构造方法,后面我们会深入。


访问控制
在java中是通过各种访问区分符来实现数据封装的,共分为四种访问级别(由高到低):private(私有)、friendly(缺省)、protected(受保护)、public(公共)。
注意:以上四种访问修饰符可以作用于任何变量和方法,类只可以定义为默认或公共级别(嵌套类除外)。
¨    public(公共)
当变量或方法被public修饰时,该变量和方法可以在任何地方(指的是任何包中)的任何类中被访问。

 //类PublicSample中的构造方法、成员变量及方法均被定义为公共的访问级别
             package com.itjob;
              class PublicSample {
                 public PublicSample(){....}

                 public int num1;
              public byte bt1;
              public char ch1;

              public void method1(){....}
           }
通过以上定义,类PublicSample中的成员方法和变量可以在任何包中的任何类中访问,即访问是公共的,不受限制的。以下访问都是允许的:
访问1
             class PublicSample {
                 ......
                 public static void main(String[] args) {
                    new PublicSample().num1 = 100;
                    new PublicSample().ch1 = '\u0000';
                    new PublicSample().bt1 = 10;
                    new PublicSample().method1();
                 }
              }
访问2
             package com.java;
              import com.itjob.*;
              class A {
                 public void method1() {
                    new PublicSample().ch1 = 'a';
                    ....
                 }
              }
¨    protected(受保护的)
当类的变量或方法被protected修饰时,该变量和方法只可以在同包中的任何类、不同包中的任何当前类的子类中所访问。即不同包中的任何不是该类的子类不可访问级别为protected的变量和方法。
              //受保护的变量
              protected Stirng str = "";
              //受保护的方法
              protected String get(){return "";}

¨    friendly(缺省的)
当类的变量和方法没有显式地被任何访问区分符修饰时,该变量和方法的访问级别是缺省的。缺省的变量和方法只能在同包的类中访问。
              //缺省访问级别的变量和方法、类
              Float f1 = null;
              void method(){...}
              class C1{...}
¨    private(私有的)
被private所修饰的所有变量和方法只能在所属类中被访问。即类的私有成员和变量只能在当前类中被访问。
              //私有的构造方法和成员变量、方法
              private ClassName(){....}
              private int num = 0;
              private void method(){....}
通过以上学习,我们可以通过以下表格来描述四种访问区分符的访问限制:
 
方法重载(method overloading)
¨    成员方法重载
学习重载之前,我们来了解一下在java中方法的特征。
在java中,每一个方法都有自己的特征,其特征主要是指方法名以及方法的参数。
            void method1(){}
            void method2(){}
method1()和method2()可以被理解为是两个方法名不同的方法,即方法的特征不一致。
            void method1(int x){}
            void method1(){}
第一个method1()与第二个method1()虽然名字一样,但是却有不同的参数,因此,这两个同名方法仍有着不同的特征。
对于java编译器来说,它只依据方法的名称、参数列表 的不同来判断两个方法是否相同,如果出现两个名称相同、参数也完全一致的方法,那么编译器就认为这两个方法是完全一样的,也就是说方法被重复定义!
以下定义是错误的:
            class ClassName {
                void m1(){}
                void m1(){}
            }
对于以上两个方法定义语句,java解释器认为这两个方法完全相同,当执行到第二条语句时,它会告诉你方法m1()已在类ClassName中被定义!
可以这样理解,当我们在一个类中不能定义相同名称的多个方法,除非这些方法具有不同的方法特征(参数的不一致)。将上面语句修改为:
            class ClassName {
                void m1(int x){}
                void m1(){}
            }
这样,虽然方法名相同,但由于两个方法的参数不一致,因此,编译器就认为这是两个不同的方法,从而不会产生歧义。

好,在这里,大家可能就会质疑,把其中的某个方法换成不同的名称不也可以正常运行吗?
对,这样确实可以解决问题,但我们知道,在现实中,往往一个类会实现复杂的功能,其中定义的多种方法可能实现的功能意义都是一样,比如我们已经熟悉的System类中的静态对象中方法println(),在该类中println()被定义了多个,每一个方法都有不同的参数,现在我们已知道每一个println()都具有相同的功能:在控制台上输出内容!我们来假想一下,如果按照每个方法定义一个不同名称,那么我们将在System类中定义十多种不同名称的打印方法,虽然功能实现了,首先,我们是否需要编写代码前给这十几种方法取不同名称,并且还得保证名称唯一,这就会增加我们的工作量;其次我们还得记住每一个方法名对应的功能,如果稍有记错,那就会得到错误的结果!
因此,我们有更好的解决办法,通过重载,可以在一个类中定义相同名称、不同参数的实现相同功能的多个方法,这样就避免了给每个方法取不同名称、熟记每个不同名的方法对应的功能的额外工作量,提高了我们的开发效率。
当一个类中的多个同名方法满足以下条件时之一时,即实现了方法重载:
a.不同的参数个数
b.不同的参数类型
c.不同的参数顺序
            
小测试:以下哪几组方法实现了重载,满足了重载的那一个条件?
                组一:
                void m1(int x){}
                void m1(int x, int y){}
                组二:
                void m1(int x, String str){}
                void m1(String str, int x){}
                组三:
                void m1(int x, int y){}
                void m1(int y, int x){}
                组四:
                void m1(int x){}
                int m1(int x, int y){}
                组五:
                void m1(int x){}
                void m2(int x){}

¨    构造方法重载
如果有一个类带有几个构造函数,那么也许会想复制其中一个构造函数的某些功能到另一个构造函数中。可以通过使用关键字this作为一个方法调用来达到这个目的。
public class Employee {
    private String name;
    private int salary;

    public Employee(String n, int s) {
        name = n;
        salary = s;
    }

    public Employee(String n) {
        this(n, 0);
    }

    public Employee() {
        this(" Unknown ");
    }
}
在第二个构造函数中,有一个字符串参数,调用this(n,0)将控制权传递到构造函数的另一个版本,即采用了一个String参数和一个int参数的构造函数中。
在第三个构造函数中,它没有参数,调用this("Unknownn")将控制权传递到构造函数的另一个版本,即采用了一个String参数的构造函数中。
注:对于this的任何调用,如果出现,在任何构造函数中必须是第一个语句。
    构造函数中调用另一构造函数,其调用(this()、super())有且只能有一次,并不能同时出现调用。
分析例题3(Example3.java)的执行结果。
提醒:方法的重载都是基于同一个类!



方法覆盖(method overriding)
覆盖是基于继承的,没有继承就没有覆盖。在java中,覆盖的实现是在子类中对从父类中继承过来的非私有方法的内容进行修改或扩展 的一个动作(注意:不能违反访问级别的限制,即子类方法的访问级别不能低于父类方法的访问级别 )。
下面我们来分析一个例子:
        class A {
            public void method() {
                System.out.println("SuperClass method()");
            }
}

        class B extends A {
            public static void main(String[] args) {
                new B().method();
            }
}
执行以上代码得到的打印结果:"SuperClass method()"。
结果分析:
子类B继承了父类A中的公共方法method(),调用子类B的method()方法实际就是调用从父类中继承过来的method()的方法。

修改子类B:
    class B extends A     {
        public void method() {
            System.out.println("SubClass method()");
        }
        // main()
        ..............
}

再次执行以上代码得到的结果是:"SubClass method()"。
结果分析:
在类B中实现方法覆盖,父类 方法method()被子类B 覆盖了。在子类B定义了一个返回类型、方法名、方法参数列表 都和从父类中继承过来的方法method()一样的方法,那么,新定义的方法就会覆盖原有的方法,实际上就是对从父类继承过来的方法重写(覆盖) !
实现方法的覆盖必须满足以下所有条件:
        a. 覆盖方法的返回类型必须与父类中被覆盖方法的返回类型相同
        b. 覆盖方法的参数列表 类型、次序和方法名称必须与被覆盖方法的参数列表 类型、次序和方法名称相同
        c. 覆盖方法的访问级别不能比被覆盖方法访问级别低
     d. 覆盖方法不能比它所覆盖的方法抛出更多的异常。(异常将在下一个模块中讨论)
        
父类中定义的方法:public void m1(int x, String str){...}
以下是在各个子类中定义的方法:
        子类1:public String m1(int x, String str){...}
        分析:没有实现覆盖,方法的返回类型不同
        子类2:public void m1(String str, int x){...}
        分析:没有实现覆盖,方法的参数类型不同
        子类3:void m1(int x, String str){...}
        分析:没有实现覆盖,方法的访问级别不能被降低
        子类4:public void m1(int x, String str){...}
        分析:已实现覆盖,满足覆盖的所有条件

你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-20 08:09
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
基于继承的多态实现
多态:一个名字可以表示许多不同类(这些不同类必须拥有一个共同的超类)的对象,从而实现以不同的方式来响应某个共同的操作集。
在java中,名字指的就是变量名,我们可以认为每个对象都有一个名字---引用该对象的变量名。比如String str = "abcd";我们就称之为对象str。因此,在java中的多态就体现在一个变量可以引用多个不同类对象,前提是这些不同类必须有者共同的父类,从而该变量可以且只能调用每个不同对象之间的公共操作集(方法)。
很明显,多态的实现是基于继承的。比如,前面所说的Manager类继承了父类Employee的所有属性和方法,这就是说,任何在Employee上的合法操作在Manager上也合法!
一个变量只能有一个类型!这个类型是在编译时指定的,按照多态的定义,一个变量可以指向不同类型的对象,在java中,当这个条件成立时,那这个变量就是多态性的!我们先来看看java中多态的实现。
父类变量可以引用子类对象!这在java是允许的,即Employee e = new Manager()是合法的,但是请注意,变量e只能调用共同的成员属性与方法,即e只能访问子类从父类中继承过来的成员!
//error! 父类变量不能访问属于子类特有的成员(即非公有成员)
e.dept = "";
以上只是实现了多态的一部分:一个父类变量引用许多不同子类对象。
接着,我们再来分析以下例题:
class Engineer extends Employee {
    public String getEmpDetails() {
        return "Engineer getEmpDetails()";
    }
}

class Manager extends Employee {
    public String getEmpDetails() {
        return "Manager getEmpDetails()";
    }

    public void m1() {
    }
}
通过以上定义,我们已知类Engineer和类Manager分别继承了类Employee,并且都覆盖了从父类中继承过来的方法getEmpDetails(),在main方法中执行以下代码:
        1  Employee e = new Manager();
        2  System.out.println(e.getEmpDetails());
        3  e = new Engineer();
        4  System.out.println(e.getEmpDetails());
结果是执行语句2打印:" Manager  getEmpDetails()",执行语句4打印:" Engineer  getEmpDetails()"。
分析:首先,通过语句1和3可以得知父类变量e可以引用不同类型的子类对象,并且,当e引用子类Manager对象时调用方法getEmpDetails()时,返回的是子类Manager已覆盖的方法内容,因此,现在我们可以肯定一点,当子类覆盖父类方法时,子类对象访问的将是已被覆盖的内容!
其次,通过语句2和4的执行结果对比,父类变量引用子类对象时,调用的将是每一个被引用对象的成员方法,即引用不同的子类对象则调用该子类的成员方法,互不干扰!
如果增加以下语句:e.m1();
将会是编译错误,因为该父类变量调用了一个不属于公有的方法,m1()是Manager类的特有成员,而不是从父类继承下来的。Manager的特殊部分是隐藏的。这是因为编译者应意识到,e 是一个Employee的引用 ,而不是一个Manager的引用
因此,通过以上分析,我们可以得出结论:父类引用 可以引用子类对象,同时该父类引用 只能访问所有子类的公有操作集(从父类继承过来的成员);当子类中已覆盖继承方法时,父类变量调用的将是子类中的已覆盖方法!
可以创建具有共同类的对象的收集(如数组)。这种收集被称作同类收集。
就是因为有了java的这种多态机制,我们因而可以实现异类收集!java拥有一个顶层父类java.lang.Object,该类是所有类的顶级父类,在我们平常定义各种类时,虚拟机会自动在类的声明语句后加上继承Object类,如下:
    class Employee 与 class Employee extends Object是等同的!extends Object是JVM自动给任意类加上去的,从而保证java中的所有类都具备一个通用父类。
既然Object是所有类的父类,那么我们就可以通过Object数组来实现异类收集,由于多态性,Object数组就能收集所有种类的元素,如:
    Object[] obj = {"123", new Employee(), new Manager()}; //收集了三种不同类型对象
    Employee[] e = {new Employee(), new Manager(), new Engineer()};  //收集了三种不同子类对象
    可以分解为: e[0] = new Employee();
            e[1] = new Manager();
            e[2] = new Engineer();
以上语句恰好满足了java中的父类变量可以引用子类对象的定义,因此,以上语句都是合法的。
异类收集就是不相同的对象的收集。

请参考例题4(Example4.java)来详细了解多态的使用。

隐藏(hiding)
通过上面的学习,我们发现,父类的私有方法对于子类来说是不可见的,注意,不可见不等于 没有,子类仍旧继承了父类所有的成员,那么这些私有的父类成员去哪了?
实际上,它们都被隐藏,对子类来说,这些父类的私有成员都被隐藏了起来,从而导致子类中的不可见。

分析以下例题:
class A {
    private void method(String str, int i) {
        System.out.println("SuperClass method()");
    }
}

class B extends A {
    public static void main(String[] args) {
        // error! 父类中的私有方法对于子类来说是隐藏的,不可在子类中访问已被隐藏的成员
        // new B().method("",0);
    }
}

构造方法在继承中的使用
分析例题:
class A {
    A() {
        System.out.println("A()");
    }
}

class B extends A {
    B() {
        System.out.println("B()");
    }

    public static void main(String[] args) {
        new B();
    }
}

执行结果为分别打印:
        A()
        B()
分析得知,父类的对象是优先于子类对象而存在的(在现实生活中也是如此),也就是说,父类对象的构造在子类对象构造之前,先调用父类构造方法创建父类对象,再调用子类构造方法创建子类对象。
因此,在继承中,父类和子类的构造方法的调用次序如下:先调用父类构函再调用子类构函!

当然,不管是构造父类对象还是子类对象,都必须遵循以下步骤执行:
         a.静态语句的执行
         b.成员变量的初始化
         c.语句块的初始化
         d.构造方法的执行

         分析例题5()的执行结果。

super关键字
构造方法不能被继承,因此,在子类中调用父类构造方法只能通过super关键字来实现。super可以理解为父类在子类中的一个对象,我们可以象使用父类对象一样使用子类对象。
例:
class A {
    A() {
        System.out.println("A()");
    }
}

class B extends A {
    B() {
        super(); // 调用父类A的构造方法,打印"A()"语句
        System.out.println("B()");
    }
}

当执行new B()语句时,结果仍是:
        A()
        B()
因此,我们通过super关键字显示地调用父类的构造 函数 ,当然,也可以象使用this对象一样通过super调用父类的成员方法。比如:super.m1()等
但是,必须得注意:父类构造 函数 只能在子类构造 函数 中通过super显示调用,并且必须是第一句!
下面语句是错误的:
        B()
        {
            System.out.println("B()");
            //error! super()语句必须是方法中的第一条语句!
            super();  
        }

你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-20 08:10
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
包装类
对于每一个java基本数据类型,java都提供了对应的包装类,如:Boolean、Character、Integer、Double等8种包装类。

在java中,包装类主要是用于将基本数据类型与对象之间进行转换连接 。
        int num = 10;
String str = (String)num;
当执行第二条语句时,就会产生转换异常,因为我们在将一个非对象类型转换成一个对象类型!问题就是,我们应该怎样才能把基本类型转换成对象,很幸运的是,java的包装类就是为了专门解决这个问题而诞生的,我们修改以上语句,修改结果如下:
        int num = 10;
        Integer numObj = new Integer(10);
        String str = (String)numObj;
这样,就能正常实现转换,因此,可以得知,包装类就是解决基本类型转换成对象的专用类。
在5.0中,java已实现了自动装、拆箱,即基本类型和对应的包装类之间可以直接赋值,转换的工作由虚拟机代劳了!
    Integer numObj = 10;语句是正确的!其中基本类型到包装类的自动转换我们称之为自动装箱,反过来就是自动拆箱,比如:
        Integer numObj = 10; //自动装箱
        int num = numObj;    //自动拆箱
因为java是面向对象语言,我们在许多场合都会将基本类型作为一个对象来处理,因此,包装类就起到了很方便的作用!
包装类有许多共同的方法和静态常量:
        valueof(***) --static方法,将对应的基本类型转换成包装类
        parseXXX(String)   --static方法,将字符串转换成对应的基本类型
        toString()   --static方法,将基本类型转换成字符串对象。
        SIZE --静态常量,返回对应基本类型占用的字节位大小。
        TYPE --静态常量,返回对应的基本数据类型名称

== 与 equals()
在java中,==与equals()都是用来比较引用,只是==即可以比较基本类型,也可以比较对象,而equals()则只能在对象之间进行引用比较。
先来了解一下==运算符,分析一下语句执行结果:
        int num1 = 10;
        int num2 = 10;
        System.out.println(num1 == num2);  //打印true
        String str1 = new String("123");
        String str2 = new String("123");
        System.out.println(str1 == str2);  //打印false
可以看出,由于基本类型不是对象,即不存在引用,所以==运算符只会比较两个基本类型的值,但当==作用于对象时,我们可以通过第二条打印语句发现,虽然str1与str2都是引用相同的值"123",但是这两个对象分别是引用两个不同内存地址的值,即引用不相同,因此str1 == str2返回false,==作用于对象时,比较的是两个对象的引用是否相同!
==运算符进行等值比较。也就是说,对于任何引用值X和Y,当且仅当X和Y指向同一对象时, X==Y返回真。
Java.lang包中的Object类有public boolean equals(Object obj)方法。它也比较两个对象是否相等。仅当被比较的两个引用指向同一对象时,对象的equals()方法返回true。
Object类的equals()方法很少被使用,因为,多数情况下我们希望比较两个对象的内容,而不是判断两个引用是否指向同一对象。
String类中的覆盖equals()方法返回true,当且仅当参数是一个不为null 的String对象,该对象与调用该方法的String对象具有相同的字符顺序。例如:
        String s1 = new String("JDK1.2");
        String s2 = new String("JDK1.2");
方法s1.equals(s2)返回真,尽管s1和s2指向两个不同的对象。
下面的例子使用equals方法测试雇员的名字和生日:
public class Employee {
    private String name;

    // private Mydate birthDate;
    private float salary;

    public Employee(String name, float salary) {
        this.name = name;
        // this.birthDate = Dob;
        this.salary = salary;
    }

    public boolean equals(Object o) {
        boolean result = false;
        if ((o != null) && (o instanceof Employee)) {
            Employee e = (Employee) o;
            if (name.equals(e.name)) {
                result = true;
            }
        }
        return result;
    }

    public int hashCode() {
        return (name.hashCode());
    }
}

我们覆盖了hashCode方法。这样做保证了相同的雇员对象有相同的hashCode。

下面的程序判断两个雇员对象引用是否相同:
public class TestEquals {
    public static void main(String[ ] args){
        Employee emp1 = new Employee("Fred Smith", 25000.0F);
        Employeeemp2 = new Employee("Fred Smith", 25000.0F);
if(emp1 == emp2){
            System.out.println("emp1 is identical to emp2")'
        }else{
            System.out.println("emp1 is not identical to emp2")'
        }

        if(emp1.equals(emp2) ){
            System.out.println("emp1 is equals to emp2")'
        }else{
            System.out.println("emp1 is not equals to emp2")'
        }

        emp2 = emp1;
        System.out.println("set emp2 = emp1");
        if(emp1 == emp2){
            System.out.println("emp1 is identical to emp2")'
        }else{
            System.out.println("emp1 is not identical to emp2")'
        }
    }
}
执行结果为:
        emp1 is not identical to emp2
        emp1 is equals to emp2
        set emp2 = emp1
        emp1 is identical to emp2

toString( )方法
toString方法被用来将一个对象转换成String表达式。当自动字符串转换发生时,它被用作编译程序的参照。例如:
        Date now = new Date()
        System.out.println(now)
        将被翻译成:
        System.out.println(now.toString());
对象类定义缺省的toString()方法,它返回类名称和它的引用的地址(通常情况下不是很有用)。许多类覆盖toString()以提供更有用的信息。例如,所有的包装类覆盖toString()以提供它们所代表的值的字符串格式。甚至没有字符串格式的类为了调试目的常常实现toString()来返回对象状态信息。
覆盖toString()方法之前:
class A {
    public static void main(String[] args) {
        System.out.println(new A());
    }
}
执行结果是完整类名称+ @ +引用地址!(垃圾数字)
覆盖toString()方法之后:
class A {
    public String toString() {
        return "This is object of Class A";
    }

    public static void main(String[] args) {
        System.out.println(new A());
    }
}
执行结果变为:"This is object of Class A"

你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-20 08:11
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 

static关键字
static关键字用来声明成员属于类,而不是属于类的对象。
1. static (类)变量
类变量可以被类的所有对象共享,以便与不共享的成员变量区分开来。        
2. static (类)方法
静态方法可以通过类名直接调用该方法,而不用通过对象调用。
例如:
class PersonCount {
    private int personID;

    private static int num = 0;

    public PersonCount() {
        num++;
        personID = num;
    }

    public static String getPersonDes() {
        return "this is a policeman";
    }
}

class TestPersonCount {
    public static void main(String[] args) {
        // 直接用类名来访问该静态方法,而不需要该类的对象
        String s = PersonCount.getPersonDes();
        System.out.println(s);
    }
}

main()是静态的,因为它必须在任何实例化发生前被顺序地访问,以便应用程序的运行。
静态方法不能被覆盖成非静态。同样,非静态方法也不能被覆盖成静态方法。
        
3 "单态 "设计模式
单态 设计模式,也就是说一个类只产生一个对象。那么怎么才能做到这一点呢?我们知道构造器是用来构造对象的。首先要对构造器入手。既然只产生一个对象,那么我们就干脆先一刀砍断,把构造器的访问权限定义成私有,不能在类的外面再构造该类的对象。也就是说只能在类的里面调用该类的构造器来产生对象。那么在该类里应该定义一个静态的属性,并初始化该类的一个对象。(原因是静态的东西只执行一次,也就是说该属性只初始化一次。那么每次得到的应该是同一个实例)
class TestSC {
    public static void main(String[] args) {
        SingleClass sc1 = SingleClass.sc;
        SingleClass sc2 = SingleClass.sc;
        sc1.test();
        sc2.test();
    }
}

class SingleClass {
    int i = 0;

    static SingleClass sc = new SingleClass();

    private SingleClass() {
    }

    public void test() {
        System.out.println("hello " + (++i));
    }
}

运行的结果为:
                hello 1
                hello 2
说明是同一个实例。
在类的设计的时候,我们也应该遵守封装的要求。把属性定义成私有的。再定义一个共有的方法来去到该属性的值。
改后的代码:
class TestSC {
    public static void main(String[] args) {
        SingleClass sc1 = SingleClass.getSingleClass();
        SingleClass sc2 = SingleClass.getSingleClass();
        sc1.test();
        sc2.test();
    }
}

// 型态1:此时,还是可以直接调用类静态变量,得到类对象,还不完全达到我们的设定
class SingleClass {
    int i = 0;

    private static SingleClass sc = new SingleClass();

    private SingleClass() {
    }

    /*
     * 因为在类的外面不能来构造给类的实例了, 所有该方法定义成静态的,通过类名直接可以调用。
     */
    public static SingleClass getSingleClass() {
        return sc;
    }

    public void test() {
        System.out.println("hello " + (++i));
    }
}

// 型态2:此时,只能调用类静态方法,得到类对象
class SingleClass {
    int i = 0;

    private static SingleClass sc = null;

    private SingleClass() {
    }

    /*
     * 因为在类的外面不能来构造给类的实例了, 所有该方法定义成静态的,通过类名直接可以调用。
     */
    public static SingleClass getSingleClass() {
        if (sc == null) {
            sc = new SingleClass();
        }

        return sc;
    }

    public void test() {
        System.out.println("hello " + (++i));
    }
}
 
final关键字
1 、final类
Java编程语言允许关键字final修饰类。如果这样做了,类便不能被继承。比如,类Java.lang.String就是一个final类。这样做是出于安全原因,因为它保证,如果方法有字符串的引用,它肯定就是类String的字符串,而不是某个其它类的字符串。
2 、final方法
方法也可以被标记为final。被标记为final的方法不能被覆盖。这是由于安全原因。如果方法具有不能被改变的实现,而且对于对象的一致状态是关键的,那么就要使方法成为final。
被声明为final的方法有时被用于优化。编译器能产生直接对方法调用的代码,而不是通常的涉及运行时查找的虚拟方法调用。
被标记为static或private的方法被自动地final。
3 、final变量
如果变量被标记为final,其结果是使它成为常数。想改变final变量的值会导致一个编译错误。下面是一个正确定义final变量的例子:
            public final int PI = 3.14;   
   
扩展知识:
内部类
    内部类,有时叫做嵌套类。内部类允许一个类定义被放到另一个类定义里。内部类是一个有用的特征,因为它们允许将逻辑上同属性的类组合到一起,并在另一个类中控制一个类的可视性。内部类可以访问外部类的属性和方法。你可以把内部类看作"方法"一样,在使用的时候调用执行。你也可以把内部类看作"属性"一样,在构造内部类对象的时候,也会在堆里为内部类的属性分配存储空间。所以内部类也有类似像修饰属性,方法那样的修饰符,比如:public,private,static 等等。当一个类没有用static  关键字修饰的时候,这个内部类就叫做成员类,类似属性,方法,作为类的成员。

成员内部类:
public class OC1 {
    private int size;
   
    public class IC {
        public void addSize() {            
            size++;
        }
    }

    public void testTheIC() {
        IC i = OC1.new IC();
        i.addSize();
    }
}
    内部对象拥有一个外部对象的引用:
图片附件: 游客没有浏览图片的权限,请 登录注册

例2:
这个例子阐述了如何在其它类(外部类的外部)实例化内部类:
class OC2 {
    private int size;

    public class IC {
        public void addSize() {
            size++;
        }
    }
}

public class TestIC // Test Inner Class
{
    public static void main(String[] args) {
        OC2 outer = new OC2();

        // 因为是成员内部类,所以必须用外部类的对象来构造内部类的对象,类似调用方法一样。
        OC2.IC inner = outer.new IC();
        inner.addSize();
    }
}

内部类要在外部类实例的上下文中实例化:
图片附件: 游客没有浏览图片的权限,请 登录注册


例3
this的一个作用是调用本类的其它构造器,另外一个作用就是做隐含参数的调用,代表当前的实例。完整的写法应该是 该类的类名.this 如下例:
本例阐述如何区分同名变量:
public class OC3 {
    private int size;

    public class IC // Inner Class
    {
        private int size;

        public void addSize(int size) {
            // 方法里的临时变量,当方法执行完自动消失
            size++;
            this.size++;
            // 代表本类的当前对象,全称是IC.this.size++;
            OC3.this.size++;
        }
    }
}
例4
静态内部类(也叫顶层类):
class OC4 {
    private static int size;

    // 声明一个内部类 叫 "IC"
    public static class SIC // Static Inner Class
    {
        public void addSize() {
            // 访问外部类的属性
            size++;
        }
    }

}

public class TestSIC // Test Static Inner Class
{
    public static void main(String[] args) {
        // 因为内部类是静态内部类,所以直接可以构造内部类的一个对象,与调用静态方法类似
        OC4.SIC inner = new OC4.SIC();
        inner.addSize();
    }
}

例5
方法内部定义内部类:
class OC5 {
    // 内部类访问,应该定义成final
    public Object makeObject(final int i) {
        class MIC // Methord Inner Class
        {
            int k = i;

            public String toString() {
                return ("属性k :" + k);
            }
        }
        return new MIC();
    }

    public static void main(String[] args) {
        OC5 oc = new OC5();
        Object o = oc.makeObject(5);
        System.out.println(o);
    }
}

注意:在方法中定义的内部类的方法,不能访问外方法的运行时变量空间(line 10),可以访问外方法的非运行时变量空间(line 11)。
例6
匿名内部类:有时候定义一个类,并不需要提供名字。所以叫匿名类。
class OC6 {
    // 多态,传递的参数应该是实现该接口的任何类产生的对象
    public void testFly(Fly f) {
        f.fly();
    }

    public static void main(String[] args) {

        OC6 oc = new OC6();
        // 画下划线的代码就是构造了实现Fly接口的某个类的对象,类名并不需要知道,只
        // 知道该对象具有接口的功能就行。
        oc.testFly(new Fly() {
            public void fly() {
                System.out.println("fly higher and higher");
            }
        });
    }
}

interface Fly {
    public void fly();
}

匿名类具有广泛性。不只是对接口才有,对抽象类或者具体的类都适用。例如:
class OC7 {
    public static void main(String[] args) {
        System.out.println(new Person() {
            public String toString() {
                return "this is a person";
            }
        });
    }
}

class Person {
}
注意:如果是接口或者抽象类的话,在匿名类里面必须实现接口或者抽象类里所有的抽象方法。如果是具体的类的话就没必要了,需要的话可以覆盖方法,不需要时可以不写任何代码。看下例:
class OC7 // Outer Class 7
{
    public static void main(String[] args) {
        // 这里其实是Person类里的一个子类,只不过该子类并没有扩展功能
        System.out.println(new Person() {
        });
    }
}

class Person {
    public String toString() {
        return "this is a person";
    }
}
内部类有如下属性:
    1 内部类只在定义他们的代码段内可见。
    2 内部类可以被定义在方法中。如果方法中的变量被标记为final,那么,就可以被内部类中的方法访问。
    3 内部类可以使用所嵌套类的类和实例变量以及所嵌套的块中的本地变量。
    4 内部类可以被定义为abstract.
    5 只有内部类可以被声明为private或protected,以便防护它们不受来自外部类的访问。
    6 一个内部类可以作为一个接口,由另一个内部类实现。
    7 被声明为static的内部类自动地成为顶层类。这些内部类失去了在本地范围和其它内部类中使用数据或变量的能力。
    8 内部类不能声明任何static成员;只有顶层类可以声明static成员。因此,一个需求static成员的内部类必须使用来自顶层类的成员。


你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-20 08:15
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
抽象类,接口
抽象类    Java语言允许你在一个类中声明一些方法,然而又不实现它。这种方法叫抽象方法。包含一个或多个抽象方法的类叫做抽象类。你可以在抽象类的子类中实现抽象方法。抽象类只能被其它类继承,不能用来创建实例。
如图设计抽象类:
图片附件: 游客没有浏览图片的权限,请 登录注册


计算fuel调用了Vehicle类的两个抽象方法,Vehicle类的抽象方法在它的子类中实现。这就是"模板方法"
接口
接口是用关键字interface来定义的,接口是客户端代码与提供服务的类之间的"规约"。接口是抽象类的变体。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。
接口的使用,弥补了Java技术单继承规则的不足。一个类可以实现多个接口。接口的实现与子类相似,当类实现某个接口时,它必须定义这个接口的所有方法。
例如:一些对象都具有飞行的能力,可以定义一个Flyer接口,它支持三种操作:
图片附件: 游客没有浏览图片的权限,请 登录注册


takeoff() 、land()、fly()。类Airplane可以实现Flyer。
interface Flyer {
    public void takeoff();
    public void land();
    public void fly();
}
public class Airplane implents Flyer{
    public void takeoff(){
        // accelerate until lift-off
        // raise landing gear
    }
    public void land(){
        // lower landing gear
        // decelerate . . .
    }
    public void fly(){
        // keep those engines running
    }
}
Java允许多个类实现同一个接口:
图片附件: 游客没有浏览图片的权限,请 登录注册

飞机是一种交通工具,并且能够飞行。鸟是一种动物,也能够飞行。这些例子说明继承与实现接口可以混合使用。
图片附件: 游客没有浏览图片的权限,请 登录注册

一个类可以实现多个接口:
图片附件: 游客没有浏览图片的权限,请 登录注册


类能实现许多接口。由类实现的接口出现在类声明的末尾以逗号分隔的列表中,如下所示:
     public class MyApplet extends Applet implements Runnable, MouseListener{ }

什么时候使用接口
    对于下述情况,应该使用接口:
    声明方法,期望一个或更多的类来实现该方法。
    揭示一个对象的编程接口,而不揭示类的实际程序体。(当将类的一个包输送到其它开发程序中时它是非常有用的。)
    捕获无关类之间的相似性,而不强迫类关系。
    描述"似函数"对象,它可以作为参数被传递到在其它对象上调用的方法中。它们是"函数指针"(用在C和C++中)用法的一个安全的替代用法.   

    结果:
            public abstract class Vehicle{
                public abstract double calcFuelEfficiency();
                public abstract double calcTripDistance();
            }
编写代码
public class Truck extends Vehicle {
    public Truck(double max_load) {
    }

    public double calcFuelEfficiecy() {
        // calculate
    }

    public double calcTripDistance() {
        // calculate
    }
}

public class RiverBarge extends Vehicle {
    public RiverBarge(double max_load) {
    }

    public double calcFuelEfficiecy() {
        // calculate
    }

    public double calcTripDistance() {
        // calculate
    }
}

你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-20 08:20
lampeter123
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:54
帖 子:2508
专家分:6424
注 册:2009-1-30
收藏
得分:0 
异常

异常的概念
在Java编程语言中,异常类定义程序中可能遇到的轻微的错误条件。你可以写代码来处理异常,并继续执行程序,而不需要让程序中止。
在程序执行中,任何中断正常程序流程的条件都是异常。例如,发生下列情况时,会出现异常:
    想打开的文件不存在
    网络连接中断
    操作数超出预定范围
    正在 装载的类文件丢失
在Java编程语言中,错误类定义被认为是不能恢复的严重错误条件。在大多数情况下,当遇到这样的错误时,建议让程序中断。
在 程序中发生错误时,发现错误的方法抛 出一个异常到其调用程序,给 出已经发生问题的信号。然后,调用方法捕获抛出的异常,在可能时,再恢复回来。这个方案给程序员一个写处理程序的选择,来处理异常。
通过浏览API,可以决定方法抛出的是什么样的异常。
异常的分类
在Java编程语言中java .lang.Throwable类充当所有对象的父类,可以使用异常处理机制将这些对象抛出并捕获。在Throwable类中定义方法来检索与异常相关的错误信息,并打印显示异常发生的栈跟踪信息。它有Error和Exception两个基本子类。
Throwable类不能直接 使用,我们 使用其 子类来捕获和描述异常信息。
异常结构如图:
图片附件: 游客没有浏览图片的权限,请 登录注册

Error表示严重的错误问题 。比如说内存溢出。不可能指望程序能处理这样的情况。
Exception 则是我们关心和需要处理的错误。
RuntimeException表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。比如,如果数组索引扩展不超出数组界限,那么,ArrayIndexOutOfBoundsException异常从不会抛出。比如,这也适用于取消引用一个空值对象变量。因为一个正确设计和实现的程序从不出现这种异常,通常对它不做处理。这会导致一个运行时信息,应确保能采取措施更正问题,而不是将它藏到谁也不注意的地方。
其它异常表示一种运行时的困难,它通常由环境效果引起,可以进行处理。例子包括文件未找到或无效URL异常(用户打了一个错误的URL),如果用户误打了什么东西,两者都容易出现。这两者都可能因为用户错误而出现,这就鼓励程序员去处理它们。
 预定义 异常
Java编程语言提供几种预定义的异常。下面是可能遇到的更具共同性的异常中的几种:
    ArithmeticException:整数被0除,运算得出的结果。
        int i = 12 / 0;
    NullPointerException:当对象没被实例化时,访问对象的属性或方法的尝试:
        Date d = null;
        System.out.println(d.toString());
    NegativeArraySizeException:创建带负维数大小的数组的尝试。
    ArrayIndexoutofBoundsException:访问超过数组大小范围的一个元素的尝试。
    SecurityException:典型地被抛出到浏览器中,SecurityManager类将抛出applets的一个异常,该异常企图做下述工作(除非明显地得到允许):
    访问一个本地文件
打开主机的一个socket,这个主机与服务于applet的主机不是同一个。
    在运行时环境中执行另一个程序
异常的处理机制
一般来说,异常的处理机制有以下三种:
try-catch-finally  主动异常处理
throws 消极异常处理
throw 引入异常
实例分析
例1
问题的描述:
    写一个常见的异常
解决方案:
请看下例:
public class TestException {
    public static void main(String args[]) {
        int i = 0;

        String ss[] = { "Hello world!", "您好,世界!", "HELLO WORLD!!" };

        for (; i < 6; i++) {
            System.out.println(ss[i]);
        }
    }
}
运行的结果为如图。
图片附件: 游客没有浏览图片的权限,请 登录注册


要处理异常,将能够抛出异常的代码放入try块中,然后创建相应的catch块的列表,每个可能被抛出异常都有一个。如果生成的异常与catch中提到的相匹配,那么catch条件的块语句就被执行。在try块之后,可能有许多catch块,每一个都处理不同的异常。
请看下例:
class TestException2 {
    public static void main(String args[]) {
        int i = 0;

        String ss[] = { "Hello world!", "您好,世界!", "HELLO WORLD!!" };

        for (; i < 5; i++) {
            try {
                System.out.println("第" + (i + 1) + "次循环:");
                System.out.println(ss[i]);
            } catch (Exception e) {
                System.out.println("数组越界");
            } finally {
                System.out.println("finally execute");
            }
        }
    }
}
运行的结果如图
图片附件: 游客没有浏览图片的权限,请 登录注册

总结:从上例可以看出:不管出现不出现异常,finally语句块都会执行。在try语句块里除了System.exit(int)语句外,finally语句块必须执行。
Throws则是自己不处理异常,而交给上级处理,俗称“异常上抛”,比如:
public static void main(String args) throws RuntimeException
这样,一旦在代码里出现RuntimeException,在本类里不做任何处理动作,而是交由上次程序或者虚拟机去处理。
自定义异常
用户定义异常是通过扩展Exception类来创建的。这种异常类可以包含一个"普通"类所包含的任何东西。下面就是一个用户定义异常类例子,它包含一个构造函数、几个变量以及方法
请看下例:
class TestMyException {
    public static void main(String[] args) {
        ABC abc = new ABD();// ABD 是 ABC的子类
        try {
            abc.a(5);
        } catch (EA e) {
            e.test();
        }
    }
}
创建自己的运行时异常,如果改成Exception,就是创建编译时的异常了,编译的时候就应该对异常处理。
class EA extends RuntimeException {
    String s;

    public EA(String s) {
        this.s = s;
    }

    public EA() {
    }

    public void test() {
        System.out.println(s);
    }
};

class EA1 extends EA // 创建自己的异常的子异常
{
    public EA1(String s) {
        super(s);
    }
};

class EA2 extends EA // 创建自己的异常的子异常
{
    public EA2(String s) {
        super(s);
    }
};

class ABC {
    public void a(int i) {
        if (i < 0)
            System.out.println("normal");
        else
            throw new EA("no normal");
    }
};

class ABD extends ABC {
    public void a(int i) {
        if (i < 0)
            System.out.println("dfsdafds");
        else if (i == 0)
            throw new EA1("参数 == 0");
        else
            throw new EA2("参数 > 0");
    }
};
运行的结果为:
     参数 > 0
方法覆盖和异常
方法覆盖要注意两点:
n    访问权限不能比父类的弱
n    抛出的异常不能比父类的多。(注意多并不是数量上的多,而是父类方法抛出的异常必须包含子类覆盖方法抛出的异常)
请看下例:
class TestMyException2 {
    public static void main(String[] args) {
        ABC abc = new ABD();
        try {
            abc.a(5);
        } catch (EA e) {
            e.test();
        }
    }
}

class EA extends Exception // 创建自己的编译时异常
{
    String s;

    public EA(String s) {
        this.s = s;
    }

    public EA() {
    }

    public void test() {
        System.out.println(s);
    }
};

class EA1 extends EA // 创建自己的异常的子异常
{
    public EA1(String s) {
        super(s);
    }
};

class EA2 extends EA // 创建自己的异常的子异常
{
    public EA2(String s) {
        super(s);
    }
};

class ABC {
    public void a(int i) throws EA {
        if (i < 0)
            System.out.println("normal");
        else
            throw new EA("no normal");
    }
};

class ABD extends ABC {
    public void a(int i) throws EA1, EA2 // 虽然抛出的异常比父类多,但是都是父类异常的子类
    {
        if (i < 0)
            System.out.println("dfsdafds");
        else if (i == 0)
            throw new EA1("参数 == 0");
        else
            throw new EA2("参数 > 0");
    }
};

运行结果为:
    参数 > 0

你的优秀和我的人生无关!!!!
    
    我要过的,是属于我自己的生活~~~
2010-07-20 08:24
快速回复:JAVA入门教程(1)
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.022307 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved