core jave2:第四章 对象和类

这一章对java来说比较重要。 类和对象这种概念贯穿了整个java,学习它不再是一些常识性的记忆,而有一些思想上的东西在里面。有很多讨论类和对象的专门的书,有时间应该看一下。

1  面向对象的概念

这个概念以我的水平很难说清楚,我只能说列出一些常识性的东西。

首先是类和对象,简单的说:类就是对象的模板,以类为模板可以生成很多具体的对象。

有几个概念需要注意:  封装(Encapsulation),继承(inheritance)。先提一下。

对象有三个特性:行为,状态,identify(不知道怎么翻译,同一性?)

行为:原文是:what can you do with this object, or what methods can you apply to it?。我就把它看成是方法了。

状态:原文是:how does the object react when you apply those methods?。我就把它看成是对象的域。

identify:原文是:how is the object distinguished from others that may have the same behavior and state?。也就是说除了行为和状态外,还有某些东西用来区分不同的对象。identify就是这些东西,具体是什么呢?搞不懂。

类的关系:依赖(uses-a),聚合(has-a),继承(is-a)。字面意思咯,依赖就是类A的方法使用了类B的对象,则A依赖B;集合就是类A包含类B的对象,则A聚合B;类A是类B的子类,则A继承B。

2  定义一个类

开始动手定义一个类。要注意在一个java源文件中,可以定义多个类。在很多书中都写过,这些类中只能有一个public 类,且java文件名必须和这个类名完全一样,否则编译会出错。呵呵,考虑一下如果不声明任何类为public ,会怎样?很爽,此时java文件名可以任意的命名,嘿嘿。

声明一个类很简单,其中构造器很重要。我以前都叫构造函数,但现在改过来了,因为它不是函数。E文中也不是函数,叫constructor,不知道是谁先提出叫构造函数的。看看构造器的几个特点,就知道为什么不是函数了。

1. 构造器的名字与类名一样
2. 一个类有多个构造器
3. 构造器可以有0个或多个参数
4. 构造器没有返回值
5. 构造器只能被new调用

1,4,5都是构造器有别于函数的地方。

对于方法的调用,有两个术语:Implicit Parameters, Explicit Parameters

对于下面的调用语句:

object.method(type para);

object既调用方法的对象是Implicit Parameters,而para参数列表中的参数是Explicit Parameters。

类的声明中最常见的结构就是:域,构造器,方法。域没什么特别的,构造器上面也说了,方法最常见的就是对域的操作。既getor和setor方法(原文是:accessor method和mutator method)。注意如果getor方法需要返回一个可变对象的引用,则要注意返回的应是该对象的一个拷贝。否则可以通过该返回值修改该对象的域。这样便打破了封装,对于面向对象这种思想,这是不好的。

final

final类不能被继承,final方法不能被重写(override),final域必须在构造时被初始化,且以后都不能被改变,做为常量使用。final类中的方法不用特别声明也自动默认是final的,而域不会自动默认为final

3  static静态域和静态方法

静态域有点像全局变量 ,它属于类而不属于对象,类不管生成多少个实例只是共享同一个静态域。

静态方法不是由对象来调用的,而是用类本身来调用。当然,你用一个对象来调用静态方法也是可行的,只是这样不规范。

注意下面三点:

1. 静态方法不能访问实例域(instance field),只能访问静态域(class field)
2. 静态方法仅能调用其它的static方法
3. 静态方法不能以任何方式引用this或super

4  方法的参数

这里对方法参数使用值传递还是引用传递有些争议。有的说对原始类型是值传递,对对象的引用是引用传递。在coro java2的第七版中则是说java中方法的所有参数传递都是值传递。不管参数是基本类型还是一个对象的引用,传递过去的都是参数值的拷贝。对于原始类型,在方法中对拷贝做任何操作都与方法外的值没关系了。对于对象的引用,引用的拷贝和方法外的引用都是指向同一个对象,所以对拷贝的操作是可以改变对象本身的(除非这个对象是不可变的如String,或wrapper类)。但如果改变拷贝指向的对象,则对拷贝的操作就不再和原来的对象有任何关系了。

总结三点如下
1. 方法不能改变原始类型参数
2. 方法可以改变对象的引用参数的状态
3. 方法不可以使一个引用指向另一个对象

5  对象的构造

首先说一下重载:重载是根据相同的方法名,不同的参数(数量不同,类型不同)区分的,返回值不能用于区别重载。

注意:对于基本类型的参数,如果找不到参数能精确匹配的方法时,会对传入参数进行自动转换,如果没有method(int),而有method(double)当调用method(12)时.会去执行method(double)。

在构造类的对象时,会先对域进行初始化,不同类型的域都有默认的初始化值,而方法中的本地变量没有,必须进行初始化。对于整形和浮点形默认初始为0,布尔型号初始为false,对象引用初始为null。char形初始为 ‘/u0000’。注意‘/u0000’不是空格是初始值,空格是’/u0020’。

对象的构造是通过构造器来完成的。关于构造器的特性前面说过。

如果你不写构造器,类就会使用默认的构造器,默认的构造器是没有任何参数的构造器,为域分配默认的初始值。如果你写了构造器,则类就不会使用默认的构造器,此时如果你写的构造器是有参数的,你将不能再使用无参的默认构造器生成对象。

构造器最主要的作用就是初始化域,除了构造,还有两个方法可以初始化域:一可以用常量赋值,甚至使用方法调用来初始化域;二用初始化程序块来初始化域,既用一对花括号将初始化语句括起来。

以下是调用构造器后初始化的顺序:
1. 首先初始化为默认值。
2. 执行所有的赋值初始和初始化程序块。按照他们在类声明中出现的顺序执行。(静态域的初始程序块前要加上static )
3. 如果构造器第一行语句调用了另一个构造器(this(...)/super(....)),则执行第二个构造器。
4. 执行被调用 的构造器

在这里提一点:静态初始化块只在类被加载时初始化一次,以后的对象构造都不会再执行。你可以把一条输出语句写在静态初始化块中,这样不写main函数,语句也会执行。如下:

public   class  Hello
{
   
static
   
{
      System.out.println(
"Hello, World");
      System.exit(
0);
   }

}

 嘿嘿 ,有意思吧,因为执行会提示没有main函数,所以需要加上System.exit(0)

提一下finalize方法,该方法会在进行垃圾回收前被调用(但你不会知道在什么时候进行垃圾回收)。

6  嵌套类

定义在另一个类中的类,嵌套类不为包含类外的类所知。
嵌套类可以直接访问包含类的成员,包含类不能直接访问嵌套类的成员。
嵌套类有两种:静态的和非静态的(既内部类inner class)
静态嵌套类不能直接访问包含类的成员,只能通过对象来访问。(不常用)
内部类可以直接访问包含类的成员。

7  包

使用包的概念是为了保证类名的唯一。

如何将类添加到包中呢?首先,包的语句必须在源文件除注释外的最开始:package XXXX.XXXX。如果不添加包,则源文件的类属于默认的包,默认的包没有包名。主要的问题是在起包名上,包名必须是和源文件所在路径的某子目录是一致的。某子目录如何选择呢?为了解问这个问题,我们先来了解一下解释器如何找到你的源文件。

首先要设置classpath,它列出了目录和归档文件,那是解释器java(不是编译器javac)查找类的起点。查找过程如下:
1. 查找%javahome%/jre/lib和%javahome%/jre/lib/ext中归档形式的系统类文件
2. 按classpath列出的目录和归档文件为起点开始查找。
根据以上定位类的方式,为了让解释器能找到你的源文件,你应该保证:“classpath+路径+包名所对应的子目录”下的目录中就有你的源文件。其中的“路径”可以没有。

将类放到包中后,执行程序时,在任意的路径下输入:java 包名+类名 就可以了.

编译器javac查找源文件比解释器卖力,如果你给出一个没有指定包的类,编译器首先需要找出包含这个类的包:
1. 按导入语句的路径查找(包括java.lang。它总是默认导入的)。
2. 在当前包中查找。
3. 在classpath列出的路径中查找。
同时,编译器还检查如果源文件比类文件新,就会再次编译。
编译器总是会在当前路径下查找,而解释器只会按照classpath查找,除非没有定义classpath.它才会查找当前路径。所以包名如果不对编译时不会出错,但执行时就会提示打不到类。

这里提一下访问修饰符:

Public 可以被任意代码访问。
Private 只能被类中的其它成员访问。
Protected 可以被同一个包中的类,及其子类访问
默认的访问级别:可以被同一包内的任意类访问。

有了包后,我们可以需要将在源文件中将某个包导入,这时使用import,这比较简单,需要注意的一点是:一条导入语句,你只能导入单一的一个包,import java.*是不行的。

另外,5.0中增加了一个静态导入Static imports。既你可以用import static java.lang.System.out;然后在程序中直接使用print();就可以了,挺方便的。

8  关于设计类时需要注意的几点

1. 保持数据私有化(private)
2. 确保数据总是被初始化
3. 在类里不要使用太多的basic types 将basic type分类封装到别的类中。
4. 并不是所有的域都需要accessors and mutators(getor  &  setor方法)
5. 使用统一的,标准的类声明格式
6. 分解有过多功能的类
7. 让你的类名和方法名反映它们所要进行的操作

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值