Java基础知识 一 对象与类

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

  • 面向对象的程序由对象组成,每个对象中包含对用户公开的特定功能部分隐藏的实现部分。程序中的很多对象来自标准库,还有一些是自定义的。至于是自己构造对象,还是从外界购买对象完全取决于开发项目的预算和时间。但是,从根本上说,只要对象满足需求,就不必关心起功能的具体实现过程。
  • 在OOP中,不必关心对象的具体实现,只要能够满足用户的需求即可。

①类
相关概念:类(class)、构造(construct)、实例(instance)、封装(encapsulation)、实例域(instance field)、方法(method)、状态(state)
②对象
对象的三个主要特性:
- 对象的行为(behavior)——可以对对象施加哪些操作,或可以对对象施加哪些方法?
- 对象的状态(state)——当施加这些方法时,对象如何响应?
- 对象标识(identity)——如何辨别具有相同行为与状态的不同对象?
③识别类
识别类的简单规则是,在分析问题的过程中寻找名词,而方法对应着动词。而在创建类时,哪些名词和动词是重要的完全取决于个人的开发经验。
④类之间的关系
在类之间,常见的关系有

  • 依赖(“uses-a”),例如Order类使用Account类是因为Order对象需要访问Account对象查看信用状态;应尽可能地将相互依赖的类减至最少(低耦合);
  • 聚合(“has-a”),例如一个Order对象包含一些Item对象;
  • 继承(“is-a”)

注,表达类关系的UML符号
这里写图片描述

(2)使用预定义类(已经定义好的类)
①对象与对象变量
相关概念:

  • 构造器(constructor),一种特殊的方法,用来构造并初始化对象。
  • 对象和对象变量的区别:

    Date deadline;

    上面代码,定义了一个对象变量deadline,他可以引用Date类型的对象。但是,一定要注意:变量deadline不是一个对象,且目前也没有引用对象。此时,不能将任何Date方法应用于这个变量上。语句

    String s = deadline.toString();

    将产生编译错误。
    一定要注意:一个对象变量并没有实际包含一个对象,而仅仅引用了一个对象。在Java中,任何对象变量的值都是对存储在另一个地方的一个对象的引用。new操作符的返回值也是一个引用。
    可以将一个对象变量设置为null,表明这个对象变量目前没有引用任何对象。
    ③更改器方法与访问器方法
    更改器方法:对实例域做出修改的方法;
    访问器方法:仅访问实例域而不进行修改。
    (3)用户自定义类

  • 在一个源文件中,只能有一个共有类,可以有任意多数目的非公有类;

  • 使用 javac 编译源代码时,如果包含main函数的类A所依赖的类B,且B跟A不在一个源文件中,编译器会自动查找类B所在的源文件进行编译;
  • 构造器的性质:
    • 构造器与类同名;
    • 每个类可以有一个以上的构造器;
    • 构造器可以有0个、1个或多个参数;
    • 构造器没有返回值;
    • 构造器总是伴随着new操作一起使用。
  • 隐式参数与显示参数

    • 方法用于操作对象以及存取对象的实例域。例如,方法:

      public void raiseSalary(double byPercent)
         {
            double raise = salary * byPercent / 100;
            salary += raise;
         }

      将调用这个方法的对象的salary实例域设置为新值。例如,

      number007.raiseSalary(5);

      它的结果将number007.salary域的值增加5%。具体说,这个调用将执行下列指令:

      double raise = number007.salary * byPercent / 100;
      salary += number007.raise;

      其中,raiseSalary方法有两个参数。第一个参数称为隐式参数(implicit),是出现在方法名前的Employee对象。第二个参数是位于方法名后面括号中的数值,这是一个显式参(explicit)数。
      可以看到,显式参数是明显列在方法声明中的,例如double byPercent。隐式参数没有出现在方法生命中。
      在每一个方法中,关键字this表示隐式参数。如果需要的话,可以使用下列方式编写raiseSalary方法:

      public void raiseSalary(double byPercent)
         {
            double raise = this.salary * byPercent / 100;
            this.salary += raise;
         }

      这种方式可以将实例域与局部变量明显区分开来。

  • 封装的优点:

    • 在有些时候,需要获取或设置实例域的值。因此,应该提供下面三项内容:
      • 一个私有的数据域;
      • 一个公有的域访问器方法;
      • 一个公有的域更改器方法。
        这样做的要比提供一个简单的公有数据域复杂一些,但却有着明显的好处:
      • 首先,可以改变内部实现,除了改类的方法之外,不会影响到其他代码;
      • 然后,更改器方法可以执行错误检查,然而直接对域进行赋值不会进行这些处理。
    • 警告:注意不要编写返回引用可变对象的访问器方法,这样会破坏封装性!(corejava,p113)
  • 基于类的访问权限

    • 一个方法可以访问所属类的所有对象的私有数据。
  • 私有方法
    在实现一个类时,由于公有数据非常危险,所以应该将所有的数据域都设置为私有的。对于方法而言,尽管绝大多数方法都被设计成为公有的,但是某些情况下,也可能将它们设计为私有的。有时,可能希望将一个计算代码划分为若干个独立的辅助方法。通常,这些辅助方法不应该成为公有接口的一部分,这是由于它们往往与当前的实现机制非常紧密,或者需要一个特殊的协议及一个特别的调用次序。最好将这样的方法设置为private的。
    对于私有方法,如果改用其他方法实现了相应的操作,则不必保留原有的方法。因为,只要方法是私有的,类设计者就可以确定:它们不会被外部的其他类操作调用,可以将其删除。如果方法是公有的,则不能删除,因为其他的代码很可能依赖它。

  • final实例域

    • 特点1:构造对象时必须初始化这样的域。也就是说,必须确保一个构造器执行之后,这个域的值被设置,并且在后面的操作中,不能够再对它做修改操作。
    • 特点2:final修饰符大都应用在基本(primitive)类型域,或不可变类的域(如果类中的每个方法都不会改变其对象的状态,这种类就是不可变的类。例如,String类。)

(4)静态域与静态方法
①静态域(类域)
如果将域定义为static,则每个类只有一个这样的域。而每个对象对所有的实例域却都有自己的一份拷贝。静态域属于类,它不属于任何独立的对象(可以用来统计类实例化出来的对象的个数)。
②静态常量
静态变量使用较少,但静态变量比较常用。
③静态方法

  • 静态方法,是一种不能向对象实施操作的方法,即没有隐式的参数的方法;
  • 在下面两种情况下使用静态方法:
    • 一个方法不需要访问对象状态,其所需参数都是通过显式参数提供(如,Math.pow())。
    • 一个方法只需要访问类的静态域。

④工厂方法(???)
静态方法还有一种常见的用途。NumberFormat 类使用工厂方法产生不同风格的格式对象。

NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFormatter = NumberFormat.getPercentInstance();
double x = 0.1;
System.out.println(currencyFormatter.format(x));
System.out.println(percentFormatter.format(x));

为什么NumberFormat类不用构造函数完成这些操作呢?主要原因有两个:

  • 无法命名构造器。构造器的名字必须跟类同名。但是,这里希望将得到的货币实例和百分比实例分别采用不同的名字;
  • 当使用构造器时,无法改变所构造的对象类型。而Factory方法将返回一个DecimalFormat类对象,这是NumberFormat的子类。

⑤main方法

  • 不需要使用对象调用静态方法。
  • 同理,main方法也是一个静态方法。因此,它不对任何对象进行操作。事实上,在启动程序时,还没有任何一个对象。静态的main 方法将执行并创建程序所需的对象。
    提示:每个类可以有一个main方法。这是一个常用于对类进行单元测试的技巧。

(5)方法参数

  • 将参数传递给方法(或函数)的两种方式:
    • 按值调用,表示方法接收的是调用者提供的值;
    • 按引用调用,表示方法接收的是调用者提供的变量的地址
  • 一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。
  • Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。
  • 方法参数公有两种类型:

    • 基本数据类型(数字、布尔值);
    • 对象引用。
  • 在Java中,一个方法不可能修改一个基本数据类型的参数。而对象引用作为参数则不同,它使得方法可以借助对象引用的拷贝来修改对象参数状态(因为,对象引用及其拷贝同时引用同一个对象)。

  • 总结,Java程序设计语言中方法参数的使用情况:
    • 一个基本数据类型(即数值型和布尔型)作为参数传递给方法时,方法不能修改参数的值;
    • 一个对象的引用值(地址)作为参数传递给方法时,方法可以借助该引用(地址)修改对应对象的状态;
    • 一个对象的引用值(地址)作为参数传递给方法时,方法不能让引用(地址)重新引用一个新的对象。

(6)对象构造
①重载
一个类中有多个同名的方法,调用方法时通过传递的参数的类型来区分。
②域的默认初始化
如果在构造器中没有显式地给域赋予初值,那么就会被自动的赋予默认值:数值默认值为0,布尔值为false,对象引用为null。然而,这是一种极坏的编程习惯。
注:这是域与局部变量的主要不同点。方法中的局部变量必须明确地初始化。但是,如果没有初始化类中的域,则它将会被初始化为默认值(0,false或null)。
③无参构造器
如果在编写一个类时没有编写构造器,那么系统就会提供一个无参构造器。这个构造器将所有的实例域设置为默认值(0,false或null)。注意,只有当用户没有编写构造器时,系统才会提供一个默认的无参构造器。如果类中提供了至少一个构造器,但没有提供无参构造器,则在构造对象时如果没有提供参数就会被视为不合法。
④域的显式初始化
由于类的构造方法可以重载,所以可以采用多种形式设置类的实例域的初始状态。这是一种很好的设计习惯。

  • 可以在类的定义中,直接将一个值赋给任何域。例如:

    class Emplyee {
        private String name = "";
        ...
    }

    在执行构造器之前,先执行赋值操作。当一个类的所有构造器都希望把相同的值赋给某个特定的实例域时,这种方式特别有用。

  • 初始值不一定是常量。下例,可以调用方法对域进行初始化。

    class Emplyee {
        private static int nextId;
        private int id = assignId();
    
        private static int assignId() {
            int r = nextId;
            nextId++;
            return r;
        }
    }

⑤参数名
推荐风格为:

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

⑥调用另一个构造器
关键字this的另一种用法:可以在构造器中调用同一个类的另一个构造器。
好处:对公共的构造器代码部分只编写一次。
⑦初始化块
初始化数据域的三种方法:

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

静态域初始化:
可以通过提供一个初始化值,或使用一个静态的初始化块来对静态域初始化;如果对类的静态域初始化的代码比较复杂时,可以使用静态的初始化块。

(7)包
作用:

  • 方便类的组织;
  • 确保类名的唯一性:在两个不同的包中,可以有相同名字的类。

①类的导入
一个类可以使用所属包的所有类,以及其他包的公有类(public class)。
访问其他包公有类的两种方式:

  • 第一种,在每个类名之前添加完整的包名;
  • 第二种,import关键字导入一个特定的类或整个包。

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

import static java.lang.System.*;

/**
 * Created by bmi-xiaoyu on 2017/5/22.
 */
public class Test1 {
    public static void main() {
        out.println("".toString()); //使用静态方法时不用加类名
    }
}

import 还可以导入特定的方法或域:

import static java.lang.System.out;

④包作用域
对于类、方法或变量,标记为public的部分可以被任意的类使用;标记为private的部分只能被定义它们的类使用;如果不指定public或private,则这个部分可以被同一个包中的所有方法访问。
这里写图片描述
(8)类路径
为了使类能够被多个程序共享,可以采用以下方式中的一种:

  • 把类放在一个目录中;
  • 将JAR文件放在一个目录中;
  • 设置类路径(class path)。类路径是所有包含类文件的路径的集合。

(9)文档注释
详细介绍了,如何利用JDK中提供的 javadoc 工具生成注释。
(10)类设计技巧
应用这些技巧会使得设计出来的类更具有OOP的专业水平:

  • 一定要保证数据私有。
  • 一定要对数据初始化。
  • 不要在类中使用过多的基本类型。
  • 不是所有的域都需要独立的域访问器和域更改器。
  • 将职责过多的类进行分解。
  • 类名和方法名要能够体现它们的职责。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值