Flyingis

Talking and thinking freely !
Flying in the world of GIS !
随笔 - 156, 文章 - 16, 评论 - 589, 引用 - 0
数据加载中……

Java接口特性学习

作者:Flyingis

    在
Java中看到接口,第一个想到的可能就是C++中的多重继承和Java中的另外一个关键字abstract。从另外一个角度实现多重继承是接口的功能之一,接口的存在可以使Java中的对象可以向上转型为多个基类型,并且和抽象类一样可以防止他人创建该类的对象,因为接口不允许创建对象。

 

interface关键字用来声明一个接口,它可以产生一个完全抽象的类,并且不提供任何具体实现。interface的特性整理如下:

1.        接口中的方法可以有参数列表和返回类型,但不能有任何方法体。

2.        接口中可以包含字段,但是会被隐式的声明为staticfinal

3.        接口中的字段只是被存储在该接口的静态存储区域内,而不属于该接口。

4.        接口中的方法可以被声明为public或不声明,但结果都会按照public类型处理。

5.        当实现一个接口时,需要将被定义的方法声明为public类型的,否则为默认访问类型,Java编译器不允许这种情况。

6.        如果没有实现接口中所有方法,那么创建的仍然是一个接口。

7.        扩展一个接口来生成新的接口应使用关键字extends,实现一个接口使用implements

 

interface在某些地方和abstract有相似的地方,但是采用哪种方式来声明类主要参照以下两点:

1.        如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。

2.        如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。

 

以上就是接口的基本特性和应用的领域,但是接口绝不仅仅如此,在Java语法结构中,接口可以被嵌套,既可以被某个类嵌套,也可以被接口嵌套。这在实际开发中可能应用的不多,但也是它的特性之一。需要注意的是,在实现某个接口时,并不需要实现嵌套在其内部的任何接口,而且,private接口不能在定义它的类之外被实现。

 

posted @ 2005-11-02 21:18 Flyingis 阅读(5070) | 评论 (0)编辑 收藏

多态学习心得

作者:Flyingis

    这几天我在重新复习
Java语言基础,虽然和团队一起,自己个人都进行了实际项目的开发,但越往上面走越觉得自己应该花点时间看看Java的基础知识,巩固一下基础。今天复习的是多态,同时写下自己的学习心得。

数据抽象、继承和多态是面向对象程序设计语言的三大特性。多态,我觉得它的作用就是用来将接口和实现分离开,改善代码的组织结构,增强代码的可读性。在某些很简单的情况下,或许我们不使用多态也能开发出满足我们需要的程序,但大多数情况,如果没有多态,就会觉得代码极其难以维护。

Java中,谈论多态就是在讨论方法调用的绑定,绑定就是将一个方法调用同一个方法主体关联起来。在C语言中,方法(C中称为函数)的绑定是由编译器来实现的,在英文中称为early binding(前期绑定),因此,大家自然就会想到相对应的late binding(后期绑定),这在Java中通常叫做run-time binding(运行时绑定),我个人觉得这样称呼更贴切,运行时绑定的目的就是在代码运行的时候能够判断对象的类型。通过一个简单的例子说明:

/**

 * 定义一个基类

 */

public Class Parents {

  public void print() {

    System.out.println(“parents”);

}

}

/**

 * 定义两个派生类

 */

public Class Father extends Parents {

  public void print() {

    System.out.println(“father”);

}

}

public Class Mother extends Parents {

  public void print() {

    System.out.println(“mother”);

}

}

/**

 * 测试输出结果的类

 */

public Class Test {

  public void find(Parents p) {

    p.print();

}

public static void main(String[] args) {

  Test t = new Test();

  Father f = new Father();

  Mother m = new Mother();

  t.find(f);

  t.find(m);

}

}

最后的输出结果分别是fathermother,将派生类的引用传给基类的引用,然后调用重写方法,基类的引用之所以能够找到应该调用那个派生类的方法,就是因为程序在运行时进行了绑定。

学过Java基础的人都能很容易理解上面的代码和多态的原理,但是仍有一些关键的地方需要注意的,算是自己对多态的一个小结:

1.        Java中除了staticfinal方法外,其他所有的方法都是运行时绑定的。在我另外一篇文章中说到private方法都被隐式指定为final的,因此final的方法不会在运行时绑定。当在派生类中重写基类中staticfinal、或private方法时,实质上是创建了一个新的方法。

2.        在派生类中,对于基类中的private方法,最好采用不同的名字。

3.        包含抽象方法的类叫做抽象类。注意定义里面包含这样的意思,只要类中包含一个抽象方法,该类就是抽象类。抽象类在派生中就是作为基类的角色,为不同的子类提供通用的接口。

4.        对象清理的顺序和创建的顺序相反,当然前提是自己想手动清理对象,因为大家都知道Java垃圾回收器。

5.        在基类的构造方法中小心调用基类中被重写的方法,这里涉及到对象初始化顺序。

6.        构造方法是被隐式声明为static方法。

7.        用继承表达行为间的差异,用字段表达状态上的变化。

posted @ 2005-10-31 19:28 Flyingis 阅读(1178) | 评论 (1)编辑 收藏

用Java实现自动在数据库表中生成ID号[原创]

    作者:Flyingis

    前段时间用Struts开发了一个B/S结构的信息管理系统,其中有一个功能是要求管理员能够对数据字典进行修改,数据字典的表结构基本上都是table(id, name),id为数据库其它表中所存储的内容,表示方式为A01、A02、A08、B10、B25、C12等等,一个字典就分配一个字母作为其ID号的标识,其实就是为了调试时方便,在其它的表中判断该字典的名称。因此对于一个特定的字典表来说,其ID号排序应该是A01、A02、A03、A04…… 

    在对字典内容进行删除的时候并不需要考虑什么,直接使用DELETE语句就可以了。关键是添加字典信息时,管理员需要在表单中填写的是table中的name字段,ID号如何生成就需要自己用代码来实现(包括ID号的01号空缺,中间有断开等情况)。下面是我设计的代码,其中关键的地方都有详细的注释:

/* 
 * 功能:增加字典信息时,自动生成最小的ID号码
 * 参数:String 字典表名称 first 字典ID的首字母,代表唯一的字典
 * 返回:String 生成的最小ID号码
 */
public String getId(String table, String first) {

// 所有除去首字母后的ID号码--整型,例如:11
int[] sid;
// 所有原始ID号码,例如:A11
String[] rid;
// 除去首字母后最小的ID号码--字符串
String sid_new = null;
// 程序返回的最小的原始ID号码
String rid_new = null;

        // 循环参数
int i = 0;
int k = 0;

con = DatabaseConnection.getConnection("jdbc/wutie");
Statement stm = null;
ResultSet rst = null;
RowSet rowRst = null;
String sql = "SELECT * FROM " + table + " order by id";

try {
    if (con.isClosed()) {
        throw new IllegalStateException("error.sql.unexpected");
    }
    stm = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
    rst = stm.executeQuery(sql);
    
    while (rst.next()) {
     k++;
     }
    sid = new int[k];
    rid = new String[k];
    rst = stm.executeQuery(sql);
    // 如果不存在结果集,则直接在first字母后面加01,例如first="A",rid_new=A01
    if (!rst.first()) {
     rid_new = first.concat("01");
     return rid_new;
     }
            // 如果存在结果集,则将表中所有ID号存入数组中,并转换为整型数据
    else {
     /*
    while (rst.next()) {
        rid[i] = rst.getString("id");
        sid[i] = Integer.parseInt(rid[i].substring(1));
        i++;
        }
        */
     for (rst.previous(); rst.next(); i++) {
     rid[i] = rst.getString("id");
     sid[i] = Integer.parseInt(rid[i].substring(1));
     }
     // 如果第一条记录ID号不为fisrt+01,例如A03、A05、A18等,则返回新增数据的ID号为A01
     if (sid[0] != 1) {
     rid_new = first.concat("01");
     return rid_new;
     }
     // 如果第一条记录ID号为first+1,即A1,则执行下面语句
    else {
     // 如果总记录数只有一条,例如A1,则返回新增数据为A02
     if (i == 1) {
     rid_new = first.concat("02");
     return rid_new;
     }
     else {
    for (int j = 1; j < k; j++) {
     // 如果相邻两条记录ID号的整数位相差1,则保存新增数据ID号整数位是前一位ID号整数位加1
     if (sid[j] == sid[j-1] + 1) {
     if (sid[j] < 9) {
     sid_new = String.valueOf(sid[j] + 1);
    rid_new = first.concat("0").concat(sid_new);
     }
     else {
     sid_new = String.valueOf(sid[j] + 1);
    rid_new = first.concat(sid_new);
     }
     }
// 如果相邻两条记录ID号的整数位相差非1,则返回新增数据ID号整数位是前一位ID号整数位加1
if (sid[j] != sid[j-1] + 1) {
if (sid[j-1] < 9) {
    sid_new = String.valueOf(sid[j-1] + 1);
    rid_new = first.concat("0").concat(sid_new);
    return rid_new;
}
else {
    sid_new = String.valueOf(sid[j-1] + 1);
    rid_new = first.concat(sid_new);
    return rid_new;
}
    }
}
    return rid_new;
     }
     }
     }     
}
catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("error.sql.runtime");
}
finally {
try {
stm.close();
con.close();
}
catch (SQLException e1) {
e1.printStackTrace();
throw new RuntimeException("error.sql.runtime");
}
}

}
    
    注意:之所以生成A01而不是A1,是因为在SQLServer2000中根据ID号正确排序的需要,如果按照升序排列,A1后面是A10、A11等,而不是A2。另外,在Hibernate中有多种自动生成ID字段的方法,但是这个项目比较小,我没有使用Hibernate中间件,这里提供的只是生成字典ID字段的一种简单思路,只能用于字典项不多于100项的情况,一般的情况可以满足了,但如果超过100项只需简单修改一下代码,不足之处还请大家多指教!

posted @ 2005-10-31 11:37 Flyingis 阅读(1070) | 评论 (1)编辑 收藏

小议final关键字

作者:Flyingis

      final
Java语言中一个很微妙的关键字,而使用它通常出于两种理由:设计与效率。我们可以对数据成员、方法和类使用final关键字。
   
final数据的声明是为了告诉编译器有一块数据是恒定不变的。对于基本数据类型,编译器可以将该常量值代入任何可能用到它的计算式中去,即可以在编译时执行计算,这样就减轻了一些运行时的负担。在对这个常量进行定义的时候,必须对其进行赋值,当然也可以在类的构造函数中赋值。当对对象引用使用final声明时,其含义容易让人迷惑,因为对于对象的引用,final可以使引用恒定不变,它可以使该引用始终指向一个对象,但是,对象自身是可以被修改的,所以在这种情况下感觉final几乎没什么作用,数组也是对象,它也存在这种情况,通过下面这个例子说明:


class Fruit {

  private final int[] m = {1, 2, 3};

  public static void main(String[] args) {

Fruit f = new Fruit();

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

  f.m[i]++;  //可以改变

}

f.m = new int[5];  //不能指向另外的一个对象,错误!

}

}

    对基本数据类型的数据使用
final的另外一个用处就是可以做到根据对象的不同而使类的功能发生改变,例如:

class Apple {

  private final int i;  //没有初始化,需要在构造函数中赋值

  private static Random r = new Random();

  public Apple() {

    i = r.newInt(10);

}

public Apple(int j) {

  i += j;

}

}

    使用final方法,可以把方法锁定,防止继承类修改它。并且使用方法类在一般情况下可以提高效率,让编译器将针对该方法的所有调用都转为内嵌式的调用,即以方法体中的实际代码来代替方法调用的代码,这样就消除了方法调用的开销。但是对于private类型的方法而言意义不大,因为private方法都已经被隐式的制定为final,如果继承类试图将该方法声明为public/protected/默认的同名方法,将不能覆盖基类中的方法,这样做是声明了一个新的方法,这是Java中的多态,但是也说明了private方法将不会起到什么作用。
   
final类的设计是为了防止以后对该类进行变动,并不希望它有子类,在final类中所有的方法都隐式指定为final的,并且这些方法无法被覆盖,而final类的字段将保持原义,不受final类的影响!

   
这段时间在重新复习Java中的基本细节与概念,欢迎拍砖!共同学习!

posted @ 2005-10-28 21:50 Flyingis 阅读(2363) | 评论 (1)编辑 收藏

在Linux下安装JDK及环境设置

作者:Flyingis

我在Fedora Core 3上已经成功安装了jdk(jdk-1_5_0_02-linux-i586.rpm),其它版本的Linux基本相同,过程如下:

1. 先从网上下载jdk(jdk-1_5_0_02-linux-i586.rpm) ,推荐SUN的官方网站www.sun.com,下载后放在/home目录中,当然其它地方也行。

进入安装目录
#cd /home
#cp jdk-1_5_0_02-linux-i586.rpm /usr/local
#cd /usr/local
给所有用户添加可执行的权限
#chmod +x jdk-1_5_0_02-linux-i586.rpm.bin
#./jdk-1_5_0_02-linux-i586.rpm.bin
此时会生成文件jdk-1_5_0_02-linux-i586.rpm,同样给所有用户添加可执行的权限
#chmod +x jdk-1_5_0_02-linux-i586.rpm
安装程序
#rpm -ivh jdk-1_5_0_02-linux-i586.rpm
出现安装协议等,按接受即可。

2.设置环境变量。
#vi /etc/profile
在最后面加入 
#set java environment
JAVA_HOME=/usr/java/jdk-1_5_0_02
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
保存退出。

要使JDK在所有的用户中使用,可以这样:
vi /etc/profile.d/java.sh
在新的java.sh中输入以下内容: 
#set java environment
JAVA_HOME=/usr/java/jdk-1_5_0_02
CLASSPATH=.:$JAVA_HOME/lib/tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
保存退出,然后给java.sh分配权限:chmod 755 /etc/profile.d/java.sh

3.在终端使用echo命令检查环境变量设置情况。
#echo $JAVA_HOME
#echo $CLASSPATH
#echo $PATH

4.检查JDK是否安装成功。
#java -version
如果看到JVM版本及相关信息,即安装成功!

posted @ 2005-10-28 15:59 Flyingis 阅读(86479) | 评论 (27)编辑 收藏

Java中存储数据的地方

   作者:Flyingis

   在
Java
程序运行时有6个地方可以存储数据:

1.寄存器:这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。
2.
堆栈:位于通用RAM中,但通过堆栈指针可以从处理器那里获得直接支持。
3.
堆:一种通用的内存池(也位于RAM),用于存放所有的Java对象。
4.
静态存储:这里的静态指的是在固定的位置”(尽管也在RAM),存放程序运行时一直存在的数据。
5.
常量存储:常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。
6.
RAM存储:如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序中没有运行时也可以存在。

       
Java程序设计时经常用到一系列类型,比如char/byte/int/long/float等等,我们有两种方式创建方式,例如创建一个String类型的引用并初始化为“Java”

        String s = "Java";
       
 String s = new String("Java");

       
采用第一种方式创建了一个并非是引用的变量,它的值为“Java”,置于堆栈之中。而第二种方式创建了一个对象,它被存储在堆里,不及在堆栈中高效。因此,当我们需要创建一个很小的、简单的变量时,采用第一种方式更好。这是Java数据存储的一个细节。

posted @ 2005-10-28 15:48 Flyingis 阅读(952) | 评论 (3)编辑 收藏

仅列出标题
共6页: 上一页 1 2 3 4 5 6