面向对象

ryluo 2020-09-11 11:20:34

面向对象

类与对象的关系

用Java语言对现实生活中的事物进行描述,通过类的形式体现,而对于事物的描述通常只关注两个方面,一个是属性,一个是行为。

类只是对事物的描述,而对象是该类事物实实在在的个体(在Java中是通过new创建的,并且是创建在堆中)。

下面简单描述一下小汽车:
1. 属性:
    轮胎数
    颜色
    ...
2. 行为:
    运行
    ...

定义类其实就是在定义类中的成员
成员:成员变量->属性  成员函数->行为
package luoruyi.class_demo;

class Car{
    int num;
    String color;

    void run() {
        System.out.println(num+"..."+color);
    }
}

public class CarDemo {
    public static void main(String[] args) {
        // c是一个类类型的变量指向了该类的对象
        Car c = new Car();

        c.num = 4;
        c.color = "red";

        c.run();
    }
}

成员变量与局部变量

  1. 成员变量定义在类中,整个类中都可以访问;局部变量定义在函数,语句,局部代码块中,只在所属的区域有效
  2. 成员变量存在于堆内存的对象中;局部变量存在于栈内存的方法中
  3. 成员变量随着对象的创建而存在,随着对象的消失而消失;局部变量随着所属区域的执行而存在,随着所属区域的结束而释放
  4. 成员变量都有默认初始化值;局部变量没有默认初始化值(局部变量不初始化无法使用)。

基本数据类型与引用数据类型的参数传递

基本数据类型参数传递,栈中的内存图如下

image-20200910162937658

package com;

public class Demo01 {
    public static void main(String[] args) {
        int x = 3;
        show(x);
        System.out.println(x);
    }

    public static void show(int x){
        x = 4;
    }
}

引用数据类型参数传递,栈和堆的内存图

image-20200910163000799

public class Demo01 {
    int x = 3;
    public static void main(String[] args) {
        Demo01 d = new Demo01();
        d.x = 9;
        show(d);
        System.out.println(x);
    }

    public static void show(Demo01 d){
        d.x = 4;
    }
}


封装

封装指的是隐藏对象的属性和实现细节,仅对外提供公共访问方式。

好处:

  1. 将变化隔离
  2. 便于使用
  3. 提高重用性
  4. 提高安全性

封装原则:

  1. 将不需要对外提供的内容都隐藏起来
  2. 把属性都隐藏,提供公共方法对其访问
package com;

class Person{
    // private: 是一个权限修饰符,用于修饰成员,私有的内容只在本类中有效
    // 私有仅仅是封装的一种体现而已
    private int age;

    public void setAge(int a) {
        if(a > 0 && a < 130)
            age = a;
        else
            System.out.println("错误的输入");
    }

    public int getAge() {
        return age;
    }

    void speak() {
        System.out.println("age="+age);
    }
}

public class PersonDemo {
    public static void main(String[] args) {
        Person p = new Person();
        p.setAge(10);
        p.speak();
    }
}

构造函数

特点:

  1. 函数与类名相同
  2. 不用定义返回值类型
  3. 没有具体的返回值

作用:

  1. 给对象进行初始化

注意:

  1. 默认构造函数的特点
  2. 多个构造函数是以继承的形式存在的
package com;

class Person {
    private String name;
    private int age;

    // 定义一个Person类的构造函数,并且参数为空,可以给对象进行初始化
    // 构造函数:构建创造对象时调用的函数。
    Person() {
        System.out.println("person run");
    }

    public void speak() {
        System.out.println("name="+age);
    }
}

public class ConsDemo {
    public static void main(String[] args) {
        Person p = new Person();
    }
}

创建对象都必须要通过构造函数初始化,一个类中,如果没有定义过构造函数,该类中会有一个默认的无参数的构造函数,如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。


一般函数与构造函数有什么区别:


什么时候定义构造函数呢?

在描述事物时,该事物一存在就具备的一些内容,这些内容都定义在构造函数中。


构造函数的重载

重载: 参数个数与参数类型不同,

注意: 相同的参数列表必须参数的顺序也相同

package com;

class Person {
    private String name;
    private int age;

    // 定义一个Person类的构造函数,并且参数为空,可以给对象进行初始化
    // 构造函数:构建创造对象时调用的函数。
    Person() {
        name = "baby";
        age = 1;
        System.out.println("run Person()");
    }

    // 重载函数
    Person(String n) {
        name = n;
        System.out.println("run Person(String n)");
    }

    Person(String n, int a) {
        name = n;
        System.out.println("run Person(String n, int a)");
    }
    // 参数列表中参数的顺序不同也是重载
    Person(int a, String n) {
        name = n;
        System.out.println("run Person(int a, String n)");
    }
    public void speak() {
        System.out.println(name+":"+age);
    }
}

public class ConsDemo {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.speak();

        Person p2 = new Person("旺财");
        p2.speak();

        Person p3 = new Person("小强",10);
        p3.speak();

        Person p4 = new Person(10,"小红");
        p4.speak();
    }
}


构造函数内存图解

image-20200910161828500


一些细节

构造函数中初始化了属性,还需要定义set方法吗?

需要,构造函数只能运行一次,属性的set方法可以运行多次

构造函数一定没有返回值嘛?

一定,即使在类中出现了有返回值的与类名相同的函数,那不能说明构造函数可以有返回值,因为那个根本就不叫构造函数,只不过是一个普通的函数,名字与类名相同而已。

构造函数中有return语句嘛?

有,用来结束函数的, 但是很少见。


this关键字

当局部变量与成员变量重名的时候,可以使用关键字this来区分。

this:就是所在函数所属对象的引用,简单说,哪个对象调用了this所在的函数,this就代表哪个对象

image-20200910164638533

image-20200910164822552

image-20200910165111089

package com;

class Person {
    private String name;
    private int age;

    Person() {
        this.name = "baby";
        this.age = 1;
        System.out.println("run Person()");
    }
    Person(String name) {
        this.name = name;
        System.out.println("run Person(String n)");
    }
    Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("run Person(String n, int a)");
    }
    public void speak() {
        System.out.println(this.name+":"+this.age);
    }
}

public class ThisDemo {
    public static void main(String[] args) {
        Person p = new Person("旺财");
        p.speak();

        Person p1 = new Person("小强");
        p1.speak();
    }
}


this也可以用于构造函数中调用其他的构造函数,但是只能定义在构造函数的第一行,因为初始化动作要先执行

image-20200910170020351

image-20200910170046047

package com;

class Person {
    private String name;
    private int age;

    Person() {
        this.name = "baby";
        this.age = 1;
        System.out.println("run Person()");
    }
    Person(String name) {
        this();  // 构造函数之间的调用,分布初始化
        this.name = name;
        System.out.println("run Person(String n)");
    }
    Person(String name, int age) {
        this(name); // 构造函数之间的调用,分布初始化
        this.age = age;
        System.out.println("run Person(String n, int a)");
    }
    public void speak() {
        System.out.println(this.name+":"+this.age);
    }
}

public class ThisDemo {
    public static void main(String[] args) {
        Person p = new Person("旺财", 10);
        p.speak();

        Person p1 = new Person("小强", 20);
        p1.speak();
    }
}


只要方法当中用到了本类的对象,就用this来表示对象。

package com;

class Person {
    private String name;
    private int age;

    Person() {
        this.name = "baby";
        this.age = 1;
        System.out.println("run Person()");
    }
    Person(String name) {
        this();
        this.name = name;
        System.out.println("run Person(String n)");
    }
    Person(String name, int age) {
        this(name); // 构造函数之间的调用,分布初始化
        this.age = age;
        System.out.println("run Person(String n, int a)");
    }
    public void speak() {
        System.out.println(this.name+":"+this.age);
    }
    /*
    判断两个人是否是同龄人
    */
    public boolean compare(Person p){
        return this.age == p.age;
    }
}

public class ThisDemo {
    public static void main(String[] args) {
        Person p = new Person("旺财", 10);
        p.speak();

        Person p1 = new Person("小强", 20);
        p1.speak();

        System.out.println(p1.compare(p));
    }
}


static关键字

static修饰的方法对象之间是共享的,所有的对象都使用一份,并且是在创建对象之前这些共享的数据就有了