Java实践(二)---对象和类

1.面向对象程序设计(OOP)概述

每个对象包含对用户公开的特定功能部分和隐藏的实现部分,在OOP中,不必关心对象的具体实现,只要能满足用户的需求即可

1.类

类(class)是构造对象的模板和蓝图,由类构造(construct)对象的过程称为创建类的实例(instance)
封装不过是将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式
对象中的数据称为实例域(instance field),操纵数据的过程称为方法(method)

实现封装的关键在于绝对不能让类中的方法直接地访问其他类中的实例域(数据)

在Java中所以的类都是源自于一个超类Object,扩展后的新类具有所扩展的类的全部属性和方法,在新类中只需要提供适用于这个新类的新方法和数据域就可以了

2.对象
对象状态的改变必须通过调用方法实现

3.识别类
面向对象程序设计时,首先从设计类开始,然后在往每个类中添加方法
一般名词为类名,动词为方法

4.类之间的关系

依赖(use-a)如果一个类的方法操纵另一个类的对象,就是一个类依赖另一个类
聚合(has-a)聚合关系意味着类A的对象包含类B的对象
继承(is-a)

使用UML(Unified Modeling Language,统一建模语言)绘制类图,用来描述类之间的关系

2.使用预定义类

1.对象与对象变量
想要使用对象,必须先构造对象,并指定其初始状态,然后,对对象应用方法;在Java程序设计语言中,使用构造器(constructor)构造新实例,构造器是一种特殊的方法,用来构造并初始化对象。构造器的名字应该与类名相同,使用new操作符进行构造新对象

对象和对象变量之间存在重要的区别,new构造的对象仅使用一次,想要使用多次就要将对象存放在一个变量中

一个对象变量并没有实际包含一个对象,而仅仅引用一个对象
在Java中,任何对象变量的值都是对存储在另一个地方的一个对象的引用

Date deadline = new Date();

有2部分,表达式new Date()构造了一个Date类型的对象,并且它的值是新创建对象的引用,这个引用存储在变量deadline中

deadline = null

显式的将对象变量设置为null,表明这个对象变量目前没有引用任何对象

所有的Java对象都存储在堆中,在Java中,必须使用clone方法获得对象的完整拷贝

2.Java类库中的GregorianCalendar类
Date类的实例有一个状态,即特定的时间点

一个使用来表示时间点的Date类
一个使日历表示法的GregorianCalendar类

new GregorianCalendar();

构造一个新对象,用于表示构造时的日期和时间(月份从0开始,因此11表示十二月,也可以使用常量Calendar.DECEMBER)

GregorianCalendar deadline = new GregorianCalendar(. . .);

通常将构造的对象存储在对象变量中

3.更改器方法和访问器方法
日历的作用是提供某个时间点的年、月、日等信息,要查询这些信息,使用GregorianCalendar类的get方法,使用set方法改变对象的状态
使用Calendar类中定义的一些常量,来获得希望得到的项,如:Calendar.MONTH或Calendar.DAY_OF_WEEK
get方法仅仅查看并返回对象的状态,set和add方法却对对象的状态进行修改
通常的习惯是在访问器方法名前加上get,在更改器方法名前加上set

3.用户自定义类

用户自定义的类每一main方法,却有自己的实例域和实例方法
文件名必须与public类的名字匹配,在一个源文件中只能有一个公有类,可以有任意数目的非公有类

关键字public意味着任何类的任何方法丢可以调用这些方法,共有四种访问级别:

public:公有的 可跨类跨包访问 (本类 本包内类 包外类)
protected:与继承有关 本类 子类可访问(相同包中的类可访问)
private:私有的 本类访问
默认模式:本类 本包可访问
final 最终的 无法改变 (不能被继承)【将实例域定义为final,构造对象时必须初始化这样的域】
static 语句块用于初始化static成员变量,是最先运行的语句块(比构造方法还要先运行)

final修饰符大都应用于基本类型域,或不可变类的域(如果类中的每个方法都不会改变其对象,这种类就是不可变的类,例如String类就是不可变的类)

类通常包括类型属于某个类类型的实例域

1.构造器(不要在构造器中定义与实例域重名的局部变量)

构造器与类同名
构造器总是伴随着new操作符的执行被调用
每个类可以有一个以上的构造器
构造器没有返回值

所以的Java对象都是在堆中构造的

2.隐式参数与显式参数

number007.raiseSalary5;

其中隐式参数:number007;显式参数:5
隐式参数没有在方法声明中,显式参数明显的列在方法声明中,在每个方法中,关键字this表示隐式参数

3.封装的优点
封装包括:一个私有的数据域,一个公有的域访问器方法,一个公有的域更改器方法

不要编写返回引用可变对象的访问器方法

class Employee
{
    private Date hireDay();
    . . .
    public Date getHireDay()
    {
        return Date hireDay;
    }
    . . .
}

如果需要返回一个可变对象的引用,应该首先对它进行克隆(clone),对象克隆是指存放在另一个位置上的对象副本

class Employee
{
    private Date hireDay();
    . . .
    public Date getHireDay()
    {
        return hireDay.clone();
    }
    . . .
}

如果需要返回一个可变数据域的拷贝,就应该使用clone

4.静态域与静态方法

1.静态域(类域)

class Employee
{
    private static int nextID = 1;
    private int id;
    . . .
}

如果将域定义为static,每个类中只有一个这样的域,所有实例将共享一个nextID域,即使没有雇员对象,静态域nextID也存在,它属于类,而不属于任何独立的对象。

2.静态常量

public class Math
{
    . . .
    public static final double PI = 3.14159268358979323846;
    . . .
}

公有常量(final域)

3.静态方法
静态方法是一种不能像对象实施操作的方法,没有隐式参数;静态方法可以访问自身类中的静态域

public static int getNextID()
{
    return nextID;//return static field
}

通过类名调用这个方法:

int n = Employee.getNextID();

在下面2中情况下使用静态方法:

一个方法不需要访问对象状态,其所需参数都是通过显式参数提供(如Math.pow)
一个方法只需要访问类的静态域(如Employee.getNextID)

4.main方法
main方法不对任何对象进行操作,在启动程序时还没有任何一个对象,静态的main方法将执行并创建程序所需的对象

5.方法参数

按值传递(call by value):方法接收的是调用者提供的值
按引用传递(call by reference):方法接收的是调用者提供的变量地址

Java程序设计语言总是采用按值传递,方法得到的是所有参数值的一个拷贝,方法不能修改传递给它的任何参数变量的内容

方法的参数共有2中类型:

基本数据类型(数字、布尔值)
对象引用(或者称为对象变量【对象变量中存储的是一个对象的引用】)

一个方法不可能修改一个基本数据类型的参数,对象引用做为参数就不同了,方法得到的是对象引用的拷贝,对象引用及其拷贝同时引用同一个对象(实际上对象引用进行的是值传递)
Java程序设计语言中方法参数的使用情况:

一个方法不能修改一个基本数据类型的参数(数值型,布尔型)
一个方法可以改变一个对象的状态
一个方法不能让对象参数引用一个新的对象

6.对象构造

1.重载
如果多个方法有相同的名字、不同的参数,便产生了重载,Java允许重载任何方法,因此要完整的描述一个方法,需要指出方法名参数类型,返回类型不是方法签名的一部分。

2.默认域初始化
如果在构造器中没有显式地给域赋予初值,那么就会被自动地赋为默认值:数值为0,布尔值为false,对象引用为null【必须明确初始化方法中的局部变量】

3.无参数的构造器
如果在编写一个类时没有编写构造器,那么系统就会提供一个无参数构造器,这个构造器将所有的实例域设置为默认值,如果类中提供了至少一个构造器,但是没有提供无参构造器,则在构造对象时如果没有提供参数就会被视为不合法

4.显式域初始化
在类定义中,直接将一个值赋给任何域,在执行构造器前,先执行赋值操作

5.参数名
在编写很小的构造器时,通常,参数用单个字符命名,如:

public Employee(String n,double s)
{
    name = n;
    salary = s;
} 

采用另一种技巧(参数变量用同样的名字将实例域屏蔽起来),如:

public Employee(String name,double salary)
{
    this.name = name;
    this.salary = salary;
} 

this指示隐式参数,也就是被构造的对象

6.调用另一个构造器
如果构造器的第一个语句形式如this(…),这个构造器将会调用同一个类的另一个构造器,如:

public Employee(double s)
{
    this("Employee #"+ nextID, s);//calls Employee(String, double)
    nextID++;
} 

采用这种方式使用this关键字非常有用,这样对公共的构造器代码部分只要编写一次即可

7.初始化块
初始化域的方法有:

在构造器中设置值
在声明中赋值
初始化块

在一个类的声明中,可以包含多个代码块,只要构造类的对象,这些块就会被执行,首先运行初始化块,然后才运行构造器的主体部分(建议将初始化块放在域定义之后),如:

class Employee
{
    private int id;
    private String name;
    private double salary;
    {//object initialization block 
        id = nextID;
        nextID++;
    }
    public Employee(String name,double salary)
    {
        name = name;
        salary = salary;
    }
    public Employee()
    {
        name = "";
        salary = 0;
    }
    . . . 
} 

调用构造器的具体步骤

1.所有数据域被初始化为默认值
2.按照类声明中出现的次序,一次执行所有域初始化语句和初始化块
3.如果构造器第一行调用第二个构造器,则执行第二个构造器主体
4.执行这个构造器主体

使用静态初始化块对静态域进行初始化
在类第一次加载的时候,将会进行静态域的初始化,与实例域一样,除非显式地设置成其他值,否则初始化为默认值,所有的静态初始化语句以及静态初始化块都依照类定义的顺序执行

8.对象析构与finalize方法
由于Java有自动的垃圾回收器,不需要人工回收内存,所以Java不支持析构器,可以为任何一个类添加finalize方法,finalize方法将在垃圾回收器清理对象之前调用,对象用完时,可以应用一个close方法来完成相应的清理操作

7.包

所有标准的Java包都处于java和javax包层次中,为了保证包名的绝对唯一性,Sun公司建议将公司的因特网域名以逆序的形式作为包名,并且对于不同的项目使用不同的子包,从编译器的角度看,嵌套的包没有任何关系,每一个都拥有独立的类集合

1.类导入
如果能够明确地自出所导入的类,将会使代码的读者更加准确地知道加载了哪些类,在包中定位类是编译器(compiler)的工作,Import语句的唯一好处是简捷,可以使用简短的名字而不是完整的包名来引用一个类

2.静态导入
import语句不仅可以导入类,还增加 导入静态方法和静态域的功能,如:

import static java.lang.System.*;

可以使用System类的静态方法和静态域,而不必加类名前缀

3.将类放入包中
将一个类放入包中,必须将包的名字放在源文件的开头
编译器对文件(带有文件分隔符和扩展名.java的文件)进操作,而Java解释器加载类(带有.分隔符)

4.包作用域
标记为public的部分可以被任意的类使用,标记为private的部分只能被定义它们的类使用;如果没有指定public和private,这部分可以被同一个包中的所有方法访问

8.类路径

类的路径必须与包名匹配
在jre/lib/tr/jar中包含数千个类库文件

为了使类能够被多个程序共享,需要走到下面几点:

1.把类放到同一个目录中【这个目录是包树状结构的基目录】
2.JAR文件放在同一个目录中
3.设置类路径(CLASSPATH),类路径是所有包含类路径的集合【类路径包括基目录,JAR文件目录,当前目录(.)】

由于运行时库文件(rt.jar和在jre/lib与jre/lib/ext目录下的一些其他的JAR文件)会被自动地搜索,所有不必显式的列在类路径中
类必须是唯一的,而import语句的次序缺无关紧要

编译器还要查看源文件是否比类文件新,如果是这样的话,类文件会被重新编译,仅可导入其他包中的共有类,一个源文件只能包含一个公有类,并且文件名必须与公有类匹配,因此编译器很容易定位到公有类的源文件

9.文档注释

JDK包含一个叫javadoc的工具,可以由源文件生成一个HTML的文档,由于文档注释与源代码在同一个文件中,在修改源代码的同时,重新运行javadoc就可以轻易的保证两者的一致性

javadoc从如下几个特性中抽取信息:


公有类与接口
公有的和受保护的构造器及方法
公有的和受保护的域

注释的位置:

注释应该放在所描述特性的前面,注释以/**开始,以*/结束
类注释必须放在import语句之后,类定义之前
每个方法注释必须放在所描述的方法之前
只需要对公有域(通常指的是静态常量)建立文档

10.类设计技巧

1.一定要保证数据私有
2.一定要对数据初始化
3.不要在类中使用过多的基本类型
4.不是所有的域都需要独立的域访问器和域更改器
5.将职责过多的类进行分解
6.类名和方法名要能够体现他们的职责

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值