Java:类(对象)、继承

Java是完全面向对象的,程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。很多对象来自标准库,还有一些是自定义的。
对于规模较小的问题,将其分解为过程的开发方式比较理想。而面向对象更加适用于解决规模较大的问题。

由类构造对象的过程称为创建类的实例
对象中的数据称为实例域。操纵数据的过程称为方法。对每个特定的对象都有一组实例域值,它们统称为对象的当前状态。当向对象发送一个信息,它的状态就有可能发生改变。
对实例域做出修改的方法称为更改器方法,仅访问实例域而不做修改的方法称为访问器方法

包含main方法的public类

一个可以运行的Java程序通常是这样的:一个带有public访问修饰符的a类,以及若干个其他类。a类包含了main方法。
源文件名是a.java,这是因为文件名必须和public类的名字相匹配。在一个源文件中,只能有一个public类。
当编译这段源代码时,编译器在目录下创建若干个类文件:a.class、b.class…
然后,将包含main方法的类名提供给字节码解释器,以便启动这个程序:

java a

字节码解释器运行a类中的main方法。

对象和对象变量

使用构造器构造新实例。构造器是一种特殊的方法,用来构造并初始化对象。构造器的名字和类名相同,构造时,要在构造器前加上new操作符,如

new Date()

这个对象也可以传递给方法,如

String s = new Date().toString();

一般会将对象存放在一个变量中:

Date birthday = new Date();

要认识到,一个对象变量并没有实际包含一个对象,而仅仅是对一个对象的引用

类之间的关系

最常见的关系有:

  • 依赖(uses-a)
  • 聚合(has-a)
  • 继承(is-a)

使用预定义类

在Java中,没有类就无法做任何事情。然而不是所有的类都具有面向对象特征,例如Math类提供了各种方法,它只封装了功能,而不需要隐藏数据。

用户自定义类

最简单类定义形式为:

class ClassName {
    private String name;

    public ClassName(String n) {
        ...
    }

    public String getName() {
        ...
    }
}

构造器

构造器的特点如下:

  • 构造器和类同名
  • 它总是伴随着new操作符被调用
  • 每个类可以有一个以上的构造器
  • 构造器可以有0个或多个参数
  • 构造器没有返回值

和C++不同,Java对象都是在堆中构造的,因此需要new操作符。C++风格的ClassName x(1,2,3);是不行的。

静态域和静态方法

static修饰符表示属于类但不属于对象的变量和函数。

静态域

如果将域定义为static,它将属于类。即使没有一个对象,静态域也存在。

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

静态方法

静态方法是一种不能向对象实时操作的方法,它只能访问自身的静态域。
调用它应该通过类名,以防引起混淆。
例如

Math.pow(x,n);

就是一个静态方法。

方法参数

Java中的方法参数总是采用值调用。
方法参数可以是基本数据类型,也可以是对象引用。
注意,如果是对象引用,它也不是引用调用,它仍然是值传递,是对象的拷贝,只不过对象及其拷贝都指向了同一个对象本身

对象构造

重载

一个类可以有多个构造器,这种特征叫做重载,它们有相同的名字和不同的参数。
Java允许重载任何方法,而不只是构造器方法。

this调用另一个构造器

关键字this的另外一个作用是:如果构造器的第一个语句形如this(…),这个构造器将调用另一个构造器。如:

public Employee(double s) {
    this("abc",s);
    ...
}

当调用new Employee(60)时,构造器Employee(double)调用了Employee(String,double)
采用这种方式,对公共的构造器代码只需要编写一次。

Java允许使用包(package)将类组织起来,以方便组织自己的代码。
标准的Java类库分布在不同的包里,这些包有一个层次结构,允许嵌套。所有的标准Java包都处在java和javax包层次中。

类的导入

一个类可以使用所属包中的所有类,以及其他包中的公共类。采用import java.util.*;就可以使用java.util包中的所有类。


包机制和C++的#include不同,事实上,C++中与包机制相对应的应该是命名空间

using namespace ...

静态导入

import语句不仅可以导入类,还可以导入静态方法和静态域。
例如,如果

import static java.lang.Math.*;

就只需要

sqrt(pow(x,2)+pow(y,2));

而不必写成

Math.sqrt(Math.pow(x,2)+Math.pow(y,2));

将类放入包中

要想将一个类放入包中,就必须将包的名字放在源文件的开头。例如

package xxx;

public calss Employee {
    ...
}

如果没有在源文件中写package语句,这个源文件中的类就被放置在默认包中。

类设计技巧

1) 一定要保证数据私有。
这是最重要的,不破坏封装性。


2) 一定要对数据初始化。
最好不要依赖于系统的默认值,而是应该显式地初始化所有的数据。


3) 不要在类中使用过多的基本类型。
用其他的类代替多个相关的基本类型的使用。


4) 将职责过多的类进行分解。

继承

Java中用extends表示继承

class Manager extends Employee {
    ...
}

和C++不同,所有的继承都是公有继承,而没有私有继承和保护继承。

超类与子类

被继承的类称为超类基类父类。继承而来的类称为子类派生类孩子类
Java程序员更多地使用超类和子类。


子类不能直接访问超类中的私有实例域,只能通过其公有方法。然而,由于子类也继承了超类的公有方法,所以为了正确调用超类中的公有方法,要使用super关键字。例如:

super.getSalary()

相比之下,C++中使用::操作符调用超类的方法。

多态

在Java中,对象变量是多态的,一个超类的变量既可以引用该超类的对象,也可以引用该超类的任何一个子类的对象。
然而,子类变量不能引用超类对象。

阻止继承:final类和方法

有时候,可能希望阻止人们利用某个类定义子类。不允许拓展的类被称为final类

final class Executive extends Manager {
    ...
}

类中的方法也可以被声明为final,如果这样做了,子类就不能覆盖这个方法

class Employee {
    ...
    public final String getName {
        ...
    }

}

将方法或类声明为final的主要目的是:确保它们不会在子类中改变语义。

抽象类

在类的继承层次结构中,位于上层的类更具有通用性,如果最高层的祖先类不需要有实例对象,就可以把它作为抽象类。不需要实现的方法叫做抽象方法。
使用abstract关键字,就可以声明不需要实现的方法:

public abstract String getDescription();

同时,包含一个或多个抽象方法的类本身必须被声明为抽象的。

abstract class Person
{
    public abstract String getDescription();
}

抽象类不能被实例化。另外,可以定义一个抽象类的对象变量,但是它只能引用非抽象子类的对象。

受保护的访问

如果希望超类中的某个域对子类也是可见的,可以使用protected关键字。

Object:所有类的超类

Object是所有类的始祖,在Java中每个类都是由它扩展而来的。
可以使用Object类型的变量引用任何类型的对象。只有数值、字符和布尔值不是对象,其他不管是对象数组还是基本类型的数组都扩展于Object类。

Object obj = new int[10];

toString方法

在Object中的toString方法用于返回表示对象值的字符串。例如:

int[] luckyNumber = {2,3,4,5};

String s = Arrays.toString(luckyNumber);

将生成字符串"[2,3,4,5]"
toString方法是一种非常有用的调试工具,用户能够获得一些有关对象状态的必要信息。

泛型数组列表ArrayList

ArrayList是一个采用类型参数的泛型类,用到一对尖括号将指定元素对象类型括起来。例如ArrayList<Employee>
下面声明和构造一个保存Employee对象的数组列表:

ArrayList<Employee> staff = new ArrayList<>();

使用add方法可以将元素添加到数组列表,例如

staff.add(new Employee("Harry Hacker",...));

如果调用add且内部数组已经满了,数组列表就将自动地创建一个更大的数组,并将所有的对象从较小的数组中拷贝到较大的数组中。


如果能够预计存储的空间大小,就可以在填充数组之前,调用ensureCapacity方法:

staff.ensureCapacity(100);

上面分配了一个包含100个对象的内部数组。
另外,还可以将初始容量传递给ArrayList构造器:

ArrayList<Employee> staff = new ArrayList<>(100);

size方法将返回数组列表所包含的实际元素数目。它等价于数组a的length方法。
一旦能够确认数组列表的大小不再发生变化,就可以调用trimToSize方法,它将调整存储区域大小,回收多余的存储空间。


和C++不同,Java没有运算符重载,因此不能通过 [] 访问元素。另外,a = b在C++中是值拷贝,而在Java中表示让a和b引用同一个数组列表。

访问数组列表元素

ArrayList类不是Java的一部分,只是一个标准库中的使用类。使用get和set方法实现访问或改变数组元素的操作,而不使用人们喜爱的 [] 语法格式。
例如要设置第i个元素,可以使用:

staff.set(i,harry);

它等价于对数组a的元素赋值:

a[i]=harry;

至于

Emyloyee e = staff.get(i);

则等价于:

Employee e = a[i];

常用的ArrayList操作

//修改staff[i]的元素值
staff.set(i,x);

//获取指定位置的元素
e = staff.get(i);

//插入元素
staff.add(i,x);

//删除元素
staff.remove(i);

对象包装器与自动装箱

有时候需要将int这样的基本类型转换为对象,所有的基本类型都有一个与之对应的类。这些类称为包装器:Integer、Long、Float 、Double、Short、Byte、Character、Void和Boolean。
对象包装器类是不可变的。
将基本类型赋给包装器会进行自动装箱,反之会进行自动拆箱。这些操作由编译器执行,而不是虚拟机。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值