第三章 面向对象编程
面向对象3条主线
1) 类和类的成员的研究(memeber)
2) 方法(method)
3) 构造器(constructor)
4) 语句块(block)
5) 内部类(nested class)
2) 面向对象的三大特征
1) 封装(encapsulation)
2) 继承(inheritance)
3) 多态(polymorphism)
3) 其他关键字
this, super, package, import, static, final, native, abstract .....
面向对象原则 :
1)有现成的对象,直接拿来用
2) 没有现成的对象, 制造一个这样的对象
总而言之就是要通过对象来完成任务
面向对象与面向过程
区别
- 
二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为。面向对象,将功能封装进对象,强调具备了功能的对象。 
- 
面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。 
OOP: Object Oriented Programming
面向过程:procedure oriented programming
面向对象的思想概述
- 
程序员从执行者转化成了指挥者。 
- 
完成需求时: 先去找具有所需功能的对象来用。 如果该对象不存在,那么创建一个具有所需功能的对象。 这样简化开发并提高复用。 
- 
类(class)和对象(object)是面向对象的核心概念。 
类是对现实世界事物的描述,是抽象的、概念上的定义
对象是实际存在的该类事物的一个个体,因而也称实例(instance)。
- 
“万事万物皆对象” 
面向对象的三大特征
- 
封装 (Encapsulation) 
- 
继承 (Inheritance) 
- 
多态 (Polymorphism) 
java语言的基本元素:类和对象
类
类 (class) 描述某种事物.
类 : 是一个数据类型, 和int, long是同级别的东西.
类是模板, 创建对象时就需要这个类模板.
类的成员之一:属 性
属性 : 也称为成员变量 描述事物的特征, 数据
类的成员之二:方 法
方法 : 也称为成员方法 描述事物的行为, 动作. 功能
句式:修饰符 返回值类型 方法名(形参列表) {}
对象方法 : 描述事物的行为动作, 也称为实例方法.
类模板 :
包括属性定义
创建对象时要使用, 依据它的所有属性的定义信息开空间 在GC区.
属性定义 : 包括修饰符, 数据类型, 属性名
包括所有方法代码
在调用方法时,会把方压入栈中执行.
对象
对象的创建和使用
概念
对象(object) 是类的一个实实在在的存在, 也称为实例(instance)
具体实例
/**
 * 类 (class) 描述某种事物.
 *      属性 : 也称为成员变量 描述事物的特征, 数据
 *      方法 : 也称为成员方法 描述事物的行为, 动作. 功能
 *
 * 对象(object) 是类的一个实实在在的存在, 也称为实例(instance)
 *
 * 类 : 是一个数据类型, 和int, long是同级别的东西.
 *
 * 类是模板, 创建对象时就需要这个类模板.
 *
 * 成员 : 隶属于同一个类的成员, 它们之间的关系是一家人. 成员可以直接互访.
 */
public class Teacher {
    String name; // 对象属性 : 描述事物的特征, 也称为实例变量.
    int age;
    String gender;
    // 修饰符 返回值类型 方法名(形参列表) {}
    // 对象方法 : 描述事物的行为动作, 也称为实例方法.
    public void lesson() {
        System.out.println(name + "老师在上课"); // 成员之间可以直接互访
    }
    public void eat(String something) {
        System.out.println(name + "老师在吃" + something);
    }
    // 描述对象的详细信息, 对象的所有的属性值的拼接的字符串
    public String say() {
        String s = "姓名 : " + name + ", 年龄 : " + age + ", 性别 : " + gender;
        return s;
    }
}
对象的产生
当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。除了基本数据类型之外的变量类型都是引用类型,如上面的Person及前面讲过的数组。
| 成员变量类型 | 初始值 | 
|---|---|
| byte | 0 | 
| short | 0 | 
| int | 0 | 
| long | 0L | 
| float | 0.0F | 
| double | 0.0D | 
| char | ‘\u0000’(表示为空) | 
| boolean | false | 
| 引用类型 | null | 
匿名对象
我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。
- 
如:new Person().shout(); 
使用情况
- 
如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。 
- 
我们经常将匿名对象作为实参传递给一个方法调用。 
public class Person {
    public String name; // 姓名
    public int age; // 年龄
    // 定义构造方法,为属性初始化
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 获取信息的方法
    public void tell() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }
    public static void main(String[] args) {
        new Person("张三", 30).tell(); // 匿名对象
    }
}
程序运行结果为: 姓名:张三,年龄:30
在以上程序的主方法中可以发现,直接使用了“new Person("张三",30)”语句,这实际上就是一个匿名对象,与之前声明的对象不同,此处没有任何栈内存引用它,所以此对象使用一次之后就等待被 GC(垃圾收集机制)回收。
(了解)匿名对象在实际开发中基本都是作为其他类实例化对象的参数传递的,在后面的 Java 应用部分的很多地方都可以发现其用法,而且细心的读者可以发现,匿名对象实际上就是个堆内存空间,对象不管是匿名的还是非匿名的,都必须在开辟堆空间之后才可以使用。
补:变量的分类:成员变量与局部变量
- 
在方法体外,类体内声明的变量称为成员变量。 
- 
在方法体内部声明的变量称为局部变量。 
成员变量(属性)和局部变量的区别?
成员变量:
- 
成员变量定义在类中,在整个类中都可以被访问。 
- 
成员变量分为类成员变量和实例成员变量,实例变量存在于对象所在的堆内存中。 
- 
成员变量有默认初始化值。 
- 
成员变量的权限修饰符可以根据需要,选择任意一个 
局部变量:
- 
局部变量只定义在局部范围内,如:方法内,代码块内等。 
- 
局部变量存在于栈内存中。 
- 
作用的范围结束,变量空间会自动释放。 
- 
局部变量没有默认初始化值,每次必须显式初始化。 
- 
局部变量声明时不指定权限修饰符 
面向对象特征之一:封装和隐藏
属性可以私有化, 用private修饰, 属性一旦私有化, 就意味着它只能在本类中访问
封装
成员私有化, 强行让使用者通过方法间接使用, 在方法中加上逻辑判断, 保护属性数据.
封装性 :
1) 属性的封装, 私有化, 保护数据
2) 功能的封装, 该对象自己做的事情, 不要向外推, 当仁不让
不该我做事情, 绝不多管闲事.
目的
Java中通过将数据声明为私有的(private),再提供公共的(public)方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:
1)隐藏一个类中不需要对外提供的实现细节;
2)使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;
3)便于修改,增强代码的可维护性;
set方法
给属性赋值使用的方法叫set方法, setter, 有参无返回
public void setAge(int age) { // 在set方法中可以对参数中的值的合法性进行判断
        if (age < 0 || age > 130) { // 如果数据非法
            return; // 提前弹栈
        }
        this.age = age;
get方法
获取属性值的方法get方法, getter, 无参有返回
 public int getAge() {
        return age;
    }
类的成员之三:构造器(构造方法)
概念
- 
构造器(constructor) 也称为构造方法, 是一个特殊的方法, 特殊在是在对象创建时进行初始化工作的. 
- 
它最终的方法名是public void <init>(...) {} 
构造器特点
- 
方法名和类名一致(首字母大写的方法名) 
- 
不能声明返回值类型, 甚至连void也不可以有 
- 
不能被一些关键字修饰, static, final, abstract.... 
- 
只能在创建对象时调用仅有一次, 不可以像普通方法一样随意调用 
缺省构造器
如果在类中没有提供任何构造器时, 编译器会自动添加一个缺省的构造器
缺省构造器的特点 :
- 
修饰符和类一致 
- 
无参 
- 
无语句 
如果在类中没有提供任何构造器时, 编译器会自动添加一个无参的构造器
如果在类中提供了构造器时, 编译器就不会自动添加缺省的无参构造器
无参构造器优点、缺点
优点:创建对象简单
缺点:对象的数据千人一面,没有个性,它是最重要的构造器
缺省构造器注意事项
- 
javabean规范要求的. 
- 
子类构造器中默认总是会调用父类无参. 
- 
反序列化或反射时方便 
构造器重载注意事项
- 
构造器也可以重载. 只要参数列表不同即可. 
- 
构造方法的连环调用特殊, 用this(...)完成 
- 
重载的构造器中必须要有一个构造器是一定没有this(...)的, 否则会形成无限递归. 
- 
this(...)在构造器中必须是第一行. 效果就是 对于构造器的连环调用 一定是先于 本构造器执行. 
构造器注意事项
- 
Java语言中,每个类都至少有一个构造器 
- 
默认构造器的修饰符与所属类的修饰符一致 
- 
一旦显式定义了构造器,则系统不再提供默认构造器 
- 
一个类可以创建多个重载的构造器 
- 
父类的构造器不可被子类继承 
封装和构造器实例
public class Teacher {
    // 属性即使没有显式赋值, 它也有一个隐式的缺省值 0
    private String name = "某老师"; // 属性的显式赋值
    private int age = 10;
    private String gender;
    // 无参构造器, 优点:创建对象简单, 缺点:对象的数据千人一面. 没有个性.
    // 它是最重要的构造器. 1) javabean规范要求的. 2) 子类构造器中默认总是会调用父类无参. 3) 反序列化或反射时方便.
    public Teacher() { // 这个才是构造器, 它最终的方法名是public void <init>(...) {}
        /*
        this.name = "佟刚"; // 为对象的属性直接赋值
        this.age = 40;
        this.gender = "男";
        */
        this("佟刚", 40, "男"); // 连环调用
        System.out.println("Teacher()..."); // 特有代码
    }
    // 全参构造器, 优点 : 功能强大,创建对象的数据可以一步到位, 缺点 : 调用复杂
    public Teacher(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        System.out.println("Teacher(String, int, String)..."); //3
    }
    public void Teacher() { // 不是构造器, 是普通方法
        System.out.println("void Teacher()...");
    }
    // 在本类中添加新的方法, 用于间接的访问本类中的私有属性
    // 给属性赋值使用的方法叫set方法, setter, 有参无返回
    public void setAge(int age) { // 在set方法中可以对参数中的值的合法性进行判断
        if (age < 0 || age > 130) { // 如果数据非法
            return; // 提前弹栈
        }
        this.age = age;
    }
    // 获取属性值的方法get方法, getter, 无参有返回
    public int getAge() {
        return age;
    }
    // 有参无返回
    public void setName(String name) {
        // name = name; // 就近原则, 就会导致左面的name仍然 还是 参数name, 是局部变量,在栈中
        this.name = name; // this表示的对象, this.name就是对象的name属性空间, 在堆内存中.
    }
    // 无参有返回
    public String getName() {
        return this.name;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public String getGender() {
        return gender;
    }
    public void lesson() {
        System.out.println(name + "老师在上课"); // 成员互访
    }
    public void eat(String something) {
        System.out.println(name + "老师在吃" + something);
    }
     
                     
                    
                