Java这个地方创建对象的时候,为什么有个js 大括号 定义 对象

问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
public class Car {
public void drive(){
System.out.println("Driving a car!");
public static void main(String[] args) {
Car car = new Car(){//这个地方创建对象的时候,为什么有个大括号?这就算是内部类?
public void drive() {
System.out.println("Driving another car!");
car.drive();
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
匿名内部类,你可以把它当做一个子类来理解。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
这是个匿名类,继承了Car类,覆盖drive方法
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?Java程序员,你为什么要关注Scala(组图)
  51CTO独家特稿上周我们从Scala创始人MartinOdersky的访谈录中了解了Scala创建的背景,这次让我们来看一看MartinOdersky对于Scala语言的设计目标是怎么说的。在创造“超越Java的语言”的过程中,具体都需要考虑到哪些方面呢?  让步  FrankSommers:您之前提到,想要创造一种存在于Java体系内,集成Java基础架构的语言。为了做到这一点,Scala要做出什么样的让步,使其能够兼容Java平台?  MartinOdersky:很幸运,我们不需要做出太多妥协,或者说,很难判断我们所做出的所有妥协都是对我们不利或是有利的。其中一个我们不得不做的妥协是购买Java的静态重载模型。也许我们应该更积极地尝试一些其他方法,如使用多方法,尽管当时我们尝试过这一点,但并没有充分探讨有关多方法的设计。也许直到今天也还没有充分探讨过,所以我不能完全肯定这种方法是否行得通。这种方法本来有着令人振奋的可能性,但我们并没有采用它,因为我们想保持与Java的兼容性。  另外一件时而会引来人们否定的事是Scala既包含Traits技术又包含类技术。大家认为一个整洁的设计应该是只采用Traits技术。目前已有一些只采用Traits而放弃类概念的整洁设计,但我们并没有这样做。因为我们想从这两方面保留与Java的互用性。我们希望有一种方式可以让Java代码很容易地调用Scala代码,而Traits并不含有映射到Java的特性,因为在Java中根本不存在这种技术。因此,我们选择了Java中所拥有的类的概念,因为我们希望能够向后映射,这样我们就可以很容易地在两个方向保留互用性。  第3个问题,与其说是语言上的问题,不如说是类库的问题。我们很想要抛弃null(空值)这种概念。NULL是很多错误的根源。在Scala中,不允许null作为任何类型的可能值,取而代之的是选项类型(optiontype)。当然,有很多Java类库中的类都返回null,我们必须要解决这个问题。  51CTO编者注:在新语言兼容旧语言的这个方面,《Think in Java》和《Think inC++》的作者BruceEckel也曾经写过一篇文章,就C++和C的关系评论兼容老语言为新语言带来的好处和限制。这篇文章相关的讨论可以参见这里。  共3页: 1 23  内容导航  第 1 页:为兼容Java而让步 第 2 页:争取Java程序员中重要的事情  第 3 页:面向对象的创新   选择你需要的战斗  BillVenners:为了能让Java程序员接受Scala,您都做了哪些努力?例如,像Java使用大括号而不是其它符号来分块程序,这使得C和C++程序员感到使用Java就如同使用C和C++一样。  MartinOdersky:我们并没有为了推销产品而设计什么特殊功能,但是为了避免产生使用障碍,我们做了一些努力。举例来说,我认为大括号起了很好的分割作用,所以我选择使用它。我们本可以坚持使用begin/end或是其它符号,但我不认为这些符号能起到更好的效果。  其中有一个我们做了改动的地方。最初我们曾使用冒号-等号表示变量赋值,就像是Pascal、Modular和Ada那样,使用单个等号表示相等。很多编程理论会认为这是最恰当的方式。赋值并不表示相等,因此,你必须使用不同的符号。但后来我与一些使用Java的人进行交流。我得到的反应是,“哦,这看起来像是一个很有趣的语言。但是,为什么你要写冒号-等号?它是什么意思?”我解释说,意思就像Pascal中使用的那样。他们说,“那我明白了,但我不明白为什么你坚持要使用这个。”然后我意识到,这并不是我们想要坚持的东西。我们并不想说,“我们有了一个更好的语言,因为我们用冒号-等号代替了等号。”这完全是不值一提的小事,人们完全可以适应任何方式。因此,我们决定不再计较这些小事,而是有其他更重要的地方我们想要与众不同。  BillVenners:这次您没有说那句您曾经说过的“选择你需要的战斗”。基本上,您认为,等号并不那么重要,还有其他您更在意的东西。那么那些重要的事情是什么?您有什么方法能够说服人们去改变他们的想法或程序?  MartinOdersky:我们首要关心的一件事是,拥有一个尽可能整洁的集成了函数式和面向对象的程序设计。我们希望拥有一流的功能,还希望拥有其他函数式程序设计的特征,如类型,泛型,模式匹配。我们希望能够以一个更加整洁的方式整合函数式和面向对象。这是我们从一开始就深感关心的事情。  后来,我们发现这实际上是很容易实现的,因为函数式语言有一套固定的特点。这些特点已经被深入研究和充分证明过了,因此,我们所面临的问题只是如何以最佳方式整合这些特点到面向对象程序设计。在做Pizza时,我们已经进行了尝试,在Scala,我认为我们得到了两者之间更顺畅的集成。但后来我们发现,在面向对象方面仍有很多事情有待开发。面向对象程序设计,至少摆在一个静态类型系统上,是一个非常未知领域。目前我们可以看到和使用一些已有的工作,但我们发现几乎所有的语言都做出了很大的妥协。  因此,随着开发Scala,我们开始发现如何能够混合对象,如何能够抽象自我类型,如何能够使用抽象类型成员,以及如何能够让这一切集成到一起。已有一些研究语言以特殊方法关注了以上几个方面,但几乎还没有任何主流语言,能够涵盖以上所有方面。最终结果表明,Scala的主要创新在于面向对象方面,这也是我们真正关心的事情。  共3页: 12 [3]  内容导航  第 1 页:为兼容Java而让步 第 2 页:争取Java程序员中重要的事情  第 3 页:面向对象的创新   面向对象的创新  51CTO推荐阅读:面向对象的思维过程  Bill Venners:您能不能给出一个具体的列表,列出一些您认为是Scala面向对象的创新?  MartinOdersky:首先,我们想要创造一个纯粹的面向对象的语言,其中的每个值都是一个对象,每个操作都是一个方法调用,每个变量都是一些类的成员。因此,我们不想要静态变量,但我们需要一些其他的东西来替代它们,所以我们提出了Singleton对象。但是,即使是Singleton对象仍然是全局结构。因此,我们所面临的挑战是如何尽可能少地使用它们,因为当你使用一个全局结构时,你就不能再改变它了。你不能实例化它。它很难测试。很难对它以任何方式进行修改。  因此,我们所面临的挑战是,如何能够不使用静态或全局思想来建立复杂的组件。尤其是,我们不得不处理组件间的递归依赖。例如我有两个组件A和B。A使用B,同时B使用A。我要如何才能让他们发现对方,并协同工作?我们所做的第一件事是基于mixin(混合式)合成的概念,然而,Java只有单一类和一串含有虚定义而没有代码的接口概念,Scala有类和Traits概念,其中Traits可以包含带有定义和函数域的方法,例如可以带有函数体。然后,我们就拥有了mixin合成,而不只是具有类实现接口,在mixin合成中,我们定义类和所有Traits。有关这项工作是如何工作的细节在此就不详述,我们称之为线性化。  因此,我们定义一个线性化Scala。但随之而来的问题是,怎么样能让一个mixin发现其他mixin?如果他们需要一些来自其他mixin的服务,他们如何指定目标?标准的面向对象方式是通过抽象成员,只要你处理方法,这种方式就会运作良好,但是,我们还必须要处理变量。如何才能让mixin找到对方的域?更重要的是,我们不得不处理类型。因为我们从一开始就有类型嵌套,就像内部类,这是另一个我认为非常重要的事情。如果你选择了mixin合成,一个Trait如何能够找到有关所有其他Trait的内部类,然后访问那些类?我们发现(不仅是发现,更是设计),我们可以通过在自我类型上定义一个抽象来做到这一点。  那么“自我类型上的抽象”究竟是什么意思?比如在一个类中,this类型代表什么意思?你会说,“表示这个类的类型。”大多数人都会这么回答。但实际上却没有任何令人信服的理由。This类型很可能是指其他的东西。只存在一个界定条件,就是当你实际创建一个类的实例的时候,然后这个你所创建的对象就与该类有同样的功能。这就与处理抽象方法时相同。你可以在一个类中定义一个抽象方法,并且不需要实现。这其实并不危险,因为当你创建一个该类的实例时,你将会检查是否所有抽象方法都有具体实现。因此,自我类型的抽象只是这种问题的一个一般化,也可以让你处理域和类型。  自我类型抽象的技术非常值得探索。早期,我们建立一种演算来研究这个问题,称为nu对象演算—νObj,我们于2003年,在面向对象程序设计欧洲会议上公布它(ECOOP2003年)。我们最初发现这一概念只是作为一个技术诀窍,为了使演算过程能够简单。直到后来开始使用它之后我们发现,也许这将是有益于语言的东西。那时候我们还不太了解到底会有什么用处,但我们决定尝试。直到后来,我们才发现,它实现了我们想要的,即让一个Traits声明它所需要的来自其他Traits的东西。这就像是现在的一些工具,如Spring所实现的功能,被称为依赖注入。但通常这种依赖注入只能适用于域,也许对方法也管用,但我们可以让它还能应用于类型。此外,在Scala中,这种注入是静态完成而不是运行时完成,其次,它达到了对于内部类型的类型安全要求。因此,从某种意义上说,它比目前的一些工具如Spring做的更好。  我为什么要学习Scala?有什么好处吗?  51CTO推荐阅读:基于JVM的语言正在开始流行  BillVenners:以后的采访中,我们将会继续再次探讨依赖注入,您刚才谈到关于自我类型的“抽象”。您提到的必须要解决的两件事是函数式和面向对象的融合以及面向对象的创新。如果我的工作室Java编程,在实际工作中,这些东西如何能够帮助我?我能得到什么实质的益处?  MartinOdersky:我们正面临的挑战之一,是我们想融合函数式和面向对象。我们很早就确定了这种概念,即不可变类是非常非常重要的。现在大家都在谈论不可变类,因为人们认为这是解决目前由多核电脑所引起的问题的一个关键方法。大家都说,不管你做什么,你都要尝试让你的代码尽可能多的使用不可变类。在Scala中,我们也从很早就采用这种方法。五,六年前,我们开始深刻考虑不可变的类。但事实证明,大量的面向对象领域一直都在使用可变对象。对于他们来说,可变状态和对象是同一回事:可变状态是一个对象中必不可少的组成部分。我们必须从本质上解释这个问题。  例如,对于一个标准的Java对象,你将创建一个域,基本上是一个可变域。然后你还需考虑构造函数,接收参数并为域赋值。这就是可变的概念,内置到每一个Java类。现在,Java具有final域概念,它不被认为是可变的,因为它只在构造函数中被赋值一次。但你仍然能看到赋值操作。我们希望能有一个更清晰的概念,让你不需要看到构造函数和赋值操作。  使用Scala我们最后所做的事是直接确定类的参数。你只需要在类名后写一个参数列表,这些就成为类的参数。不存在独立可变域和构造函数的概念,这些实际上转变成了一些我们必须要解决的问题。其中之一是,如果你想要有几个构造函数,那要怎么办?我们必须为其确定语法和规则。你可以在你的primary(主要)构造函数之外使用auxiliary(辅助)构造函数。另一个问题是,如果你希望你的参数作为一个域可见化,该怎么办?需要创建一个单独的域,然后再赋值吗?或者是有可能传递参数给一个类,然后立即变成一个域而对其他人可用?因此,我们必须为其创建语法,我相信这种做法也是全新的。最后在面向对象方面还有很多其他新颖的想法。  Bill Venners:对于我这样的一个Java程序员,能得到什么益处?  MartinOdersky:好处就是你可以用更简洁的语法来定义类。使用Scala编写类,能够更容易、更简洁。如果你想要使用不可变类,那将更加容易,因为它非常适合做这件事。你还可以像使用Java那样来使用Scala定义可变类。这甚至比用Java更方便,但Scala真正耀眼的地方还在于它的不可变类。它比Java更自然、更简明。  编者后记:  随着业界开始流传基于JVM的语言正在开始流行这样的声音,处在基于JVM的非Java语言之首的Groovy和Scala被寄以相当大的期望。曾经有一篇英文文章对于几个JVM语言(Groovy,Scala和JRuby)进行了比对,结果是无论从速度,缓存需求还是垃圾处理方面,Scala都是最适合企业级开发的语言。究竟Scala是否真的如此神奇,还让我们拭目以待。  相关阅读  Java以外的选择 Scala编程语言简介  Java之外,选择Scala还是Groovy?  Scala创始人:创造比Java更好的语言
(责任编辑: 和讯网站)
分享文章到“尽管以C++为基础,但 Java 是一种更纯粹的面向对象程序设计语言”。无论C++还是Java 都属于杂合语言。但在 Java 中,设计者觉得这种杂合并不象在 C++里那么重要。杂合语言允许采用多种编程风格;之所以说 C++是一种杂合语言,是因为它支持与 C语言的向后兼容能力。由于C++是C的一个超集,所以包含的许多特性都是后者不具备的,这些特性使 C++在某些地方显得过于复杂。Java 语言首先便假定了我们只希望进行面向对象的程序设计。也就是说,正式用它设计之前,必须先将自己的思想转入一个面向对象的世界(除非早已习惯了这个世界的思维方式)。只有做好这个准备工作,与其他OOP语言相比,才能体会到
Java 的易学易用。在本章,我们将探讨 Java 程序的基本组件,并体会为什么说Java 乃至Java 程序内的一切都是对象。
用引用去操作对象
每种语言都有自己在内存中处理元素的方法。有时候程序员必须时刻注意自己正在处理的什么类型。你曾经直接处理过元素,或你用过一些特殊的语法处理某种间接地引用(如c或c++内的指针)吗?
java在这里做了简化,可以用一致的语法把任何东西被看做对象。但要注意,尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)。你能把它想象成电视机(the object)和电视机的遥控器(reference)。只要你拿着引用,你就有一个电视机的连接,但是当你换频道或调低音量时,你操作的是引用,再由遥控器去修改电视机(object)。如果你想在房间里移动同时控制电视机,你只需带着遥控器(reference)而不是电视机。
当然,遥控器在没电视机的情况下可以单独存在,就是说你拥有一个reference并不意味着有这个对象连接着一个对象。所以如果你想要抓住一个单词或句子,你应该创造一个String 的reference:
package com.thinkinjava.
public class Everythingisobject {
public static void main(String args[])
System.out.println(s.hashCode());//编译不过
System.out.println(s);
但是你仅仅创造了一个reference,并没有创造一个object。如果你想赋给s一个消息,它会报错,因为s并没有连接任何对象(没有连接的电视机),没有初始化引用,所以对变量s的任何操作(除了初始化赋值外)
都将引发异常.安全起见,当你创造它时,你应该把引用初始化了:
String s="asdf";
注意:这是java的一个特殊的特征:通过一个文本就把String 类型的引用初始化了,通常,必须为对象使用一种更通用的初始化类型。
你必须创造所有的类型
当你创造了一个引用,你想要这个引用连接一个新的对象。一般你要用new这个操作符。new的意思是:“把我变成这些对象的一个对象”。所以在上面的例子中,可以说:
String s = new String("asdf");它不仅指出“将我变成一个新字串”,也通过提供一个初始字串,指出了“如何生成这个新字串”(赋予一个初始字符串)。
当然,java除了String还有很多初始类型。重要的你能创造你自己的类型。事实上,在java程序中,创造新类型是基本的活动。
保存在哪里?
搞清楚当程序运行时数据如何放置是很有用的---特别是内存如何分配很重要。有5个不同的地方存储数据:
(1) 寄存器(Registers)。这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部。然而,寄存器的数量十分有限,所以寄存器是根据需要来分配。我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存在的任何踪迹。(2) 堆栈(The stack)。驻留于常规 RAM(随机访问存储器)区域,但可通过它的“堆栈指针”获得处理器的直接支持。堆栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。创建程序时,Java 编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是
由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些Java
数据要保存在堆栈里——特别是对象句柄,但Java 对象并
不放到其中。
(3) 堆(The heap)。一种常规用途的内存池(也在 RAM区域),其中保存了Java 对象。和堆栈不同,“内存堆”或“堆”(Heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需用new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!(4) 静态存储(Constant storage)。这儿的“静态”(Static)是指“位于固定位置”(尽管也在 RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static 关键字指出一个对象的特定元素是静态的。但 Java 对象本身永远都不会置入静态存储空间。(5) 常数存储。常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格地保护,所以可考虑将它们置入只读存储器(ROM)。(6) 非RAM 存储(Non-RAM storage)。若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对象”和“固定对象”。对于流式对象,对象会变成字节流,通常会发给另一台机器。而对于固定对象,对象保存在磁盘中。即使程序中止运行,它们仍可保持自己的状态不变。对于这些类型的数据存储,一个特别有用的技巧就是它们能存在于其他媒体中。一旦需要,甚至能将它们恢复成普通的、基于RAM的对象。
特别的例子:原始类型
有一组类型在你的程序中要经常使用它们,你要特别对待。你能把它们当成原始类型。特殊对待它们的原因是如果用new去创建一个对象---特别是小的简单的变量---并不高效,因为new的对象在堆(heap)中。对于这些原始类型,java回到了c和c++用的方法,就是不用new去创建变量,不用利用引用的自动变量。这个变量直接容纳了值,并且放在堆栈(stack)中,所以它更加高效。
java决定了每种原始类型的大小。就象在大多数语言里那样,这些大小并不随着机器结构的变化而变化。这种大小的不可更改正是 Java 程序具有很强移植能力的原因之一。
封装器类型
Unicode 2的 16次方-1
Byte(注释①)
-2 的15 次方
+2的 15次方-1
Short(注释①)
-2的 31次方
+2 的31 次方-1
-2 的63 次方
+2的 63次方-1
Void(注释①)
数值类型都是有符号的类型,所以不要去找没有符号的类型。
boolean没有显式的定义;它仅仅能定义true或false。
原始类型的封装器类允许你在堆里定义一个非原始对象去代表原始类型
char c = 'x';
Character C = new Character('c');
也可以直接使用:
Character C = new Character('x');
java se5 自动装箱将自动从一个原始类型转为包装类型
Character ch='x';
然后回去:
封装原始类型的原因将在以后的章节里解释。
高精度数字
java包括两种实现了高精度的数字类型:BigInteger和BigDecimal.尽管它们可以化为封装器类型,但是它们都没有基本类型。
这两个类都有方法对应着基本类型的操作。就是说你在int和float上做的任何事情,在BigInteger和BigDecimal上也能做,就是说你必须调用它们的方法来代替操作符。同时因为涉及到别的更多的东西,性能会降低,操作会更慢。你为了精确度降低了速度。如下:
BigInteger bigInttmp=new BigInteger("222222");
BigInteger bigInttmp1=new BigInteger("333333");
System.out.println(bigInttmp.add(bigInttmp1));
print result:555555
BigInteger支持任意精度的整形。这意味着你能表示任意大小的整形并在操作中不担心丢失任意信息。
BigDecimal支持任意精度的定点数字。例如,可用它进行精确的币值计算。
至于调用这两个类时可选用的构建器和方法,请自行参考联机帮助文档。
Java 的数组
几乎所有的程序语言都支持数组。在C和 C++里使用数组是非常危险的,因为那些数组只是内存块。若程序访问自己内存块以外的数组,或者在初始化之前使用内存(属于常规编程错误),会产生不可预测的后果(注释②)。
②:在C++里,应尽量不要使用数组,换用标准模板库(Standard TemplateLibrary)里更安全的容器。
java一个主要的设计目标就是安全,所以许多困扰c和c++程序员的问题不会在java里存在。一个java数组可以确保初始化并且不会访问到数组范围之外。数组的范围检查会占据每个数组少量的内存开销以及在运行时验证索引,但由此换回的是更高的安全性,以及更高的工作效率。为此付出少许代价是值得的。
当你创建一个数组对象时,相当于是在创建的很多数组引用,而且那些引用的每一个引用都自动初始化为一个特殊值,并带有自己的关键字:null.当java看到null时,它认出这个引用没有志向一个对象。你必须在使用每个引用前,把一个对象赋给每一个引用。并且如果你试图使用一个指向null的引用,就会在运行时报告问题。所以典型的数组问题能在java中阻止。
你也能创建基本类型的数组。同样,编译器确保对它初始化因为它将那个数组的内存化为零。
数组问题将在以后的章节里详细讨论。
绝对不要清除对象:
在许多编程语言中,变量的“生命周期”(Lifetime)一直是程序员需要着重考虑的问题。变量应持续多长时间?如果你去清除它,你应该什么时候进行?对生命周期的迷惑导致了很多的bug,并且这部分展现java如何通过为你做所有的清理工作来简化这个问题的。
大多数程序设计语言都有“作用域”的概念。对于作用域中定义的名称,作用域决定着名字的“可见性”和“生命周期”。在c和c++和java中,作用域被大括号的位置决定的。如下:
int x = 12;
/* only x available */
int q = 96;
/* both x & q available */
/* only x available */
/* q “out of scope” */
作为在作用域里定义的一个变量,它只有在那个作用域结束之前才可使用。在上面的例子中,缩进排版使Java 代码更易辨读。由于 Java 是一种形式自由的语言,所以额外的空格、制表位以及回车都不会对结果程序造成影响。注意尽管在 C和 C++里是合法的,但在 Java 里不能象下面这样书写代码:
int x = 12;
int x = 96; /* illegal */
编译器会认为变量x 已被定义。所以C 和C++能将一个变量“隐藏”在一个更大的作用域里。但这种做法在Java 里是不允许的,因为Java 的设计者认为这样做使程序产生了混淆。
对象的作用域:
java对象的生命周期跟基本类型的生命周期是不一样的。当你用new创建一个java对象的时候,java对象会徘徊在作用域范围之外。比如:
String s = new String("a string");
} /* 作用域的终点 */
引用s在作用域之外消失了。但是,这个被引用s指向的String 对象仍然在内存里。在这个代码中,没有办法在作用域之外访问对象,因为指向对象的引用已经超出了作用域之外。在后面的章节中你会看到对象的引用如何在程序中传递和复制。
这样的结果是因为只要我们需要由new创建的对象就一直存在,C++程序中的大量问题在java中消失了。在c++中你不能肯定对象在你需要的时候还存在,你也必须要在你用过对象后去清除对象。
这样就带来了有趣的问题。如果java不清除对象,怎样才能防止它们大量充斥内存,并最终造成程序的“凝固”呢?在C++中这个问题很严重。java处理了这个问题。java有一个垃圾收集器,它会检查所有被new创建的对象并且搞清楚那些对象没有被引用。然后它会释放这些对象的内存,所以内存又能被新的对象利用了。这意味着你不用担心内存的回收问题。你能简单的创建对象,并且当你不用他们的时候,它们将自己消失。这就消灭了一类编程问题:所谓的“内存泄露”,程序员经常忘记去释放内存
创建新的数据类型:类
如果任何东西都能看成一个对象,那么什么决定着一种特定对象类型的外观和行为呢?或者说,什么建立了对象的类型?你可能希望有个关键字“type”,并且这是合理的。历史上,不管怎么样,大多数面向对象语言使用class去定义“我将告诉你一个对象的新类型看起来是什么”。class 关键字太常用了,以至于本书许多地方并没有用粗体字或双引号加以强调。在这个关键字的后面,应该跟随新数据类型的名称。例如:
class ATypeName {/*类主体置于这里}
这样就引入了一种新类型,接下来便可用new 创建这种类型的一个新对象:
ATypeName a = new ATypeName();
在ATypeName 里,类主体只由一条注释构成(星号和斜杠以及其中的内容,本章后面还会详细讲述),所以并不能对它做太多的事情。事实上,除非为其定义了某些方法,否则根本不能指示它做任何事情。
字段和方法
当你定义一个class(并且你在java中做的所有的事是定义类,制造这些类的对象,并且把信息传递给对象),你能把两种类型的元素放在class里:fields(有时叫数据成员),和methods(有时叫成员函数)。一个field可以是一个你能用引用调用的任何类型的对象,或基本类型。如果是一个对象的引用,你必须初始化这个引用头连接一个对象(使用new去做)。但若是一种主类型,则可在类定义位置直接初始化(正如后面会看到的那样,句柄亦可在定义位置初始化)。
每个对象都为它的field保有存储空间;一般的field不会在对象之间共享。这有一个带有field的class的例子:
class DataOnly {
}除了保持数据这个class没有做任何事情。但你能创建这个类的一个对象:
DataOnly d = new DataOnly();你能给fields赋值,当时你必须首先知道如何引用一个对象的一个成员。
为达到引用对象成员的目的,首先要写上对象句柄的名字,再跟随一个点号(句点),再跟随对象内部成员的名字。即“对象引用.成员”。例如:
d.f = 1.1f;
d.b =你可能会去修改你的对象包含的其他对象的field。你可以再写点号去访问和修改。如:
myPlane.leftTank.capacity = 100;这个DataOnly类除了保持数据不能做任何事,因为它没有方法。为了去理解是怎么工作的,你必须首先理解参数和返回值。
当field是基本类型时的默认值
当一个基本类型是一个类的成员时,即使你不初始化它他也能保证有一个默认值的:
基本类型 默认值
Boolean false
'\u0000'(null)
byte (byte)0
float 0.0f
double 0.0d
当变量当做类的成员使用的时候,java能确保变量的默认值。这就确保了当基本类型作为成员变量时能够被初始化(C++不具备这一功能),可有效遏止多种相关的编程错误。
当这种保证不能用于局部变量--局部变量并不是类的field。因此,如果你在一个方法定义中你有:
那么x 会得到一些随机值(这与C 和C++是一样的),不会自动初始化成零。我们责任是在正式使用x 前分配一个适当的值。如果忘记,就会得到一条编译期错误,告诉我们变量可能尚未初始化。这种处理正是Java优于C++的表现之一。许多 C++编译器会对变量未初始化发出警告,但在 Java 里却是错误。如下:
成员变量不用人工初始化,java自动分配默认值:
&pre name="code" class="java"&public class Everythingisobject {
int fieldO
public static void main(String args[])
Everythingisobject objDefautVal=new Everythingisobject();
objDefautVal.DefaultValue();
void DefaultValue()
System.out.println(fieldObject);
//System.out.println(field);
局部变量不给初始化默认值会报告编译期错误:
public class Everythingisobject {
int fieldO
public static void main(String args[])
Everythingisobject objDefautVal=new Everythingisobject();
objDefautVal.DefaultValue();
void DefaultValue()
System.out.println(field);
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The local variable field may not have been initialized但是,对于你写的程序来说这种初始化的值也许不是对的,或是非法的。最好是对你的类成员变量有个显式的初始化。
方法、自变量和返回值:
在许多语言中(像c和c++),function被用于描述子程序。在java中更为通用的是method作为“做某事的途径”。尽管它们表达的实际是同一个意思,但从现在开始,本书将一直使用“方法”,而不是“函数”。
Java 的“方法”决定了一个对象能够接收的消息。通过本节的学习,大家会知道方法的定义有多么简单!方法的基本组成部分包括名字、自变量、返回类型以及主体。下面便是它最基本的形式:
返回类型 方法名( /* 自变量列表*/ ) {/* 方法主体 */}返回类型是指调用方法之后返回的数值类型。显然,方法名的作用是对具体的方法进行标识和引用。自变量列表列出了想传递给方法的信息类型和名称。Java 的方法只能作为类的一部分创建。只能针对某个对象调用一个方法(注释③),而且那个对象必须能够执行那个方法调用。若试图为一个对象调用错误的方法,就会在编译期得到一条出错消息。为一个对象调用方法时,需要先列出对象的名字,在后面跟上一个句点,再跟上方法名以及它的参数列表。亦即“对象名.方法名(自变量1,自变量2,自变量 3...)。举个例子来说,假设我们有一个方法名叫
f(),它没有自变量,返回的是类型为int的一个值。那么,假设有一个名为 a 的对象,可为其调用方法f(),则代码如下:
int x = a.f();返回值的类型必须兼容 x的类型。象这样调用一个方法的行动通常叫作“向对象发送一条消息”。在上面的例子中,消息是f(),而对象是 a。面向对象的程序设计通常简单地归纳为“向对象发送消息”。
③:正如马上就要学到的那样,“静态”方法可针对类调用,毋需一个对象。
方法参数列表
方法参数列表定义了你向方法传递了什么信息。跟你猜的一样,这些信息--像java中其它的一样--采用对象的形式。所以,你在参数列表中要定义传人对象的类型和每个对象的名称。像java在其它地方处理对象一样,实际上你传递的是引用(对于前面提及的“特殊”数据类型 boolean,char,byte,short,int,long,,float 以及double 来说是一个例外。但在传递对象时,通常都是指传递指向对象的引用。)。但引用的类型必须是正确的。倘若希望自变量是一个“字串”,那么传递的必须是一个字串。
下面让我们考虑将一个字串作为自变量使用的方法。下面列出的是定义代码,必须将它置于一个类定义里,否则无法编译:
int storage(String s) {
return s.length() * 2;
}这个方法告诉在一个类型为String的变量中,你需要多少个byte去处理特定的String的信息(字串里的每个字符都是16位,或者说 2 个字节、以便提供对Unicode 字符的支持)。这个参数是String类型的并且被命名为s。一旦s被传人方法,你就能像其它对象一样对待它了。(可向其发送消息)。这里,方法length()被调用,它是String的方法之一。它返回的是一个字符串的字符个数。
也可以了解return 关键字的运用。它主要做两件事情。首先,它意味着“离开方法,我已完工了”。其次,假设方法生成了一个值,则那个值紧接在return 语句的后面。在这种情况下,返回值是通过计算表达式“s.length()*2”而产生的。
可按自己的愿望返回任意类型,但倘若不想返回任何东西,就可指示方法返回void(空)。下面列出一些例子。
boolean flag() { }
float naturalLogBase() { return 2.718; }
void nothing() { }
void nothing2() {}若返回类型为void,则return 关键字唯一的作用就是退出方法。所以一旦抵达方法末尾,该关键字便不需要了。可在任何地方从一个方法返回。但假设已指定了一种非 void 的返回类型,那么无论从何地返回,编译器都会确保我们返回的是正确的类型。
到此为止,大家或许已得到了这样的一个印象:一个程序只是一系列对象的集合,它们的方法将其他对象作为自己的自变量使用,而且将消息发给那些对象。这种说法大体正确,但通过以后的学习,大家还会知道如何在一个方法里作出决策,做一些更细致的基层工作。至于这一章,只需理解消息传送就足够了。
构建 Java 程序
正式构建自己的第一个 Java 程序前,还有几个问题需要注意。
名字的可见性
在所有编程语言中,一个问题是名称的控制。如果你在程序的一个模块中使用了一个名称,并且另一块程序员使用了另一个名称,你如何区分这两个名称同时阻止这两个名称发生冲突?这个问题在 C语言里特别突出。因为程序未提供很好的名字管理方法。C++的类(即 Java 类的基础)嵌套使用类里的函数,使其不至于同其他类里的嵌套函数名冲突。然而,C++仍然允许使用全局数据以及全局函数,所以仍然难以避免冲突。为解决这个问题,C++用额外的关键字引入了“命名空间”的概念。
java通过一个全新的方法避免了这个问题。为了给一个库生成明确的名字,采用了与Internet域名类似的名字。事实上,Java 的设计者鼓励程序员反转使用自己的Internet 域名,因为它们肯定是独一无二的。由于我的域名是,所以我的实用工具库就可命名为com.bruceeckel.utility.foibles。反转了域名后,可将点号想象成子目录。
在Java 1.0 和 Java 1.1 中,域扩展名 com,edu,org,net 等都约定为大写形式。所以库的样子就变成:COM.bruceeckel.utility.foibles。然而,在 Java 1.2的开发过程中,设计者发现这样做会造成一些问题。所以目前的整个软件包都以小写字母为标准。
Java 的这种特殊机制意味着所有文件都自动存在于自己的命名空间里。而且一个文件里的每个类都自动获得一个独一无二的标识符(当然,一个文件里的类名必须是唯一的)。所以不必学习特殊的语言知识来解决这个问题——语言本身已帮我们照顾到这一点。
使用其他组件
一旦要在自己的程序里使用一个预先定义好的类,编译器就必须知道如何找到它。当然,这个类可能就在发出调用的那个相同的源码文件里。如果是那种情况,只需简单地使用这个类即可——即使它直到文件的后面仍未得到定义。Java 消除了“向前引用”的问题,所以不要关心这些事情。
但假若那个类位于其他文件里呢?您或许认为编译器应该足够“联盟”,可以自行发现它。但实情并非如此。假设我们想使用一个具有特定名称的类,但那个类的定义位于多个文件里。或者更糟,假设我们准备写一个程序,但在创建它的时候,却向自己的库加入了一个新类,它与现有某个类的名字发生了冲突。
为解决这个问题,必须消除所有潜在的、纠缠不清的情况。为达到这个目的,要用import 关键字准确告诉Java 编译器我们希望的类是什么。import的作用是指示编译器导入一个“包”——或者说一个“类库”(在其他语言里,可将“库”想象成一系列函数、数据以及类的集合。但请记住,Java 的所有代码都必须写入一个类中)。
大多数时候,我们直接采用来自标准Java 库的组件(部件)即可,它们是与编译器配套提供的。使用这些组件时,没有必要关心冗长的保留域名;举个例子来说,只需象下面这样写一行代码即可:
import java.util.V它的作用是告诉编译器我们想使用 Java 的Vector 类。然而,util 包含了数量众多的类,我们有时希望使用其中的几个,同时不想全部明确地声明它们。为达到这个目的,可使用“*”通配符。如下所示:
import java.util.*;
需导入一系列类时,采用的通常是这个办法。应尽量避免一个一个地导入类。static 关键字:
一般地,当我们创建一个类时,你会描述这个类的对象的外观和行为,直到你用new关键字你才得到了一个对象,并且使存储空间得以分配而且方法也变得可用。
有两种情况下,这个方式并不满足。一个是如果你想仅仅有个存储空间来保存特别的数据,不管你创建了多少这个类的对象或甚至没有对象被创建。另一个是如果你需要一个方法,并且这个方法不与这个类的任何对象有关系。也就是说你需要一个方法你能够调用即使没有对象被创建。
你能通过static这个关键字去实现这两个效果。当你说某个东西是static,它意味着特定的域值或方法没有与特定的类的实例绑定。所以即使你没有创建一个类的实例你也能调用一个static 方法或访问一个static的域值。而在这之前,对于非 static数据和方法,我们必须创建一个对象,并用那个对象访问数据或方法。这是由于非static数据和方法必须知道它们操作的具体对象。当然,在正式使用前,由于static方法不需要创建任何对象,所以它们不可简单地调用其他的那些成员,同时不引用一个已命名的对象,从而直接访问非
static成员或方法(因为非static成员和方法必须同一个特定的对象关联到一起)。
有些面向对象语言使用“类数据”和类方法两个术语,这意味着数据和方法仅仅跟类这个整体有关系,与类的特定对象没关系。有时候java文章里会出现这些术语。
浏览: 378 次
来自: 北京
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 js 大括号 定义 对象 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信