• Java核心技术——第4章


    面向对象程序设计概述

    面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。

    从根本上说,只要对象满足要求,不必关心其功能的具体实现过程。

    与传统的结构化程序区别:

    • 传统的结构化程序通过一系列过程(算法)来求解问题,算法是第一位,数据结构第二位
    • OOP则是数据第一位,然后考虑操作数据的方法

    相关概念

    • 类:构造对象的模板或蓝图

    • 封装:将数据和行为组合在一个包中,并对对象的使用者隐藏数据的实现方式

      封装的关键:绝不能让类中的方法直接访问其他类的实例域

    • 继承:拓展一个类来建立另外一个类的过程

    如何识别类

    分析问题时找名词和动词,名词对应类,动词对应方法

    对象

    三个主要特性

    • 对象的行为:由可调用的方法决定
    • 对象的状态:状态的改变必须通过调用方法实现——封装的体现
    • 对象的标识:同一个类创建的实例,标识永远是不同的

    类与类之间的关系

    • 依赖(uses-a):一个类的方法操纵另一个类的对象,应尽可能避免这种关系
    • 聚合(has-a):类A的对象包含类B的对象
    • 继承(is-a):表示特殊与一般的关系

    使用预定义类

    对象与对象变量

    • 构造器:特殊的方法,名字与类名相同,用于构造对象

      new Date()
      
    • 对象变量:引用一个对象,并不是包含一个对象,类似于指针

      Date birthday = new Date();
      

      局部变量不会自动初始化为null,必须通过调用new或设置为null进行初始化

    更改器方法和访问器方法

    • 更改器方法:调用后对象的状态改变
    • 访问器方法:调用后对象的状态不变,只访问不修改

    用户自定义类

    一个源文件中只能有一个公有类,但可以有任意数量的非公有类

    如果将每个类单独放在一个源文件中时,可以用通配符一起编译,也可以只编译共有类所在的源文件

    关键字public:任何类的任何方法都可以调用

    关键字private:只有本类中的方法可以访问

    构造器

    • 构造器与类同名
    • 构造器总是伴随着new操作符的执行被调用,而不能对一个已存在的对象调用
    • 不要在构造器中定义与实例域重名的局部变量

    隐式参数与显式参数

    number007.raiseSalary(5);
    
    • 隐式参数:方法的调用者,不出现在方法的声明中,即上面调用代码中的number007,在方法声明时可用关键字this表示隐式参数
    • 显式参数:明显地列在方法声明中的参数

    封装的优点

    要获取或设置实例域的值,应提供:

    1. 一个私有的数据域
    2. 一个公有的访问器方法——可以改变方法的内部实现,而不会影响其他代码
    3. 一个公有的更改器方法——可以执行错误检测

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

    例:

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

    其中Data类对象是可变的,如果返回的hireDay改变,则会同时改变类中的私有数据域,破坏了封闭性

    如果要返回一个可变对象的引用,则首先对它进行克隆

    final实例域

    • 应用于基本类型域、不可变类的域:相当于是常量,其值不能改变

      不可变类:类中的每个方法都不会改变其对象

    • 应用于可变域:相当于c中const int*指针,不可以指向其他的对象,但是修改它指向的对象

    静态域与静态方法

    静态域

    关键字static,类的所有实例共享静态域,属于类,不属于任何一个独立对象,可以通过类名来访问

    静态常量

    public class Math
    {
    	public static final double PI = 3.14;
    }
    

    可采用Math.PI访问

    如果没有static,则变成Math的实例域,需要Math类对象访问,并且每个对象都有一份拷贝

    静态方法

    静态方法是一种不能向对象实施操作的方法,不能访问实例域,因为只有对象才能访问实例域,但可以访问自身类中的静态域

    以下两种情况下使用静态方法:

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

    关键词static含义:属于类但不属于对象的变量和函数

    工厂方法

    也属于静态方法,直接使用类名调用,用于构造对象

    为何不用构造器?

    1. 无法命名构造器,该类不同种类的构造方法,要加以区分则使用工厂方法
    2. 使用构造器时,无法改变所构造的对象类型

    main方法

    main方法也是静态方法

    main方法不对任何对象进行操作

    每个类都可以有一个main方法,常用于对类进行单元测试

    方法参数

    • 按值调用:方法接收的是调用者提供的值
    • 按引用调用:方法接收的是调用者提供的变量地址

    Java总是按值调用,即方法得到的时所有参数值的一个拷贝

    注意Java的对象引用

    public static void swap(Employee x,Employee y)
    {
    	Employee tmp=x;
    	x=y;
    	y=tmp;
    }
    

    这是不能交换x,y所引用的对象,只是交换了x,y的拷贝

    image-20200412095509885

    总结:

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

    对象的构造

    重载

    如果多个方法有相同的名字、不同的参数,则产生重载,返回类型不同不可以,即不能有两个名字相同、参数类型相同,但返回类型不同的方法

    默认域初始化

    如果没有在构造器中显式给域赋予初值,则会自动被赋为默认值(数值0,布尔值false,对象引用null)

    区别于局部变量,局部变量必须被明确的初始化

    无参数的构造器

    类中没有构造器时,系统会提供一个默认的无参数构造器

    类中一旦有构造器,则系统提供的构造器无效

    显式域初始化

    可以给任何域显式的赋予初值,这样的赋值会在构造器之前执行,而且赋值不一定是常数,可以调用方法进行初始化

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

    参数名

    参数变量如果和实例域的名称相同,则会覆盖实例域,此时要想访问实例域需要通过this关键词

    好的习惯:

    在参数前加前缀”a“

    public Employee(String aName,double aSalary)
    {
    	name = aName;
    	salary = aSalary;
    }
    

    或者通过this

    调用另一个构造器

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

    public Employee(double s)
    {
    	this("Employee #"+nextId,s);
    	nextId++;
    }
    

    初始化块

    设置一个代码块,在其中放入域初始化语句,则可在构造器执行之前对域进行初始化

    调用构造器的具体步骤:

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

    一般通过提供一个初始化值初始化静态域,如果初始化语句比较复杂,则可以使用静态初始化块

    • Java允许用包(package)将类组织起来,方便组织自己的代码
    • 使用包主要原因是确保类名的唯一性
    • 从编译器的角度看,嵌套包之间没有任何联系
    • 包的命名习惯:以域名的倒序作为包名——保证包名的唯一性

    类的导入

    一个类可以使用所属包中的所有类,以及其他包中的公有类

    如何访问公有类:

    1. 在类名前加上完整的包名

    2. 使用import导入相关的类,然后就可以直接使用类中的方法

      注:import 可以用*导入多个类,但是不能导入多个包

    如果导入的包中含有同名的类怎么办:

    1. 如果只需使用其中一个类,则再次import这个特定的类
    2. 如果两个类都要使用,则在使用前加上完整的包名

    静态导入

    import 不仅可以导入类,还能导入静态方法和静态域

    注意:不能静态导入类!!

    import static java.lang.Math.*;
    

    这样就不用加类名前缀了,如sqrt(pow(x,2)+pow(y,2))

    将类放入包中

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

    package com.horstmann.coreJava;
    

    对应的源文件会被放在com/horstmann/coreJava目录下

    包作用域

    类、方法、变量:

    • public:可以被任意类使用
    • private:只能被定义它们的类使用
    • 没有指定:可以被同一个包中的所有方法访问

    类设计技巧

    1. 一定要保证数据私有

    2. 一定要对数据初始化

    3. 不要在类中使用过多的基本类型

      用其他类代替多个相关的基本类型

    4. 不是所有的域都需要独立的域访问器和域更改器

    5. 将职责过多的类进行分解

    6. 类型和方法名要能体现它们的职责

    7. 优先使用不可变的类

      更改对象的问题在于:如果多个线程试图同时更新一个对象,就会发生并发更改,其结果不可预料

  • 相关阅读:
    【转】Windows Server 2003为什么识别不了的移动硬盘
    VBSCRIPT常用函数【转】
    【轉】javascript实现图片缩略与优化
    【转】Tips:禁用Windows Beep声
    EXT同struts2后台交互一个中文问题
    ASCII码对照表[转]
    bat判断进程存在不存在
    look与look like
    美国俚语there was no snap in his turtle
    take credit for用法
  • 原文地址:https://www.cnblogs.com/xkf97/p/12688338.html
Copyright © 2020-2023  润新知