活在JAVA岛的快乐日子

 
 

常用链接

  • 我的随笔
  • 我的评论
  • 我的参与
  • 最新评论

留言簿(4)

  • 给我留言
  • 查看公开留言
  • 查看私人留言

随笔档案

  • 2006年2月 (2)
  • 2005年12月 (1)
  • 2005年11月 (13)

文章分类

  • DATABASE(2) (rss)
  • JAVA PROGRAMING (rss)

文章档案

  • 2007年1月 (2)

Links

  • Flyingis
  • JAVA牛棚
  • oksonic博客
  • Willpower's Java Zone
  • 水木尤寒

搜索

  •  

最新评论

  • 1. re: JAVA STATIC 关键字[未登录]
  • 很好很强大
  • --1
  • 2. re: Servlets/JSP开发技术问答(转贴)[未登录]
  • 这是什么乱七八糟的啊
    大部分都说一半
  • --kkk
  • 3. re: 好象搞懂了
  • 很有启发 实际上通过static可以“主动”初始化一些东西 而不必再手工调用方法进行初始化了

    感谢楼主
  • --yeqiufeng

阅读排行榜

  • 1. JAVA STATIC 关键字(3972)
  • 2. JSP内建对象- - (1576)
  • 3. Vetor Arraylist list(1253)
  • 4. java.util包(转贴)(1175)
  • 5. Thinking IN java 访问权限(978)

评论排行榜

  • 1. Servlets/JSP开发技术问答(转贴)(1)
  • 2. 好象搞懂了(1)
  • 3. JAVA STATIC 关键字(1)
  • 4. Thinking IN java 访问权限(0)
  • 5. java的事件(转)(0)

Powered by: 博客园
模板提供:沪江博客
BlogJava | 首页 | 发新随笔 | 发新文章 | 联系 | 聚合 | 管理

JAVA STATIC 关键字
Static  :
对于类的属性来说
有类变量和实例变量
class StaticTest
{  static int i=47;
}
对于不同的对象  StaticTest st1=new StaticTest(),StaticTest st2=new StaticTest()都只有一个共享的存储空间!
引用Static变量有两种方法.可以用一个对象去定位他。.也可以用其类名直接调用!
如果一个成员被声明为static,他就能够在他的类的对象被创建之前被访问,不必引用任何对象。最常见的例子是main()方法,
static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何;
Java变量在类这个级别分两种,类变量(static)和实例变量,而在静态的方法中不能够直接访问实例变量,实例变量需要初始化一个类的实例才可以用。


静态的东西之所以有这种区分是为了区别对待类和对象的成员。如果某个变量或者方法被声明为static,意味着在类初始化时就必须分配内存空间。而方法调用内部需要的变量既然是临时的,会随着方法调用结束而失效的,那么没有道理让它成为static的对吧

1.静态变量属于类,为该类所有对象所分享,在程序开始执行前就分配内存空间,其作用可以类似VB中的全局变量,如果前面加上final,功能类似全局常量,不可以修改其值.比如圆周率

2.类的静态方法不能访问类的实例变量,可以访问类的静态变量、实例化的类的实例变量

3.静态方法中不能定义静态变量的

前几天在csdn上看了一篇关于static的帖子,看了之后感觉很多疑惑都澄清了,今天粘在这里。

public class ExplicitStatic{
  public static void main(String[] args){
    System.out.println("Inside main()");
      Cups.c1.f(99);
 }
 static Cups x=new Cups();
 static Cups y=new Cups();
}
class Cup{
      Cup(int marker){
         System.out.println("Cup("+marker+")");
      }
      void f(int marker){
         System.out.println("f("+marker+")");
      }
}
class Cups{
  static Cup c1=new Cup(11);
  static Cup c2;
  Cup c3=new Cup(33);
  Cup c4;
 { c3=new Cup(3);
   c4=new Cup(4);
 }
 static{
   c1=new Cup(1);
   c2=new Cup(2);
 }
 Cups(){
 System.out.println("Cups()");
  }
}
/*输出结果:
cup(11)
cup(1)
cup(2)
cup(33)
cup(3)
cup(4)
cups()
cup(33)
cup(3)
cup(4)
cup()
inside main()
f(99)
*/
/*
首先初始化的是static,顺序是代码顺序up-to-down!然后在是自己调用的方法!
上面的执行顺序是
1: static Cups x=new Cups(); 转入 Cups对象
2: static Cup c1=new Cup(11); 转入 Cup对象
3: 执行Cup的输出 Cup(11);
4:  cups对象里的 static Cup c2;
5: static{
   c1=new Cup(1);转入Cup对象 输出 Cup(1)
   c2=new Cup(2);转入Cup对象 输出 Cup(2)
 }
6: cups对象里的 Cup c3=new Cup(33); 输出 Cup(33)
7:c3=new Cup(3); 输出 Cup(3)
   c4=new Cup(4); 输出 Cup(4)
8:Cups(){
 System.out.println("Cups()"); 输出 Cups()
  }
9:static Cups y=new Cups();
 注意Cups里的static成员已经初始化 所以 static Cup c1=new Cup(11);
 static Cup c2;static{
   c1=new Cup(1);
   c2=new Cup(2);
 }
 不在执行!
下面的就和上面一样了!
*/

首次使用的地方也是static初始化发生的地方。装载的时候,所有static对象和static代码块都会按照本来的顺序初始化(亦即它们在类定义代码里写入的顺序)。当然,static数据只会初始化一次。

程序一开始访问MAIN方法,然后开始一加载对应的CLASS文件,如果他具有基类,加载基类,最后完成STATIC的初始化,


posted @ 2005-11-12 14:42 活在JAVA岛的日子 阅读(3972) | 评论 (1) | 编辑 收藏
 
Thinking IN java 访问权限

对于继承,static :hide;non static :override.
  
关键字:包访问权
当属性或方法前不声明访问权是默认为包访问权.
具有包访问权的方法或者属性只能被同一个包内的其他类访问.
处于相同目录的类之间具有默认的包访问权限.即可以访问其他文件的包访问权限方法.
//处于不同包类不能访问具有包访问权限的方法或属性.
package animal;
public class animal
{
 void bite()
 {
 System.out.println("bite");
 }
}
package test;
import animal.*;
public class test
{
   public static void main(String args[])
   {

       animal animal=new animal();
       animal.bite();//因为bite()只具有包访问权
}
}
// 处于相同目录的类之间具有默认的包访问权限.即可以访问其他文件的包访问权限方法.
public class test
{
   public static void main(String args[])
   {
   animal animal=new animal();
   animal.bite();
  }
}
public class test
{
   public static void main(String args[])
   {
   animal animal=new animal();
   animal.bite();
  }
}

package test;
import animal.*;
public class dog extends animal    继承但是不属于同一个包
{
   public static void main(String args[])
   {
      dog dog=new dog();
      dog.bite();//bite只是具有包访问权

   }
}
PROTECTED 关键字:继承访问权限! 
导出类可以使用在基类定义为PROTECTED的方法,对于同一个包的非继承关系类具有包访问权!
在同一个包中,可以通过在子类中超类的实例来访问超类的protected变量,而不在同一个包中,就不能这样做
protected 指定该变量可以被同一个包中的类或其子类访问,但是不能通过超类的实例来实现,在子类中可以覆盖此变量
public class animal
{
 protected void bite()
 {
System.out.println("bite");
 }
}
public class test
{
   public static void main(String args[])
   {
   animal animal=new animal();
   animal.bite();
  }
}
导出类可以使用基类的PROTECTED方法
package animal;
public class animal
{
 protected void bite()
 {
 System.out.println("bite");
 }
}

package test;
import animal.*;
public class dog extends animal
{
   public static void main(String args[])
   {
      dog dog=new dog();
      dog.bite();//bite只是具有包访问权
}
}
Private关键字
具有Private关键字的方法只能被定义该方法的内部
public class animal
{
  private String s="fasf";
  private void test()
  {}
 protected void bite()
 { System.out.println("bite");}
}
public class test
{
   public static void main(String args[])
   {
   animal animal=new animal();
   //animal.s="fafaf";  can not access private
  // animal.test();    can not access private 
   animal.bite();
  }
}
//私有构造函数
class privatetest
{
    private privatetest()
    {}
    public static privatetest make()
    {
    return new privatetest();
    }
    public void f()
    {
  System.out.println("success");
 }
}
public class test
{
   public static void main(String srgs[])
   {
       privatetest pt=privatetest.make();
       pt.f();
 }
}
类的访问权限  类的访问权限只能是缺省或者是"public"
//包访问权限:
package animal;
 class animal
{
 protected void bite()
 { System.out.println("bite");}
}
package test;
import animal.*;
public class test
{
   public static void main(String args[])
   {  animal animal=new animal();  // can  not access from outside package;
       animal.bite();//因为bite()只具有包访问权
     }
}

posted @ 2005-11-12 11:57 活在JAVA岛的日子 阅读(978) | 评论 (0) | 编辑 收藏
 
java的事件(转)

JAVA事件的总结(转)- -

                                      

在阿泠的自省上看到的文章,虽然我现在还没有看到事件,不过先收录过来^_^。

JAVA事件无非就是键盘事件,鼠标事件,按钮等事件。专业点可以分为语义事件(按钮等到事件)和低层事件(键盘事件,鼠标事件);

下面我简要的总结一下:

1、鼠标事件:点鼠标按钮事它会调用三个监听器方法:mousePressed,mouseReleased,mouseClicked.


鼠标事件提供了mousePressed,mouseClicked,mouseDragged,mouseEntered,mouseExited, mouseUp,mouseDown,mouseDrag等事件。下面介绍一个鼠标一例子:
import java.awt.*;
import java.applet.Applet;
public class CountClick extends Applet
{int CurrentMarks=0;
int a,b;
 public boolean mouseDown(Event evt,int x,int y)//鼠标按下时做的事
 { CurrentMarks++;//计录按下次数
   repaint();//刷新面版
   a=x;//得到鼠标的横坐标
   b=y;//得到鼠标的竖坐标
   return true;
 }
 public void paint(Graphics g)
 { g.drawString(" "+CurrentMarks,10,10);//打印按下次数
   g.drawString(" "+a,10,30);//打印鼠标的横坐标
   g.drawString(" "+b,10,20);//打印鼠标的坚坐标
 }
}
//<applet code="CountClick.class" width="200" height="100"></applet>      

      
   2、键盘事件:如果我们希望使用键盘获得输入信息,就必须处理键盘事件。我们可以用在Conponent的keyDown来实现。如下例子:
import java.applet.Applet;import java.awt.*;
{   char Presskey;
     public boolean keyDown(Event evt, int key)
     {   Presskey=(char)key;//记录你按下的键
     repaint(); return true;
}
      public void paint(Graphics g)
     {    g.drawString(Presskey,10,10); }//打印你按下的键值
}
   3、铵钮等事件:这方面的内容比较多,通过一个例子做一个简单的介绍。

//*******注意Repaint()方法的使用******//
//**通过本程序对JAVA的数据隐藏有了一近一步的了解***///

import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
public class Awtactiontest2 extends Applet implements ItemListener ,ActionListener
//实现ItemListener ,ActionListener接口
{
 int num = 5;
  Choice ch=new Choice ();
 Button one=new Button("one");
 Button two=new Button("two"); 
 Button three=new Button("three");
 Image  aa[];
 Image  a;
 public void init()
 {
        aa = new Image[num];
        for(int i = 0; i < num; i++)//把图片的路径加到数组中存储
        {
            aa[i] = getImage(getdocument.ase(),"A"+(i+1)+".JPG");
        }
        num=4;//给一个初值
 this.setBackground(Color.white);
 ch. addItem("A1.JPG" );
 ch. addItem ("A2.JPG" );
 ch. addItem ("A3.JPG" );
 ch. addItem ("A4.JPG" );
 add (ch);
 a = getImage(getdocument.ase(),"A1.JPG");//对a一个初值;
 add (one);
 add (two);
 add (three);
 ch.addItemListener(this);//注意把ItemListener接口implements进来
 one.addActionListener(this);//注意把ActionListener接口implements进来
 two.addActionListener(this);
 three.addActionListener(this);
 }
public void itemStateChanged (ItemEvent e)
  {
   
    a = getImage(getdocument.ase(),ch.getSelectedItem ());
    repaint();
  }
 public void actionPerformed(ActionEvent e)
 {
 if(e.getSource()==one)
 {
        num=1;
        repaint();//对程序刷新
 }
 if(e.getSource()==two)
 {
        num=2;
        repaint();
 }
 if(e.getSource()==three)
 {
        num=3;
        repaint();
 }
 }
 public void paint(Graphics g)
 {
        //g.drawImage(aa[i],0,0,this);
     
  int w=a.getWidth(this);
  int h=a.getHeight(this);
 // g.drawLine(100,1,200,500);
 try{ 
 g.drawImage(a,20,300,10+w,20+h,this);//要抓异常,如果图片找不到呢
 g.drawImage(aa[num],50,50,200,200,this);
 }
 catch(Exception e)
 {
  System.out.println(e);
 }
  }
 public boolean handleEvent(Event ewt)//关窗体,我原以为这个可以把死循环给关了,其它不然.一样的关不了程序
 {
         if(ewt.id==Event.WINDOW_DESTROY)
          System.exit(0);
          else 
          return super.handleEvent(ewt);
          return true;
 }
}
//<Applet code="Awtactiontest2.class" width=400 height=500></applet>

posted @ 2005-11-12 02:36 活在JAVA岛的日子 阅读(257) | 评论 (0) | 编辑 收藏
 
2-4

第2章 万事万物皆对象


一.所有对象都必须由你建立
1. 存储在哪里
1. 寄存器:我们在程序中无法控制
2. stack:存放基本类型的数据和对象的reference,但对象本身不存放在stack中,而是存放在Heap中
3. Heap:存放用new产生的数据
4. Static storage:存放在对象中用static定义的静态成员
5. Constant storage:存放常量
6. NON-RAM:硬盘等永久存储空间
2. 特例:基本型别
基本类型数据存放在Stack中,存放的是数据。而产生对象时,只把对象的reference存放在stack中,用于指向某个对象,对象本身存放在Heap中。
3. Java中的数组
当你产生某个存储对象的数组时,真正产生的其实是存储reference的数组。引数组建立后,其中的每一个reference都会被自动设为null,表示"不指向任何对象"。
二.建立新的数据型别:class
1. 数据成员和函数
1.1 基本成员的缺省值
1) 当class的某个成员属于基本型别时,即使你没有为它提供初值,Java仍保证它有一个缺省值。
2) 只有当变量身份是"class内的成员时,Java才保证为该变量提供初值。
三.函数(Mehtods),引数(arguments),返回值(return values)
1. 引数列
当引数传递的是对象时,传递的是对象的reference。
四.注解用内嵌式文档
Java提供两种注解风格:/*XXXX*/、//XXXX

第3章 控制程序流程


一.使用Java运算符
1.关系运算符
1.) 当对两个对象运用关系运算符进行比较时,比较的是object reference,如:

Integer n1 = new Integer(3);
Integer n2 = new Integer(3);
System.out.println(n1==n2);


结果为false,因为两个object reference(n1和n2)值是不同的
2) equals()的缺省行为也是拿referenct来比较。不过Java中的class覆写了equals方法(覆写时一般先做instanceof的比较,然后在做期望的值的比较,如Integer期望的比较值就是其数值),如:

Integer n1 = new Integer(3);
Integer n2 = new Integer(3);
System.out.println(n1.quals(n2));//值为true


2. 逻辑运算符
1) 只能将and、or、not施用于boolean值身上。如果逻辑运算符两边的值存在non-boolean值,将会出错,如:

int test1 = 1;
System.out.println((test && 1<2);//编辑出错,test是non-boolean值

3. 位移运算符
如果所操作的位移对象是char、byte、short,位移动作发生之前,其值会先被晋升为int,运算结果会是int。
二.流程控制
1. 迭代(iteration)
1.1 逗号运算符
逗号运算符只能用于for循环的控制表达式中的initialization和step两部分中,如:for(int i=0, j=I+1; I<5; i++, j=I*2)
1.2 break和continue
break表示退出循环;continue表示退出本次循环,回来循环起始位置。
1.3 label
label只有放在迭代语句之前才起作用,在label和迭代语句之间插入任何语句都不会起作用。
2. Switch
switch中的选择器必须是int或char型,而且每个case段都应该break,否则不管是否匹配,将按代码顺序执行每个case段的代码。如:

char c='c';
switch (c){
  case 'a':System.out.println("a");break;//如果不break将继续执行下面的case 'b',case 'c',default等段
  case 'b':System.out.println("b");break;
  default:System.out.println("default");break;
  case 'c':System.out.println("c");break;
}


3. 计算细节
1) 从float或double转为整数值,总是以完全舍弃小数的方式进行。
2)   默认情况带小数的为double型,如:1.23应该是double型,如果你想要float型的话得写为 1.23f 或 1.23F。
4. Math.random()的输出范围是[0, 1)。

第4章 初始化和清理


一.以构造函数(constructor)确保初始化的进行
如果某个class具备构造函数,Java便会在对象生成之际,使用者有能力加以操作之前,自动调用其构造函数,于是便能名确保初始化动作一定被执行。
二.函数重载(Method overloading)
1. 区分重载函数
由于只能从函数名和函数的引数列来区分两个函数,而重载函数具有相同的函数名称,所以每个重载函数都必须具备独一无二的引数列。
2. Default构造函数
1) default构造函数是一种不带任何引数的构造函数。如果你所开发的class不具任何构造函数,编译器会自动为你生成一个default构造函数。
2) 如果你自行定义了任何一个构造函数(不论有无引数),编译器就不会为你生成default构造函数。
3) 如果定义了一个class,如

class Bush{
Bush(int I){}
}


当想用new Bush();来产生class的实例时,会产生错误。因为在定义class时已定义了构造函数,所以编译器就不会为class生成default构造函数。当我们用new Bush()来产生实例时,会尝试调用default构造函数,但在class中没有default构造函数,所以会出错。如:

class Sundae
{
Sundae(int i) {}
}
public class IceCream
{
public static void main(String[] args)
{
//Sundae x = new Sundae();会编译出错,无构造函数Sundae()
Sundae y = new Sundae(1);
}
}


*:在定义一个class时,如果定义了自己的构造函数,最好同时定义一个default构造函数
3. 关键字this
1) this仅用于函数之内,能取得"唤起此一函数"的那个object reference。
2) 在构造函数中,通过this可以调用同一class中别的构造函数,如

public class Flower{
Flower (int petals){}
Flower(String ss){}
Flower(int petals, Sting ss){
//petals++;调用另一个构造函数的语句必须在最起始的位置
this(petals);
//this(ss);会产生错误,因为在一个构造函数中只能调用一个构造函数
}
}


**:1)在构造调用另一个构造函数,调用动作必须置于最起始的位置
2)不能在构造函数以外的任何函数内调用构造函数
3)在一个构造函数内只能调用一个构造函数
4. Static的意义
无法在static函数中调用non-static函数(反向可行)。为什么不能呢,我们看下面的例子。
例4.2.4.1
假设能在static函数中调用non-static函数,那么(a)处就将出错。因为在没有产生Movie class实例之前,在就不存在Movie class内的name实例,而在getName()中却要使用name实例,显然的错误的。

class Movie{
String name = "";
Movie(){}
public Movie(String name) { this.name = name; }
public static String getName() { return name; }
}
public class Test{
public static void main(String[] args){
//下面两名先产生实例后再调用getName()没有问题
//Movie movie1 = new Movie("movie1");
//String name1 = movie1.getName();
//下面一名将出错
//String name2 = Movie.getname(); (a)
}
}


三.清理(cleanup):终结(finalization)与垃圾回收(garbage collection)
1)你的对象可能不会被回收
只有当程序不够内存时,垃圾回收器才会启动去回收不再被使用的对象的内存空间。某个对象所占用的空间可能永远不会被释放掉,因为你的程序可能永远不会逼近内存用完的那一刻,而垃圾回收器完全没有被启动以释放你的对象所占据的内存,那些空间便会在程序终止时才一次归还给操作系统
3) 只有在采用原生函数(native methods)时,才使用finalize()。


四.成员初始化(member initialization)
1) 函数中的变量不会被自动初始化,如

void f(){
int i;
i++;
}


将发生编译错误,因为i没有被初始化。
2) class的数据成员会被自动初始化,具体情况如下(见P220例子):
基本型别:boolean:false、char:null(\u0000)、byte:0、short:0、int:0、
long:0 、float:0、double:0
对象(reference):null


五. 初始化次序:
1) 所有变量一定会在任何一个函数(甚至是构造函数)被调用之前完成初始化(见P233例子)
2) 在产生一个class的对象(包含static成员的class的代码被装载)时,首先自动按代码排列顺序初始化class中的static成员变量或static block,所有这些初始化操作只在第一次生成该对象时进行。
3) 自动初始化class中的其它成员变量或non-static block。
4) 调用构造函数。
例:

class Cup{
Cup(int marker){
System.out.println("Cup(" + marker + ")");
}
void f(int marker){
System.out.println("f(" + marker + ")");
}
}

class Cups{
static Cup c1 = new Cup(11);
static Cup c2;
Cup c3 = new Cup(33);
Cup c4;
{
c3 = new Cup(3);
c4 = new Cup(4);
}
static{
c1 = new Cup(1);
c2 = new Cup(2);
}
Cups(){
System.out.println("Cups()");
}
}

public class ExplicitStatic{
public static void main(String[] args){
System.out.println("Inside main()");
Cups.c1.f(99);
}
static Cups x = new Cups();
static Cups y = new Cups();
}


结果为:
Cup(11)
Cup(1)
Cup(2)
Cup(33)
Cup(3)
Cup(4)
Cups()
Cup(33)
Cup(3)
Cup(4)
Cups()
Inside main()
f(99)
2. Array的初始化
1) 定义数组时不能指定大小。如int[4] iArr = {0, 1, 2, 3};,由于指定了数组的大小,会编译出错。
2) 数组只是存放reference的数组。Array与non-array的结构图如下:
a)对于基本型别数据,存放的是数据。如
int i = 5;

b)对于class变量,存放的是reference,这个reference指向一个存有class实例的内存空间。如

String s = "hello";



变量s存放的是一个reference,这个reference指向一个存有String实例的内存空间。
c)对于基本型别数组,存放的是reference数组,数组中的每一个reference都指向一个class实例的内存空间。如

int[] ia = {10, 11, 12};



数组ia存放的是一个reference数组,数组中的每一个reference都指向一个的int实例的内存空间。
d)对于class数组,存放的是reference数组,数组中的每一个reference都指向一个的class实例的内存空间。如

String[] sa = {"hello1", "hello2", "hello3"}; 



数组sa存放的是一个reference数组,数组中的每一个reference都指向一个的String实例的内存空间。
3) 任何数组都要进行初始化,使用没有进行初始化的数组会产生运行时错误,如:

int[] iArr;
System.out.pritnln(iArr[0]);//产生错误,因为iArr还未初始化


数组初始化可在任何地方,可用以下方法来对数组进行初始化:
a) int[] iArr = {1,1,1,1};//数组的长度为{}元素的个数
b) int i = 10;

int[] iArr = new int[i];//数组的长度可为变量(这在C/C++中不行)
System.out.println(iArr[0]);//iArr[0]是一个int,自动初始化值为0
Integer[] iArr2 = new Integer[i];
System.out.println(iArr2[0]);//iArr[0]是一个reference,自动初始为null



I) 对于基本型别数组,new产生的是用于存放数据的数组;否则,产生的只是存放reference的数组。
II) new可用来初始化基本型别的数组,但不能产生non-array的  基本型别数据。
c) int[] iArr = new int[]{1,1,1,1};

Integer[] iArr2 = new Integer[]{new Integer(1), new Integer(2)};


3. 多维数组(Multidimensional)arrays
多维数组每一维的大小可以不一样,如:

Integer[][][] a5;
a5 = new Integer[3];
for(int i=0; i<a5.length; i++)
a5[i] = new Integer[i+1];
for(int j=0; j<a5[i].length
a5[i][j] = new Integer[i+j+1];
posted @ 2005-11-12 02:33 活在JAVA岛的日子 阅读(134) | 评论 (0) | 编辑 收藏
 
转贴别人的读书笔记 Think In Java读书笔记5-7

Think In Java读书笔记-1(第5——7章)- -

                                      

第5章 隐藏实现细节


一.Java访问权限饰词(access specifiers)
Java有public、protect、friendly、private四种访问权限,并且这四访问权限的访问范围越来越小。
1. friendly
1) 果一个class内的数据成员或方法没有任何权限饰词,那么它的缺省访问权限就是friendly。同一个package内的其它所有classes都可以访问friendly成员,但对package以外的classes则形同private。
2)  对于同一个文件夹下的、没有用package的classes,Java会自动将这些classes初见为隶属于该目录的default package,可以相互调用class中的friendly成员。如以下两个class分别在同一个文件夹的两个文件中,虽然没有引入package,但隶属于相同的default package。
class Sundae{
//以下两个方法缺省为friendly
Sundae(){}
Void f() {System.out.println("Sundae.f()");
}
public class IceCream{
public static void main(String[] args){
Sundae x = new Sundae();
x.f();
}
}

2. public:可以被任何class调用
3. private:private成员只能在成员所属的class内被调用,如:
class Sundae{
private Sundae(){}//只能在Sundae class中被调用
Sundae(int i) {}
static Sundae makASundae() {
return new Sundae();
}
}
public class IceCream{
public static void main(String[] args){
// Sundae class中构造函数Sundae()是private,
// 所以不能用它进行初始化
//Sundae x = new Sundae();
Sundae y = new Sundae(1);//Sundae(int)是friendly,可以在此调用
Sundae z = Sundae.makASundae();
}
}

4. protected:具有friendly访问权限的同时,又能被subclass(当然包括子孙类,即子类的子类)所访问。即,既能被同一package中的classes访问,又能被protected成员所在class的subclass访问。

二.Class的访问权限
1.Class同样具有public、protect、friendly、private四种访问访问权限:
1)public:在任何地方都可被使用
2)protect、private:除了它自己,没有任何class可以使用,所以class不能是
protected或private(inner class除外)
3) friendly:同一个package中的classes能用
2. 如何调用构造函数被声明为private的class
1) 用static函数
2) 用Singteton模式
class Soup{
private Soup(){}
//(1)静态函数方法
public static Soup makeSout(){
return new Soup();
}
//(2)The "Singleton" pattern:
private static Soup ps1 = new Soup();
public static Soup access(){
return ps1;
}
public void f(String msg){
System.out.println("f(" + msg + ")");
}
}
public class Lunch{
public static void main(String[] args){
//Soup priv1 = new Soup();编译错误
Soup priv2 = Soup.makeSout();
Soup priv3 = Soup.access();
priv2.f("priv2");
priv3.f("priv3");
}


第6章 重复运用classes


一.继承(inheritance)
1. 在derived class中overriding某个函数时,只能覆写base class中的接口,即base class中的public或protected或friendly函数。如果试图overriding一个private函数,虽然编译通过,但实际上你只是在derived class中添加了一个函数。如
class Cleanser{    
private void prt(){//(b)
System.out.println("Cleanser.prt()");
}
}
public class ExplicitStatic extends Cleanser{
public void prt(){
System.out.println("ExplicitStatic.prt()");
}
public static void main(String[] args){
Cleanser x = new ExplicitStatic();
x.prt();//(a)
}
}

因为Cleanser中的prt()是private,所以不能在其derived class中被覆写。ExplicitStatic中的prt()只是ExplicitStatic中的一个函数,所以当试图在(a)处通过多态来调用prt()时,会发生错误。如果把(b)处的private去掉,则结果为
ExplicitStatic.prt()
2. Super的使用
1)通过关键字super可以调用当前class的superclass(父类)。
例6.1.1.1
class Base{
Base(){System.out.println("Base()");}
public void scrub() { System.out.println(" Base.scrub()"); }
}
class Cleanser extends Base{
private String s = new String("Cleanser");
public void append(String a) { s+=a; }
public void dilute() { append(" dilute()"); }
public void apply() { append(" apply()"); }
public void scrub() { append(" scrub()"); }
public void print() { System.out.println(s); }
Cleanser(){
System.out.println("Cleanser(): " + s);
}
public static void testStatic(){
System.out.println("testStatic()");
}
public static void main(String[] args){
Cleanser x = new Cleanser();
x.dilute(); x.apply(); x.scrub(); x.print();
}
}
public class ExplicitStatic extends Cleanser{
ExplicitStatic(){
System.out.println("ExplicitStatic()");
}
public void scrub(){
append(" Detergen.scrub()");
super.testStatic();
super.scrub();//调用的是Cleanser.scrub()
}
public void foam() { append(" foam()"); }
public static void main(String[] args){
ExplicitStatic x = new ExplicitStatic();
x.dilute(); x.apply(); x.scrub(); x.foam();
x.print(); System.out.println("Test base class:");
Cleanser.main(args);
testStatic();
}
}

运行结果:
Base()
Cleanser(): Cleanser
ExplicitStatic()
testStatic()
Cleanser dilute() apply() Detergen.scrub() scrub() foam()
Test base class:
Base()
Cleanser(): Cleanser
Cleanser dilute() apply() scrub()
testStatic()
2)通过super来调用superclass中的成员时,调用的是最近成员。
例6.1.1.2
class Base{
protected String baseS = "Base";//(a)
//private String baseS = "Base";
Base(){System.out.println("Base()");}
}
class Cleanser extends Base{
protected String baseS = "Cleanser";//(b)
public String s = new String("Cleanser");
Cleanser(){
System.out.println("Cleanser(): " + s);
}
Cleanser(String a){
System.out.println("Cleanser(" + a + "): s = " + s );
}
}
public class ExplicitStatic extends Cleanser{
String s2 = s;
String baseS = super.baseS; //(c)
ExplicitStatic(){
super("ExplicitStatic");
System.out.println("ExplicitStatic():s2 = " + s2 + ", baseS = "

+ baseS + "super.baseS = " + super.baseS);
baseS = "ExplicitStatic";
System.out.println("baseS = " + baseS + " , super.baseS = " + super.baseS);
}
public static void main(String[] args){
ExplicitStatic x = new ExplicitStatic();
}
}


结果1:
Base()
Cleanser(ExplicitStatic): s = Cleanser
ExplicitStatic():s2 = Cleanser, baseS = Cleanser,super.baseS = Cleanser
baseS = ExplicitStatic , super.baseS = Cleanser
在上面例子中,在三个class中都存在String bases实例。在ExplicitStatic中如果直接调用baseS,则实际调用的是当前类ExplicitStatic中的baseS(即(c)处的成员);如果通过super.bases来调用baseS,则调用的是离当前类ExplicitStatic最近的baseS成员,即Cleanser class中的baseS实例(即(b)处),产生的结果如结果1所示。如果把(b)处语句注释掉,则将调用Base class中的baseS,结果如结果2所示。
结果2:
Base()
Cleanser(ExplicitStatic): s = Cleanser
ExplicitStatic():s2 = Cleanser, baseS = Base,super.baseS = Base
baseS = ExplicitStatic , super.baseS = Base
3. Base class的初始化
2.1 当你产生derived class对象时,其中会包含base class子对象(subobject)。这个子对象就和你另外产生的base class对象一模一样。
2.2 通过super()可调用base class的构造函数,但必须放在构造函数的第一行,并且只能在构造函数中运用。
2.3 初始化顺序为:
1) 加载代码(.class文件)
2) 初始化class的静态成员,初始化顺序了"从里到外",即从base class开始。
3) 在derived class的构造函数中调用base class的构造函数。
如果在derived class的构造函数中没有通过super()显式调用调用base class的构造函数,编译器会调用bass class的default构造函数并自动生成相应的调用语句,从而产生一个base class实例。如果在derived class的构造函数中通过super()显示调用了父类的构造函数,则调用所指定的构造函数。调用构造函数的调用顺序是"从里到外"。
4) 调用derived class的构造函数。
**:当base class没有default构造函数时,必须在derived class的构造函数中通过super显示调用base class的构造函数。
例:下面代码的初始化过程为:
1) 装载ExplicitStatic的代码(装载ExplicitStatic.class文件)。
2) 发现ExplicitStatic有关键字extends,装载ExplicitStatic的base class的代码(装载Cleanser.class文件)。
3) 发现Cleanser有关键字extends,装载Cleanser的base class的代码(装载Base.class文件)。
4) 初始化Base class中的静态成员。
5) 初始化Cleanser class中的静态成员。
6) 初始化ExplicitStatic class中的静态成员。
如果把(c)处的代码注释掉,那么初始化工作到此就结束了。
7) 为ExplicitStatic对象分配存储空间,并把存储空间初始化为0。
8) 在ExplicitStatic class的构造中调用super("ExplicitStatic")(在ExplicitStatic class的构造函数中显式调用父类的构造函数),试图产生一个Cleanser class实例。
9) 为Cleanser对象分配存储空间,并把存储空间初始化为0。
10) 由于Cleanser class又是继承自Base class,会在Cleanser class的构造函数中通过super()(由于没有显式调用父类的构造函数,所以自动调用父类的default构造函数)调用父类的构造函数,试图产生一个Cleanser class实例。
11) 产生一个Base class实例。先初始化成员变量,再调用构造函数。
12) 回到Cleanser class,产生一个实例。首先初始化Cleanser class中的成员数据,再执行构造函数Cleanser(String a)中的其余部分。
13) 回到ExplicitStatic class,产生一个实例。首先初始化ExplicitStatic class中的成员数据,再执行构造函数ExplicitStatic ()中的其余部分(System.out.println("ExplicitStatic()"))。
class Base{
static int s1 = prt("s1 initialized.", 11);
int i1 = prt("i1 initialized.", 12);
Base(){
System.out.println("Base()");
System.out.println("s1 = " + s1 + " ,i1 = " + i1);
draw();//(d)
}
void draw(){
System.out.println("base.draw:s1 = " + s1 + " ,i1 = " + i1);
}
static int prt(String s, int num) {
System.out.println(s);
return num;
}
}
class Cleanser extends Base{
static int s2 = prt("s2 initialized.", 21);
int i2 = prt("i2 initialized.", 22);
Cleanser(){
System.out.println("Cleanser()");
System.out.println("s2 = " + s2 + " ,i2 = " + i2);
}
Cleanser(String a){
//super();(b)
System.out.println("Cleanser(" + a + ")");
System.out.println("s2 = " + s2 + " ,i2 = " + i2);
}

void draw(){
System.out.println("Cleanser.draw:s2 = " + s2 + " ,i2 = " + i2);
}
}
public class ExplicitStatic extends Cleanser{
static int s3 = prt("s3 initialized.", 31);
int i3 = prt("i3 initialized", 31);
ExplicitStatic(){
super("ExplicitStatic");//(a)
System.out.println("ExplicitStatic()");
System.out.println("s3 = " + s3 + " ,i3 = " + i3);
}
public static void main(String[] args){
ExplicitStatic x = new ExplicitStatic();//(c)
}
}

结果:
s1 initialized.
s2 initialized.
s3 initialized.
//如果把(c)处的代码注释掉,输出结果到此为止,不会输出下面结果
i1 initialized.
Base()
s1 = 11 ,i1 = 12
Cleanser.draw:s2 = 21 ,i2 = 0//(d)处结果
i2 initialized.
Cleanser(ExplicitStatic)//(a)处结果
s2 = 21 ,i2 = 22
i3 initialized
ExplicitStatic()
s3 = 31 ,i3 = 31
由于在Base()中调用draw()时,Cleanser中的i2还未进行初始化,而在为Cleanser对象分配存储空间时,把存储空间初始化为0,所以此时i2为0。
2.4 代码及结果中的(a)说明了是先产生当前class的base class的实例,否则在derived class中无法调用base class的成员。在调用Cleanser class的构造函数Cleanser(String a)时,在Cleanser(String a)中没有用super显式调用Base class的构造函数,所以系统会自动生成调用Base class的default构造函数的语句,如(b)。
4. 组合与继承之间的快择
. 1)继承表示的是一种"is-a(是一个)"的关系,如货车是汽车中的一种;组合表示的是一种"has-a(有一个)"的关系,如汽车有四个轮子。
2)是否需要将新的class向上转型为base class。
5. 在继承中的访问权限
protect变量能被子孙类所调用。如Base class中的baseS能被Cleanser class和ExplicitStatic class调用。
class Base{
protected String baseS = "Base";
//private String baseS = "Base";
Base(){System.out.println("Base()");}
}
class Cleanser extends Base{
protected String baseS = "Cleanser";
public String s = new String("Cleanser");
Cleanser(){
System.out.println("Cleanser(): " + s);
}
Cleanser(String a){
System.out.println("Cleanser(" + a + "): s = " + s );
}
}
public class ExplicitStatic extends Cleanser{
String s2 = s;
String baseS = super.baseS;
ExplicitStatic(){
super("ExplicitStatic");
System.out.println("ExplicitStatic():s2 = " + s2 + ", baseS = "
+ baseS + "super.baseS = " + super.baseS);
baseS = "ExplicitStatic";
System.out.println("baseS = " + baseS + " , super.baseS = " + super.baseS);
}
public static void main(String[] args){
ExplicitStatic x = new ExplicitStatic();
}
}

结果:
Base()
Cleanser(ExplicitStatic): s = Cleanser
ExplicitStatic():s2 = Cleanser, baseS = Cleanser, super.baseS = Cleanser
baseS = ExplicitStatic , super.baseS = Cleanser
二.关键字final
1.Final data
1.1 final data
1)当基本型别被定义为final,表示它的数据值不能被改变。如
final int i = 9;
i++;//编译错误,不能改变I的值
2) 当object reference被定义为final时,不能改变的只是reference而不是对象本身。如
class Value{

int i = 1;
}
public class ExplicitStatic extends Cleanser{
public static void main(String[] args){
final Value v = new Value();//v.i = 1
v.i++;//v.i = 2
//v = new Value();
}
}


由于v为final,所以不能通过new Value()使v重新指向一个对象;但是v所指向的对象的值是可以改变的(v.i++)。
1.2 blank finals
我们可以将数据成员声明为final但不给予初值,这就是blank finals。但blank finals必须且只能在构造函数中进行初始化。
public class ExplicitStatic {
final int ib;
final int i = 1;
ExplicitStatic()
{
ib = 2;//(a)
//i = 3; (b)
System.out.println("i = " + i + ", ib = " + ib);
}
public static void main(String[] args){
ExplicitStatic ex = new ExplicitStatic();
}
}

ib为blank finals,所以可以在构造函数中进行初始化。如果把(a)处的代码注释掉,则ib没有初值,编译出错。而i在定义处已进行了初始化,则不能改变i的值,(b)处的代码编译错误。
**:非blank finals成员即使在构造函数中也不能更改其值
2.Final methods
1)被声明为final的函数不能被覆写
2)class中所有private函数自然而然会是final。
3. Final classes
1)当一个class被声明为final时,表示它不能被继承,但class的数据成员不是final,可以被改变。如
class SmallBrain{}

final class Dinosaur{
int i = 7;
int j = i;
SmallBrain x = new SmallBrain();
void f(){};
}

//不能继承final函数
//class Further extends Dinosaur{}

public class ExplicitStatic{
public static void main(String[] args){
Dinosaur n = new Dinosaur();
n.f();
n.i = 40;//final class中的non-final数据成员可以被改变
n.j++;
}
}

2)final class中的所有函数也都自然是final,因为没有人能够加以覆写。

第7章 多态


一.再探向上转型(upcasting)
将某个object reference视为一个"reference to base type"的动作,称为向上转型。
1. Upcasting后调用某个函数时,如果derived class中覆写了该函数,则会调用derived class中的函数;否则,会调用base class中的函数。如
class First{
public void prt(){
System.out.println("First");
}
}
class Second extends First{
//(a)
public void prt(){
System.out.println("Second");
}
}
public class ExplicitStatic{
public static void main(String[] args){
First n = new Second();
n.prt();;
}
}

结果为Second。如果当Second class中的prt()函数注释掉,将输出First。
2. 向上转型后只能调用base class中被derived class覆写的函数。
/*
abstract class First{
int i = 122;
public void prt(){
System.out.println("First.i = " + i);
}
public abstract void prt(First f);
}

class Second extends First{
public void prt(){
System.out.println("Second.i = " + i);
}

public void prt(First i)
{

}

public void prt(int i)
{

}
}
public class ExplicitStatic{
public static void main(String[] args){
First n = new Second();
n.prt(2);;
}
}
*/

class First{
public void prt(){
System.out.println("First");
}
}
class Second extends First{
//(a)
public void prt(){
System.out.println("Second");
}
public void prt(int i){//(a)
System.out.println("Second.i = " + i);
}
}
public class ExplicitStatic{
public static void main(String[] args){
First n = new Second();
n.prt(3);
}
}

(a)处的函数只是Second class中的函数,所以不能通过n.prt(3)进行调用。
二.Abstract class和Abstract methods
1. 如果一个class中存在abstract class,则class也必须被声明为abstract class。
2. abstract class不能被实例化。
3. 如果base class是一个abstract class,那么derived class必须实现base class中所有的abstract methods;否则,derived class也必须被声明为abstract class。
三.其它要点
1. 纯粹继承与扩充
纯粹继承:只有base class所建议的函数,才被derived class加以覆写。
扩充:除了覆写base class的函数,还实现了自己的函数
abstract class First{
public abstract void f();
public abstract void g();
}
//纯粹继承
class Second extends First{
public void f(){}
public void g(){}
}
//扩充
class Third extends First{
public void f(){}
public void g(){}
public void u(){}//base class不存在的函数
}

2. 向下转型
1) 向下转型时只能调用base class中被覆写过的函数
2) 只有本来就为derived class对象时才能正确向下转弄。
class First{
public void f(){}
public void g(){}
}
class Second extends First{
public void f(){}
public void g(){}
public void u(){}
public void v(){}
}
public class ExplicitStatic{
public static void main(String[] args){
First[] x = {new First(), new Second()};
x[0].f();
x[1].g();
//!x[1].u();class First中不存在函数u()
//((Second)x[0]).f();(a)
((Second)x[1]).u();
}
}
posted @ 2005-11-12 02:26 活在JAVA岛的日子 阅读(502) | 评论 (0) | 编辑 收藏
 
开始努力了
        学习了JAVA一段时间了。有时也看看人家写的BLOG,觉得自己也应该写点东西!或许有助于提高自己吧!
posted @ 2005-11-11 17:57 活在JAVA岛的日子 阅读(133) | 评论 (0) | 编辑 收藏
 
仅列出标题
共2页: 上一页 1 2