当前位置:  技术问答>java相关

如何在java中將多個結構體放在一個java文件中,就像c里一樣?

    来源: 互联网  发布时间:2015-03-23

    本文导语:  我可以把一個結構體定義在對應的java文件中,但是要把多個結構體放在一個文件中,應該怎麼辦? | 7.6 内部类 在Java 1.1中,可将一个类定义置入另一个类定义中。这就叫作“内部类”。内部类...

我可以把一個結構體定義在對應的java文件中,但是要把多個結構體放在一個文件中,應該怎麼辦?

|
7.6 内部类
在Java 1.1中,可将一个类定义置入另一个类定义中。这就叫作“内部类”。内部类对我们非常有用,因为利用它可对那些逻辑上相互联系的类进行分组,并可控制一个类在另一个类里的“可见性”。然而,我们必须认识到内部类与以前讲述的“合成”方法存在着根本的区别。
通常,对内部类的需要并不是特别明显的,至少不会立即感觉到自己需要使用内部类。在本章的末尾,介绍完内部类的所有语法之后,大家会发现一个特别的例子。通过它应该可以清晰地认识到内部类的好处。
创建内部类的过程是平淡无奇的:将类定义置入一个用于封装它的类内部(若执行这个程序遇到麻烦,请参见第3章的3.1.2小节“赋值”):

//: Parcel1.java
// Creating inner classes
package c07.parcel1;

public class Parcel1 {
  class Contents {
    private int i = 11;
    public int value() { return i; }
  }
  class Destination {
    private String label;
    Destination(String whereTo) {
      label = whereTo;
    }
    String readLabel() { return label; }
  }
  // Using inner classes looks just like
  // using any other class, within Parcel1:
  public void ship(String dest) {
    Contents c = new Contents();
    Destination d = new Destination(dest);
  }  
  public static void main(String[] args) {
    Parcel1 p = new Parcel1();
    p.ship("Tanzania");
  }
} ///:~

若在ship()内部使用,内部类的使用看起来和其他任何类都没什么分别。在这里,唯一明显的区别就是它的名字嵌套在Parcel1里面。但大家不久就会知道,这其实并非唯一的区别。
更典型的一种情况是,一个外部类拥有一个特殊的方法,它会返回指向一个内部类的句柄。就象下面这样:

//: Parcel2.java
// Returning a handle to an inner class
package c07.parcel2;

public class Parcel2 {
  class Contents {
    private int i = 11;
    public int value() { return i; }
  }
  class Destination {
    private String label;
    Destination(String whereTo) {
      label = whereTo;
    }
    String readLabel() { return label; }
  }
  public Destination to(String s) {
    return new Destination(s);
  }
  public Contents cont() { 
    return new Contents(); 
  }
  public void ship(String dest) {
    Contents c = cont();
    Destination d = to(dest);
  }  
  public static void main(String[] args) {
    Parcel2 p = new Parcel2();
    p.ship("Tanzania");
    Parcel2 q = new Parcel2();
    // Defining handles to inner classes:
    Parcel2.Contents c = q.cont();
    Parcel2.Destination d = q.to("Borneo");
  }
} ///:~

若想在除外部类非static方法内部之外的任何地方生成内部类的一个对象,必须将那个对象的类型设为“外部类名.内部类名”,就象main()中展示的那样。

7.6.1 内部类和上溯造型
迄今为止,内部类看起来仍然没什么特别的地方。毕竟,用它实现隐藏显得有些大题小做。Java已经有一个非常优秀的隐藏机制——只允许类成为“友好的”(只在一个包内可见),而不是把它创建成一个内部类。
然而,当我们准备上溯造型到一个基础类(特别是到一个接口)的时候,内部类就开始发挥其关键作用(从用于实现的对象生成一个接口句柄具有与上溯造型至一个基础类相同的效果)。这是由于内部类随后可完全进入不可见或不可用状态——对任何人都将如此。所以我们可以非常方便地隐藏实施细节。我们得到的全部回报就是一个基础类或者接口的句柄,而且甚至有可能不知道准确的类型。就象下面这样:

//: Parcel3.java
// Returning a handle to an inner class
package c07.parcel3;

abstract class Contents {
  abstract public int value();
}

interface Destination {
  String readLabel();
}

public class Parcel3 {
  private class PContents extends Contents {
    private int i = 11;
    public int value() { return i; }
  }
  protected class PDestination
      implements Destination {
    private String label;
    private PDestination(String whereTo) {
      label = whereTo;
    }
    public String readLabel() { return label; }
  }
  public Destination dest(String s) {
    return new PDestination(s);
  }
  public Contents cont() { 
    return new PContents(); 
  }
}

class Test {
  public static void main(String[] args) {
    Parcel3 p = new Parcel3();
    Contents c = p.cont();
    Destination d = p.dest("Tanzania");
    // Illegal -- can't access private class:
    //! Parcel3.PContents c = p.new PContents();
  }
} ///:~

现在,Contents和Destination代表可由客户程序员使用的接口(记住接口会将自己的所有成员都变成public属性)。为方便起见,它们置于单独一个文件里,但原始的Contents和Destination在它们自己的文件中是相互public的。
在Parcel3中,一些新东西已经加入:内部类PContents被设为private,所以除了Parcel3之外,其他任何东西都不能访问它。PDestination被设为protected,所以除了Parcel3,Parcel3包内的类(因为protected也为包赋予了访问权;也就是说,protected也是“友好的”),以及Parcel3的继承者之外,其他任何东西都不能访问PDestination。这意味着客户程序员对这些成员的认识与访问将会受到限制。事实上,我们甚至不能下溯造型到一个private内部类(或者一个protected内部类,除非自己本身便是一个继承者),因为我们不能访问名字,就象在classTest里看到的那样。所以,利用private内部类,类设计人员可完全禁止其他人依赖类型编码,并可将具体的实施细节完全隐藏起来。除此以外,从客户程序员的角度来看,一个接口的范围没有意义的,因为他们不能访问不属于公共接口类的任何额外方法。这样一来,Java编译器也有机会生成效率更高的代码。
普通(非内部)类不可设为private或protected——只允许public或者“友好的”。
注意Contents不必成为一个抽象类。在这儿也可以使用一个普通类,但这种设计最典型的起点依然是一个“接口”。

7.6.2 方法和作用域中的内部类
至此,我们已基本理解了内部类的典型用途。对那些涉及内部类的代码,通常表达的都是“单纯”的内部类,非常简单,且极易理解。然而,内部类的设计非常全面,不可避免地会遇到它们的其他大量用法——假若我们在一个方法甚至一个任意的作用域内创建内部类。有两方面的原因促使我们这样做:
(1) 正如前面展示的那样,我们准备实现某种形式的接口,使自己能创建和返回一个句柄。
(2) 要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序方案。同时不愿意把它公开。

在下面这个例子里,将修改前面的代码,以便使用:
(1) 在一个方法内定义的类
(2) 在方法的一个作用域内定义的类
(3) 一个匿名类,用于实现一个接口
(4) 一个匿名类,用于扩展拥有非默认构建器的一个类
(5) 一个匿名类,用于执行字段初始化
(6) 一个匿名类,通过实例初始化进行构建(匿名内部类不可拥有构建器)

所有这些都在innerscopes包内发生。首先,来自前述代码的通用接口会在它们自己的文件里获得定义,使它们能在所有的例子里使用:

//: Destination.java
package c07.innerscopes;

interface Destination {
  String readLabel();
} ///:~

由于我们已认为Contents可能是一个抽象类,所以可采取下面这种更自然的形式,就象一个接口那样:

//: Contents.java
package c07.innerscopes;

interface Contents {
  int value();
} ///:~

尽管是含有具体实施细节的一个普通类,但Wrapping也作为它所有衍生类的一个通用“接口”使用:

//: Wrapping.java
package c07.innerscopes;

public class Wrapping {
  private int i;
  public Wrapping(int x) { i = x; }
  public int value() { return i; }
} ///:~

在上面的代码中,我们注意到Wrapping有一个要求使用自变量的构建器,这就使情况变得更加有趣了。
第一个例子展示了如何在一个方法的作用域(而不是另一个类的作用域)中创建一个完整的类:

//: Parcel4.java
// Nesting a class within a method
package c07.innerscopes;

public class Parcel4 {
  public Destination dest(String s) {
    class PDestination
        implements Destination {
      private String label;
      private PDestination(String whereTo) {
        label = whereTo;
      }
      public String readLabel() { return label; }
    }
    return new PDestination(s);
  }
  public static void main(String[] args) {
    Parcel4 p = new Parcel4();
    Destination d = p.dest("Tanzania");
  }
} ///:~

PDestination类属于dest()的一部分,而不是Parcel4的一部分(同时注意可为相同目录内每个类内部的一个内部类使用类标识符PDestination,这样做不会发生命名的冲突)。因此,PDestination不可从dest()的外部访问。请注意在返回语句中发生的上溯造型——除了指向基础类Destination的一个句柄之外,没有任何东西超出dest()的边界之外。当然,不能由于类PDestination的名字置于dest()内部,就认为在dest()返回之后PDestination不是一个有效的对象。
下面这个例子展示了如何在任意作用域内嵌套一个内部类:

//: Parcel5.java
// Nesting a class within a scope
package c07.innerscopes;

public class Parcel5 {
  private void internalTracking(boolean b) {
    if(b) {
      class TrackingSlip {
        private String id;
        TrackingSlip(String s) {
          id = s;
        }
        String getSlip() { return id; }
      }
      TrackingSlip ts = new TrackingSlip("slip");
      String s = ts.getSlip();
    }
    // Can't use it here! Out of scope:
    //! TrackingSlip ts = new TrackingSlip("x");
  }
  public void track() { internalTracking(true); }
  public static void main(String[] args) {
    Parcel5 p = new Parcel5();
    p.track();
  }
} ///:~

TrackingSlip类嵌套于一个if语句的作用域内。这并不意味着类是有条件创建的——它会随同其他所有东西得到编译。然而,在定义它的那个作用域之外,它是不可使用的。除这些以外,它看起来和一个普通类并没有什么区别。
下面这个例子看起来有些奇怪:

//: Parcel6.java
// A method that returns an anonymous inner class
package c07.innerscopes;

public class Parcel6 {
  public Contents cont() {
    return new Contents() {
      private int i = 11;
      public int value() { return i; }
    }; // Semicolon required in this case
  }
  public static void main(String[] args) {
    Parcel6 p = new Parcel6();
    Contents c = p.cont();
  }
} ///:~

cont()方法同时合并了返回值的创建代码,以及用于表示那个返回值的类。除此以外,这个类是匿名的——它没有名字。而且看起来似乎更让人摸不着头脑的是,我们准备创建一个Contents对象:
return new Contents()
但在这之后,在遇到分号之前,我们又说:“等一等,让我先在一个类定义里再耍一下花招”:

return new Contents() {
private int i = 11;
public int value() { return i; }
};

这种奇怪的语法要表达的意思是:“创建从Contents衍生出来的匿名类的一个对象”。由new表达式返回的句柄会自动上溯造型成一个Contents句柄。匿名内部类的语法其实要表达的是:

class MyContents extends Contents {
private int i = 11;
public int value() { return i; }
}
return new MyContents();

在匿名内部类中,Contents是用一个默认构建器创建的。下面这段代码展示了基础类需要含有自变量的一个构建器时做的事情:

//: Parcel7.java
// An anonymous inner class that calls the 
// base-class constructor
package c07.innerscopes;

public class Parcel7 {
  public Wrapping wrap(int x) {
    // Base constructor call:
    return new Wrapping(x) { 
      public int value() {
        return super.value() * 47;
      }
    }; // Semicolon required
  }
  public static void main(String[] args) {
    Parcel7 p = new Parcel7();
    Wrapping w = p.wrap(10);
  }
} ///:~

也就是说,我们将适当的自变量简单地传递给基础类构建器,在这儿表现为在“new Wrapping(x)”中传递x。匿名类不能拥有一个构建器,这和在调用super()时的常规做法不同。
在前述的两个例子中,分号并不标志着类主体的结束(和C++不同)。相反,它标志着用于包含匿名类的那个表达式的结束。因此,它完全等价于在其他任何地方使用分号。
若想对匿名内部类的一个对象进行某种形式的初始化,此时会出现什么情况呢?由于它是匿名的,没有名字赋给构建器,所以我们不能拥有一个构建器。然而,我们可在定义自己的字段时进行初始化:

//: Parcel8.java
// An anonymous inner class that performs 
// initialization. A briefer version
// of Parcel5.java.
package c07.innerscopes;

public class Parcel8 {
  // Argument must be final to use inside 
  // anonymous inner class:
  public Destination dest(final String dest) {
    return new Destination() {
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
  public static void main(String[] args) {
    Parcel8 p = new Parcel8();
    Destination d = p.dest("Tanzania");
  }
} ///:~

若试图定义一个匿名内部类,并想使用在匿名内部类外部定义的一个对象,则编译器要求外部对象为final属性。这正是我们将dest()的自变量设为final的原因。如果忘记这样做,就会得到一条编译期出错提示。
只要自己只是想分配一个字段,上述方法就肯定可行。但假如需要采取一些类似于构建器的行动,又应怎样操作呢?通过Java 1.1的实例初始化,我们可以有效地为一个匿名内部类创建一个构建器:

//: Parcel9.java
// Using "instance initialization" to perform 
// construction on an anonymous inner class
package c07.innerscopes;

public class Parcel9 {
  public Destination 
  dest(final String dest, final float price) {
    return new Destination() {
      private int cost;
      // Instance initialization for each object:
      {
        cost = Math.round(price);
        if(cost > 100)
          System.out.println("Over budget!");
      }
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
  public static void main(String[] args) {
    Parcel9 p = new Parcel9();
    Destination d = p.dest("Tanzania", 101.395F);
  }
} ///:~

在实例初始化模块中,我们可看到代码不能作为类初始化模块(即if语句)的一部分执行。所以实际上,一个实例初始化模块就是一个匿名内部类的构建器。当然,它的功能是有限的;我们不能对实例初始化模块进行过载处理,所以只能拥有这些构建器的其中一个。


|
一个文件可以包含多个类,但是只能有一个public顶层类
public class A{
 public class B{}
}
class C{}

|
定义为类不就行了?

    
 
 

您可能感兴趣的文章:

  • .jsp和.java文件要放在哪儿?
  • 请问::大家用Java是做application还是applet?我要是学Java,重点放在那儿部分?
  • 请问:初学JAVA,需要把精力放在些什么地方?
  • java -cp 命令放在sh脚本里不能被执行.
  • 请问:jsp中用到的.class和.java后缀的文件应放在哪个目录下??(Tomcat)
  • JAVA类文件放在哪儿?
  • java.io 莱鸟问题:程序运行时用到的文件应该放在哪个目录下?在线等待。。。
  • 把java扩展包放在jrelibext下,老说找不到相应的包
  • 我有一个原来在widows下运行的程序,现在我想把他作成一个corba组件放在服务器上,与java(jsp+servlet)相连,大家有什么建议,或者有什
  • JSP用javabeans的时候java文件应该放在什么位置?
  • 请问java applet程序用appletviewer运行正常,而放在网页中运行就没有显示,错在那里呢?急急急,送20分啊
  • 我们的java项目放在了独立的liunx服务器上,个别页面出现路乱码
  • 诚邀具有JAVA开发经验且英语水平过硬的开发人员一起来翻译J2SDK标准版V1.4.0 API文档和J2EE1.3 API文档,完成后将放在网上共享下载,详情到网站http://china-programer.myrice.com/
  • 連接數據庫,將查詢的結果放在表格裡,怎麼樣實現?(我是java生手)
  • Java读写包括中文的txt文件时不同编码格式问题解决
  • JAVA编译的CLASS文件可以反编译为JAVA文件吗?
  • 保存java.sh文件时,多出一个java.sh~文件
  • 用什么工具可以把JAVA的.CLASS文件反编译成.JAVA文件??
  • 请问把.class文件反编译为.java文件的工具有什么???能恢复到原来的.java文件吗???
  • 一个.java文件中怎样来调用另一个.java文件中的变量及其它东西!
  • 用java读中文linux中的文件是正确的,用java读英文linux版本中的文件是乱码,如何使英文linux读出的文件数据也是中文的?
  • java文件复制代码片断(java实现文件拷贝)
  • java读取csv文件示例分享(java解析csv文件)
  • 我刚学java,想请教一下,我在文本中创建了一个接口,一个类,还有一个扩展类,保存为.java文件时,如何给文件名?
  • 请教:有没有把java编译好的.java和.class文件编译成各个平台下的可执行文件??.exe?着急着急
  • java文件操作之java写文件简单示例
  • java复制文件和java移动文件的示例分享
  • java读取文件内容的三种方法代码片断分享(java文件操作)
  • 编译前的java文件没有,只有class文件
  • 我用java编了一个程序,是多个java文件,属于一个包,需要联编,但我不会
  • 低级问题:.java文件交付用户怎么运行,难道也是DOS下:java xx.java?有没有.exe?
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • java命名空间java.sql类types的类成员方法: java_object定义及介绍
  • 我想学JAVA ,是买THINK IN JAVA 还是JAVA2核心技术:卷1 好???
  • java命名空间java.awt.datatransfer类dataflavor的类成员方法: imageflavor定义及介绍
  • 请问Java高手,Java的优势在那里??,Java主要适合于开发哪类应用程序
  • java命名空间java.lang.management类managementfactory的类成员方法: getcompilationmxbean定义及介绍
  • 如何将java.util.Date转化为java.sql.Date?数据库中Date类型对应于java的哪个Date呢
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getlibrarypath定义及介绍
  • 谁有电子版的《Java编程思想第二版(Thinking in java second)》和《Java2编程详解(special edition java2)》?得到给分
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getstarttime定义及介绍
  • 本人想学java,请问java程序员的待遇如何,和java主要有几个比较强的方向
  • java命名空间java.awt.datatransfer类dataflavor的类成员方法: stringflavor定义及介绍
  • 我对JAVA一窍不通,可惜别人却给我一个Java的project,要我做一个安装程序,请问哪里有JAVA INSTALLER下载,而且我要不要安装java的sdk才能完成此项任务?
  • java命名空间java.security类keystore的类成员方法: getdefaulttype定义及介绍
  • 新年第一天,让我们讨论一下未来一年JAVA的发展趋势! 个人认为,JAVA将主要朝ERP和JAVA手机方面发展!
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getclasspath定义及介绍
  • 我想学Java,但不知道Java的实用的开发工具有那些,Java主要用在哪些方面,EJB到底是什么东西??
  • java命名空间java.awt.datatransfer类dataflavor的类成员方法: javaserializedobjectmimetype定义及介绍
  • redhat7.3下,java程序打印中文直接用java命令执行正常,用crontab执行java命令为乱码
  • java命名空间java.awt.datatransfer类dataflavor的类成员方法: javafilelistflavor定义及介绍
  • 各位学java的朋友,学java的未来是什么,你们学java都用来开发什么项目啊!来者给分!!
  • java命名空间java.lang.management接口runtimemxbean的类成员方法: getvmname定义及介绍
  • 请问java程序中的import为什么有的用java.….*,而有的又用java.….…,有什么区别吗?


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3