Java零基础入门笔记7-Java面向对象

1、概述

  • 相较于早年面向过程的编程方式,基于面向对象设计思想的开发在程序的稳定性可扩展性可重用性方面都有着无可比拟的优势。
  • 面向对象的三大特征:继承封装多态

2、类和对象

2.1、概念理解

  • 对象:正所谓万物皆对象,现实存在的客观事物都是对象。
  • 面向对象:所谓面向对象,从字面上理解即与对象面对面、关注对象。而从计算机的角度而言,面向对象即关注现实存在的事物的各方面的信息,从对象的角度出发,根据事物的特征进行相关的程序设计
  • 举个例子:比如我们要去宠物店买一只猫,店员会问你想要一只什么样的猫呢?于是你就跟店员说想要一只小一点的、可爱的并且不容易掉毛的宠物猫。于是店员根据你的描述带你去看了符合你描述特征的猫。那么,我们去宠物店买猫的过程,其实就可以理解为一个面向对象的过程。刚开始呢我描述了一个我期望当中的宠物猫的模型(它是虚拟的,但涵盖了我所想要的宠物猫的特征),后来店员根据我的描述带我去看了猫(满足要求的实物)。这便引出了下面的概念。
  • 类是模子,确定对象将会拥有的特征(属性)和行为(方法)。而对象是类的实例化表现
  • 类只是个虚拟化的模子,而对象是真实存在的。
  • 由于在计算机当中所有的信息都是数据,所以可以理解为:类是对象的类型,对象是特定类型的数据
  • 所谓属性就是对象具有的各种静态特征(对象有什么?),而方法对象具有的各种动态行为(对象能做什么?)。
  • 在开发过程中,我们会先定义类,然后根据类去实例化对象,然后完成相应的程序逻辑。

2.2、创建类及实例化对象

回顾:包名的推荐命名规范:
1. 英文字母小写;
2. 域名的倒序;
3. 推荐的命名方式为域名的倒序+模块+功能(这一部分跟动物相关,所以后面可以加上animal,例如com.xxx.animal,具体到实际开发中可能会有特定的命名规则)。

  • 1.新建一个名为ObjectProj的Java项目,新建一个包,包名可以参考上面的讲述进行命名,然后在包中新建一个名为Cat的类,代码如下所示。
/**
 * 宠物猫类
 * 
 * @author chaixingsi
 *
 */
public class Cat {
    // 成员属性:昵称、年龄、体重、品种
    String name;
    int month;
    double weight;
    String species;

    // 成员方法:跑动、吃东西
    public void run() {
        System.out.println("小猫快跑!");
    }

    // run的重载方法
    public void run(String name) {
        System.out.println("名叫" + name + "的小猫快跑!");
    }

    public void eat() {
        System.out.println("小猫吃鱼!");
    }
}
  • 2.再新建一个名为CatTest的类,在主方法中去实例化对象。
public class CatTest {
    public static void main(String[] args) {
        // 实例化对象
        Cat cat = new Cat();
        // 测试:调用方法
        cat.eat();
        cat.run();
        // 输出属性的默认值(在没有赋值的情况下)
        System.out.println("年龄:" + cat.month);// 默认值为0
        System.out.println("昵称:" + cat.name);// 默认值为null
        System.out.println("体重:" + cat.weight);// 默认值为0.0
        // 为属性赋值
        cat.name = "旺旺";
        cat.month = 3;
        cat.species = "中华田园猫";
        cat.weight = 500;
        System.out.println("昵称:" + cat.name + ",年龄:" + cat.month + ",体重:" + cat.weight + ",品种:" + cat.species);
        // 方法重载
        cat.run(cat.name);
    }
}
  • 3.运行代码,结果如下。
    这里写图片描述

3、单一职责原则

首先思考一个问题,我们之前写的代码都是在一个类里面就写完了,这里我们还分成了两个类来写,为什么要这么做呢?要回答这个问题,就要提到单一职责原则了。

  • 所谓单一职责原则(SRP:Single Responsibility Principle),也称之为单一功能原则,它是面向对象设计当中的的一个重要原则,在这个原则中,建议我们:一个类应该有且只有一个引起职责(功能)变化的原因。简单来说就是一个类最好只有一个功能。
  • 在软件系统中,如果在一个类(大到模块,小到方法)当中承担的职责(功能)越多,那么就意味着它的交融和耦合性就越高(相当于把这些职责耦合在一起),则被复用的可能性就越低;而于此同时,由于耦合性比较高,当类当中其中一个职责(功能)发生变化时,就有可能会影响同类当中其他职责(功能)的运作,进而影响整个程序的运行。(就跟我们一边走路(或开车)一边玩手机一样,容易出事是一样的道理!
  • 在程序开发中,建议把不同职责(功能)放在不同的类当中,当一个职责发生变化时,对其他参与者的影响就会小很多,并且该类的复用性也会大大提升。
  • 请看以下场景:T负责两个不同的职责:职责P1和职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。也就是说P1和P2被耦合在一起。解决办法:遵守单一职责原则,将不同的职责封装到不同类或模块中。如分别建立两个类T1和T2,使T1完成职责P1功能,T2完成职责P2功能。这样修改T1时,不会使职责P2发生故障风险;同理,修改T2时,也不会使职责P1发生故障风险。
  • 像上面的代码,我们将跟猫相关的属性和方法封装到Cat类当中,而把跟测试相关的内容放到CatTest类当中,这就是一种职责单一的表现。
  • 关于设计模式的更多内容请参见csdn专栏:设计模式

4、new关键字

  • 1.实例化对象的过程可以分为两部分:
    • 声明对象:Cat cat
      • 声明对象是在内存的空间里开辟了一块儿区域取名叫cat,而此时它还不是一个真正的对象(即此时不能像真正的对象那样使用它),此时cat的空间里是空的(null),如下图所示。
      • 这里写图片描述
    • 实例化对象:new Cat();
      • 而实例化对象时,是在内存的空间里开辟了一块空间,完成了对象相关信息的初始化操作,如下图所示。
      • 这里写图片描述
  • 从上面可以看到,声明对象和实例化对象这两个步骤是在内存的不同区域内完成的。声明是在栈当中,而实例化是在堆里面。那这两个不同的空间是如何关联起来呢?看代码Cat cat=new Cat();这就是通过赋值符号将堆当中的内存地址存到了栈当中(在栈当中存放着堆的地址引用),从而将声明的对象指向实例化的具体的空间。
  • 这里写图片描述
  • 因此new关键字作用是在内存的当中开辟了一块实例空间(注意这里的)。
  • 2.假设:我们现在创建另外一只猫,Cat cat2=new Cat();,由于都是通过new关键字来实例化的,因此catcat2指向的是内存当中两块儿不同的空间,即便cat2的属性信息和cat一样。此时修改cat2的信息,cat的信息是不会受到影响的。
    这里写图片描述
  • 3.那对象实例化只有new一种吗?答案是否定的。比如cat2对象是通过Cat cat2=cat;来实例化的。即在栈当中将cat存储的内存地址赋值给cat2,使两个对象指向内存当中的同一块儿区域(即都可以对这块区域进行操作(修改属性等))。此时修改任何一方的信息,另外一方都会受到影响(代码演示略)。
    这里写图片描述

5、构造方法

  • 说完new关键字,下面再来说一下new的好搭档构造方法
  • 构造方法又称为构造函数,也叫构造器。我们经常会通过构造方法来完成对象初始化的相关设置
  • 之所以说构造方法和new是好搭档,是因为它在类外被调用的时候,必须配合new关键字。是不能被对象单独调用的。
  • 构造方法的语法结构:
    1. 构造方法与类同名且没有返回值
    2. 构造方法的前面可以加上适当的访问修饰符
    3. 在方法名后面可以添加参数也可以不添加任何参数
    4. 注意!!!构造方法只能在对象实例化的时候调用,因此和new是个好搭档。
public 构造方法名() {
    //初始化代码
}
  • 像之前的代码,我们在Cat类当中定义了run()eat()方法,而并没有定义Cat()这个构造方法,那在实例化对象时为什么可以直接使用呢(如代码Cat cat=new Cat();)?这是因为,当没有指定构造方法时,系统会自动添加无参的构造方法。而当有指定构造方法,并且无论是带参构造方法还是无参构造方法(一个类中可以有多个构造方法),系统将不再自动添加无参构造方法了。下面进行代码演示。

5.1、无参构造方法

  • 1.在Cat类当中手动添加一个无参构造方法,代码如下。
public Cat() {
    System.out.println("我是无参构造方法!");
}
  • 2.修改CatTest代码如下:
public class CatTest {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.run();
    }
}
  • 3.运行代码,”小猫快跑”的语句”在我是无参构造方法”之后打印出来,说明在实例化对象的时候会调用构造方法,并且,run方法只能通过对象名.run()来调用(即实例化对象之后调用)。
    这里写图片描述
  • 4.为了更清楚的看到执行的顺序,下面我们通过调试来看一下。
    这里写图片描述
  • 5.若将无参构造修改为一个带参的构造方法,则会如下图所示提示”The constructor Cat() is undefined
    这里写图片描述
  • 6.构造方法改为带参的话,我们实例化时可以调用这个带参的构造方法(如果还想调用无参构造,则再添加一个无参构造方法即可)。
Cat cat=new Cat("旺旺");

5.2、带参构造方法

  • 1.在Cat类当中编写一个带参的构造方法,如下所示。
public Cat(String name,int month,double weight,String species) {
    name=name;
    month=month;
    weight=weight;
    species=species;
}
  • 2.但是会有黄色波浪样式的警告(显示这几条语句没有起作用),如下图所示,我们先忽略这个。
    这里写图片描述
  • 3.修改CatTest代码如下。
public class CatTest {
    public static void main(String[] args) {
        Cat cat = new Cat("旺旺", 5, 600, "英国短毛");
        System.out.println("昵称:" + cat.name + ",年龄:" + cat.month 
                + ",体重:" + cat.weight + ",品种:" + cat.species);
    }
}
  • 4.运行程序,结果如下所示。
    这里写图片描述
  • 5.修改Cat中刚才编写的带参构造方法(this代表了当前对象,通过this可以调用成员的属性,如下代码所示)。
public Cat(String name, int month, double weight, String species) {
    this.name = name;
    this.month = month;
    this.weight = weight;
    this.species = species;
}

或者改为(两种方法均可)

public Cat(String name1, int month1, double weight1, String species1) {
    name = name1;
    month = month1;
    weight = weight1;
    species = species1;
}
  • 6.再次运行代码,结果如下。
    这里写图片描述
  • 7.步骤4中显示的结果表明,我们传递的参数并没有赋值给成员属性(由于传递参数的名字和成员变量的属性名相同,就近原则造成的)。下面我们调试一下代码。
    这里写图片描述

6、this关键字

上面我们在解决问题的时候已经使用了this关键字,那么this有什么样的功能呢?

  • this在类中代表当前对象,可以通过this关键字完成当前对象的成员属性、方法及构造方法的调用。
  • 1.新建一个名为User的类,编写如下代码。
public class User {
    private String name;

    public User() {
        System.out.println("我是无参构造方法");
    }

    public User(String name) {
        // 用于构造函数间的相互调用,而且只能放在构造函数的第一行
        this();// 表示调用本类当中的无参构造方法
        this.name = name;
        this.method();// 这里就等同于user.method,这里也可以不加this
    }

    public void method() {
        System.out.println("我是成员方法");
    }

    public static void main(String[] args) {
        User user = new User("李明");
        user.method();
        System.out.println(user.name);
    }
}
  • 2.运行结果。
    这里写图片描述

猜你喜欢

转载自blog.csdn.net/chaixingsi/article/details/81910616