当前位置:   article > 正文

【程序员养成之路】Java基础篇 4-从面向对象里找对象_面向对象 如何确定对象

面向对象 如何确定对象

以下内容若有误,欢迎私信我或在下方留言,谢谢^_−


面向对象

1.面向对象概述

面向对象是相对于面向过程而言的,所以,理解面向对象,先要理解面向过程是什么。

面向过程(Procedure Oriented)关注的是我该怎么做,是通过分析要解决的问题,并拆分成若干个步骤,然后按照这些步骤依次进行。

比如说我现在想在家里吃面,那就需要依次进行买面、煮面、吃面、洗碗这些步骤,这就是面向过程的思想。

面向对象(Object Oriented,OO)关注的是我该让谁做,是把构成问题的事物按照一定规则划分为多个独立的对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

比如同样是上面的例子,我现在不是在家里了,而是去面馆,面不再需要自己煮,所以买面由面馆的进货员负责,煮面由面馆的厨师负责,洗碗则由面馆的后勤负责,而我只需要负责吃面就可以了,这就是面向对象的思想。

面向对象编程(Procedure Oriented Programming,OOP)的本质:以类的方式组织代码,以对象的组织封装数据。

2.面向对象特性
2.1 封装

(1)封装是面向对象的核心思想,将对象的特性和行为封装起来,不需要让外界知道具体实现细节。比如玩手机,我们并不需要知道手机内部到底是怎么运作的,就可以使用手机。

(2)程序的设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅暴露少量的方法给外部使用。

(3)封装的优点:

  • 良好的封装可以降低耦合度。
  • 保证数据的安全性,不让外界随意更改内部信息。
  • 隐藏代码,实现细节。
  • 增强系统的可维护性。
public class Student {
    // 使用private对变量进行修饰,达到封装的目的
    // 成员变量私有
    private String name;    // 姓名
    private int age;   	    // 年龄
    private char sex;       // 性别

    // 使用public对方法进行修饰,以便外部能够通过使用get、set方法对成员变量进行操作
    // 方法公有
    public String getName(){
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    // 对setAge()方法添加判断条件,外部看不到
    public void setAge(int age) {
        if (age < 120 && age > 0) {
            this.age = age;
        }else {
            age = 0;
        }
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
2.2 继承

(1)继承主要描述的是类与类、接口与接口之间的关系,继承可以在无需重新编写原有类的情况下,对原有类的功能进行扩展,同时也解决了类中存在共同代码的问题。

(2)继承的关键字是extends。Java类只有单继承,但可以多重继承,即一个子类可以有一个父类,该父类可以有自己的父类。

举个栗子:你只有一个亲生爸爸,不能有两个亲生爸爸,但你的爸爸可以有自己的爸爸(也就是你爷爷),而你不能既是你爸爸的儿子又是你爷爷的儿子,也不能是其他男性的亲生儿子。

小提一下:父类也称为超类、基类,子类也称为派生类、拓展类。

/*动物类(父类)*/
public class Animal {
    private String name;
    private double weight;
    public void eat() {
        System.out.println("吃饭ing");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
/*狗类(子类)*/
public class Dog extends Animal {
    public void run() {
        System.out.println("跑步ing");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
/*测试类*/
public class Test {
    public static void main(String[] args) {
        // 创建一个对象
        Dog dog = new Dog();
        // 调用动物类的eat()方法
        dog.eat();
        // 调用狗类的run()方法
        dog.run();
    }
}
/*
	输出结果:
	吃饭ing
	跑步ing
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
2.3 多态

(1)概念

多态指的是在一个类中定义的字段和方法被其他类继承后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现出的多种不同行为特性。

(2)多态的三个前提

  • 存在继承或实现关系
  • 子类重写父类方法
  • 父类引用指向子类对象(如Father father = new Son();)

(3)好处和弊端

  • 好处:提高程序的扩展性。定义方法时,使用父类型作为参数,以后使用的时候,就可以使用不同具体的子类型参与操作。
  • 弊端:不能使用子类特有方法。
/*动物类*/
public class Animal {
    public int age = 2;
    public void eat() {
        System.out.println("吃东西");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
// 子类(狗类)继承父类(动物类)
public class Dog extends Animal {
    public int age = 3;
    public int weight = 20;
    // 重写父类(动物类)方法
    @Override
    public void eat() {
        System.out.println("狗吃狗粮");
    }
    // 子类特有方法
    public void lookHouse() {
        System.out.println("狗狗看家");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
/*测试类*/
public class Test {
    public static void main(String[] args) {
        /*
          向上转型:
          从子类到父类,父类引用指向子类对象
        */
        Animal dog = new Dog();
        // 多态是方法的多态,属性没有多态性,因此下面输出为:2
        System.out.println(dog.age);
        // 子类重写父类方法,执行子类方法,因此下面输出为:狗吃狗粮
        dog.eat();
        // 不能调用子类特有的方法
        dog.lookHouse();    // 报错:Cannot resolve method 'lookHouse' in 'Animal'
        /*
            向下转型:
            从父类到子类,父类引用转为子类对象
        */
        ((Dog)dog).lookHouse();
    }
/*
    运行结果:
    2
    狗吃狗粮
    狗狗看家
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
编译看左边,执行看右边:

父类变量引用指向子类对象时,该变量的成员变量和静态方法和父类保持一致,而对于非静态方法,编译时与父类一致,运行时则与子类一致。

3.类与对象的关系

类是对某一类事物的抽象描述,包括字段(成员变量)和行为(成员方法)

比如人,有身高、体重等属性,也有吃、喝、玩等行为,将这些共同的属性和行为提取出来就可以形成一个类,所以一个类可以简单理解为就是一个模板。

对象用于表示现实中该类事物的个体,是类的实例化、具体化,并且一个类可以对应多个对象

比如猫猫、狗狗、鸡鸡、鸭鸭等就是动物类的对象。当然,猫又分为黑猫、白猫、大猫、小猫,所以,猫也可以单独作为一个类。

类是抽象的,对象是具体的

public class Demo {
    public static void main(String[] args) {
        // 通过new创建一个对象
        Animal animal = new Animal();
        // 给该对象赋值
        animal.name = "小一";
        animal.weight = 20.20;
        // 调用该对象的方法
        animal.eat();   // 小一正在吃饭!现在是20.2kg。
    }
}
// 定义一个动物类
class Animal {
    // 定义两个成员变量
    String name;
    double weight;
    // 定义一个行为(方法)
    public void eat() {
        System.out.println(name + "正在吃饭!现在是" + weight + "kg。");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
4.构造方法

构造方法,也称为构造器,是一种专门用来创建对象的方法,其功能主要是完成对象的初始化,与其他方法一样也可以重载。

public class Person {
    String name;
    int age;

    // 无参构造方法
    public Person() {
    }
    // 有参构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意:

  • 构造方法必须和所在类的名字一模一样
  • 构造方法不需要写返回类型,也不能写void和return语句
  • 如果类中没有编写任何构造方法,编译器会自动创建一个无参构造方法(可以通过IDEA反编译查看.class文件)。
  • 如果类中编写了至少一个构造方法,那编译器就不会自动创建无参构造方法,若需要使用无参构造方法,则需要手动添加(强烈建议)。

拓展1:值传递和引用传递

值传递:指在调用函数时将实际参数复制一份传递给函数,这样在函数中对参数进行修改,将不会影响到实际参数。

/*值传递*/
public class Demo {
    public static void main(String[] args) {
        int num = 2;
        System.out.println(num);    // 输出结果:2
        change(num);	// 并没有改变实际参数
        System.out.println(num);    // 输出结果:2
    }
    // 无返回值
    private static void change(int a) {
        a = 20;
        System.out.println(a);    // 输出结果:20
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

引用传递:指在调用函数时将实际参数的地址直接传递到函数中,这样在函数中对参数所进行的修改,将影响到实际参数。

Java中只有值传递!以下举例是错误的,因为调用change方法(函数)时,是将实参所引用的地址通过值传递给了形参,修改的其实是引用地址所指向的堆内存中的数据,并不是修改地址。

public class Demo {
    public static void main(String[] args) {
        Student student = new Student();
        // 输出结果:null今年0岁!
        System.out.println(student.name + "今年" + student.age + "岁了!");  
        change(student);
        // 输出结果:小一今年18岁!
        System.out.println(student.name + "今年" + student.age + "岁了!");  
    }
    // 无返回值
    private static void change(Student student) {
        student.name = "小一";
        student.age = 18;
    }
}
// 定义Student类
class Student {
    String name;
    int age;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

引用传递举例(C++)

#include <iostream>
using namespace std;

void change(int& num)
{
	num = 10;
}

int main()
{
	int num = 5;
	cout << num << endl;		// 输出结果:5
	change(num);
    cout << num << endl;		// 输出结果:10
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

拓展2:方法重写

方法重写用于继承关系中,即子类重写父类的方法(名称相同,方法体不同)。当子类需要父类的功能,而子类又有自己的特有内容时,就可以通过方法重写实现,这样,子类即继承了父类的功能,又有自己的特有内容。

/*人类*/
public class Person {
    // 父类方法
    public void sleep (String name) {
        System.out.println(name + "在睡觉!");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
/*学生类*/
public class Student extends Person{
    // 重写父类方法
    public void sleep(String name) {
        System.out.println(name + "在玩手机");
        // 继承父类方法
        super.sleep(name);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
/*测试类*/
public class Test {
    public static void main(String[] args) {
        // 创建对象,调用方法
        Person person = new Person();
        person.sleep("小一");
        System.out.println("-------------");
        Student student = new Student();
        student.sleep("小二");
    }
/*
    运行结果:
    小一在睡觉!
    -------------
    小二在玩手机
    小二在睡觉!
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

注意事项:

  • 方法名必须相同
  • 参数列表必须相同
  • 修饰符的权限范围只增不减(public>protected>default>private)
  • 被static、final、private修饰的方法不能被重写

注解:@Override

作用:帮助检查重写方法的方法声明的正确性。


【程序员养成之路】Java基础篇 1-聊聊Java那些事

【程序员养成之路】Java基础篇 2-初学Java必知的基础语法

【程序员养成之路】Java基础篇 3-反手就能写个冒泡排序的数组

【程序员养成之路】Java基础篇 5-从异常机制认识常见bug

【程序员养成之路】Java基础篇 6-啥都能“装”的集合

【程序员养成之路】Java基础篇 7-流进流出的IO流(一)

【程序员养成之路】Java基础篇 8-流进流出的IO流(二)

【程序员养成之路】Java基础篇 9-认识一下类加载器与反射


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/849832
推荐阅读
相关标签
  

闽ICP备14008679号