第五天:类与对象、封装、构造方法

一.面向对象思想

(一)面向对象的概念:

Java语言是一种\color{red}{面向对象}的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的\color{red}{属性}\color{red}{行为}。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。 它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。

  • 面向过程:当需要实现一个功能的时候,每一个 具体的步骤都要亲力亲为,详细处理每一个细节。
  • 面向对象:当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有 该功能的人,来帮我做事儿。

举例:洗衣服

  • 面向过程:把衣服脱下来-->找一个盆-->放点洗衣粉-->加点水-> 浸泡10分钟-->揉一揉-->清洗衣服-->拧干-->晾起来
  • 面向对象:把衣服脱下来-->打开全自动洗衣机-->扔衣服-->按钮-->晾起来

(二)面向对象的特点:

面向对象的语言中,包含了三大基本特征,即封装、继承和多态。

二.类与对象

(一)什么是类

类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。

  • 属性:就是该事物的状态信息。
  • 行为:就是该事物能够做什么。

举例:小猫。

  • 属性:名字、体重、年龄、颜色。
  • 行为:走、跑、叫。

(二)什么是对象

对象:是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为。

举例:小猫。

  • 属性:汤姆、5kg、2、白色。
  • 行为:溜墙根走、蹦跶跑、喵喵叫。

(三)类与对象的关系

  • 类是对一类事物的描述,是抽象的。
  • 对象是一类事物的实例,是具体的。
  • 类是对象的模板,对象是类的实体。
image.png

(四)类的定义

1.事物与类的对比

现实世界的一类事物:

  • 属性:事物的状态信息。
  • 行为:事物能够做什么。

Java中用类(class)描述事物也是如此:

  • 成员变量:对应事物的属性 。
  • 成员方法:对应事物的行为。
2.类的定义格式:
public class ClassName {
//成员变量
//成员方法
}
  • 定义类:就是定义类的成员,包括成员变量和成员方法。
  • 成员变量:和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外。
  • 成员方法:和以前定义方法几乎是一样的。只不过把static去掉。

代码:

public class Student {
    // 成员变量
    String name; // 姓名
    int age; // 年龄

    // 成员方法
    public void study() {
        // 学习的方法
        System.out.println("好好学习,天天向上!");
    }

    public void eat() {
        System.out.println("吃饭饭~");
    }
}

(五)对象的使用

1.对象的使用格式

通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用。
(1) 导包:也就是指出需要使用的类,在什么位置。
import 包名称.类名称;
import cn.cxy.demo04.Student ;
对于和当前类属于同-一个包的情况,可以省略导包语句不写。
(2) 创建:
类名称 对象名= new 类名称();
Student stu = new Student();
(3) 使用(分为两种情况):

  • 使用成员变量:对象名.成员变量名
  • 使用成员方法:对象名.成员方法名(参数)

代码:

public class StudentTest1 {
    public static void main(String[] args) {
        // 创建对象格式:类名 对象名 = new 类名();
        Student student = new Student();
        System.out.println("student:" + student);

        // 直接输出成员变量值
        System.out.println("姓名:" + student.name); // null
        System.out.println("年龄:" + student.age); // 0

        // 给成员变量赋值
        student.name = "赵丽颖";
        student.age = 20;

        // 再次输出成员变量的值
        System.out.println("姓名:" + student.name); // 赵丽颖
        System.out.println("年龄:" + student.age); // 20

        // 调用成员变量方法
        student.study(); // 好好学习,天天向上!
        student.eat();  // 吃饭饭~
    }
}

运行结果:


image.png
2.成员变量的默认值

如果成员变量没有进行赋值,那么将会有一个默认值,规则和数组一样。

                数据类型                       默认值
基本类型         整数(byte,short,int,long) 0
                浮点数(float,double)        0.0
                字符(char)                  '\u0000'
                布尔(boolean)               false
引用类型         数组,类,接口                 null

三.对象内存图

(一)只有一个对象的内存图

代码:
Phone.java

public class Phone {
    // 成员变量
    String brand; // 品牌
    double price; //价格
    String color; // 颜色

    // 成员方法
    public void call(String who) {
        System.out.println("给" + who + "打电话");
    }

    public void sendMessage() {
        System.out.println("群发短信");
    }
}

PhoneTest1.java

public class PhoneTest1 {
    public static void main(String[] args) {
        // 根据Phone类,创建一个名为one的对象
        // 格式:类名称 对象名 = new 类名称();

        Phone one = new Phone();
        System.out.println(one.brand); // null
        System.out.println(one.price); // 0.0
        System.out.println(one.color); // null
        System.out.println("==============");

        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "黑色";
        System.out.println(one.brand); // 苹果
        System.out.println(one.price); // 8388.0
        System.out.println(one.color); // 黑色
        System.out.println("==============");

        one.call("乔布斯"); // 给乔布斯打电话
        one.sendMessage(); // 群发短信
    }
}

运行结果:

image.png
内存图
只有一个对象的内存图.png

(二)两个对象使用同一个方法的内存图

代码:
PhoneTest2.java

public class PhoneTest2 {
    public static void main(String[] args) {
        // 根据Phone类,创建一个名为one的对象
        // 格式:类名称 对象名 = new 类名称();

        Phone one = new Phone();
        System.out.println(one.brand); // null
        System.out.println(one.price); // 0.0
        System.out.println(one.color); // null
        System.out.println("==============");

        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "黑色";
        System.out.println(one.brand); // 苹果
        System.out.println(one.price); // 8388.0
        System.out.println(one.color); // 黑色
        System.out.println("==============");

        one.call("乔布斯"); // 给乔布斯打电话
        one.sendMessage(); // 群发短信

        System.out.println("============================");

        Phone two = new Phone();
        System.out.println(two.brand); // null
        System.out.println(two.price); // 0.0
        System.out.println(two.color); // null
        System.out.println("==============");

        two.brand = "三星";
        two.price = 5999.0;
        two.color = "蓝色";
        System.out.println(two.brand); // 三星
        System.out.println(two.price); // 5999.0
        System.out.println(two.color); // 蓝色
        System.out.println("==============");

        two.call("欧巴"); // 给欧巴打电话
        two.sendMessage(); // 群发短信
    }
}

运行结果:

image.png
内存图
02-两个对象使用同一个方法的内存图.png

(三)两个引用指向同一个对象的内存图

代码:
PhoneSame.java

public class PhoneSame {
    public static void main(String[] args) {
        // 根据Phone类,创建一个名为one的对象
        // 格式:类名称 对象名 = new 类名称();

        Phone one = new Phone();
        System.out.println(one.brand); // null
        System.out.println(one.price); // 0.0
        System.out.println(one.color); // null
        System.out.println("==============");

        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "黑色";
        System.out.println(one.brand); // 苹果
        System.out.println(one.price); // 8388.0
        System.out.println(one.color); // 黑色
        System.out.println("==============");

        one.call("乔布斯"); // 给乔布斯打电话
        one.sendMessage(); // 群发短信

        System.out.println("============================");

        Phone two = new Phone();
        System.out.println(two.brand); // null
        System.out.println(two.price); // 0.0
        System.out.println(two.color); // null
        System.out.println("==============");

        two.brand = "三星";
        two.price = 5999.0;
        two.color = "蓝色";
        System.out.println(two.brand); // 三星
        System.out.println(two.price); // 5999.0
        System.out.println(two.color); // 蓝色
        System.out.println("==============");

        two.call("欧巴"); // 给欧巴打电话
        two.sendMessage(); // 群发短信
    }
}

运行结果:


image.png
内存图:
两个引用指向同一个对象的内存图.png

(四)使用对象类型作为方法的参数的内存图

  • 当一个对象作为参数,传递到方法当中时,实际上传递进去的是对象的地址值。

PhoneParam.java
代码:

public class PhoneParam {
    public static void main(String[] args) {
        Phone one = new Phone();
        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "土豪金";

        method(one); // 传递进去的参数其实就是地址值
    }

    public static void method(Phone param) {
        System.out.println(param.brand); // 苹果
        System.out.println(param.price); // 8388.0
        System.out.println(param.color); // 土豪金
    }
}

运行结果:

image.png
内存图
使用对象类型作为方法的参数.png

(五)使用对象类型作为方法的返回值的内存图

  • 当使用一个对象类型作为方法的返回值时:返回值其实就是对象的地址值。

PhoneReturn.java
代码:

public class PhoneReturn {
    public static void main(String[] args) {
        Phone two = getPhone();
        System.out.println(two.brand); // 苹果
        System.out.println(two.price); // 8388.0
        System.out.println(two.color); // 玫瑰金
    }

    public static Phone getPhone() {
        Phone one = new Phone();
        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "玫瑰金";
        return one;
    }
}

运行结果:

image.png
内存图
使用对象类型作为方法的返回值.png

四.成员变量和局部变量区别

(一)什么是成员变量和局部变量

变量根据定义位置的不同,我们给变量起了不同的名字。如下图所示:

image.png

(二)成员变量和局部变量区别

1.在类中的位置不同 \color{red}{重点}
  • 成员变量:在方法的外部,直接写在类当中。
  • 局部变量:在方法的内部或者在方法的声明上(形式参数)。
2.作用范围不一样 \color{red}{重点}
  • 成员变量:整个类全都可以通用。
  • 局部变量:只有方法当中才可以使用,出了方法就不能再用。
3.初始化值的不同 \color{red}{重点}
  • 成员变量:有默认值。
  • 局部变量:没有默认值,如果要想使用,必须手动进行赋值。
4.在内存中的位置不同 \color{red}{了解}
  • 成员变量:位于堆内存。
  • 局部变量:位于栈内存。
5.生命周期不同 \color{red}{了解}
  • 成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失。
  • 局部变量:随着方法进栈而诞生,随着方法出栈而消失。

五.封装

(一)封装概述

面向对象编程语言是对客观世界的模拟,客观世界里\color{red}{成员变量}都是隐藏在对象内部的,外界无法\color{red}{直接操作}\color{red}{修改}。封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类\color{red}{随意访问}。要访问该类的数据,必须通过\color{red}{指定的方式}。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。

(二)封装的原则

将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。

(三)封装的步骤

  • 使用 private 关键字来修饰成员变量。
  • 对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。

(四)封装的操作—private关键字

1.private的含义
  • private是一个权限修饰符,代表最小权限。
  • 可以修饰成员变量和成员方法。
  • 被private修饰后的成员变量和成员方法,只在本类中才能访问。
2.private的使用格式

private 数据类型 变量名;
使用 private 修饰成员变量
代码:

public class Student {
    private String name;
    private int age;
}
3.间接访问private成员变量

间接访问private成员变量,就是定义一对儿Getter/Setter方法
必须叫setXxx或者是getXxx

命名规则:

  • 对于Getter来说,不能有参数,返回值类型和成员变量对应。
  • 对于Setter来说,不能有返回值,参数类型和成员变量对应。

对于基本类型当中的boolean值,Getter方法一定要写成isXxx的形式,而setXxx规则不变。

代码:
Student2.java

package cn.cxy.demo04;

public class Student2 {
    private String name; //姓名
    private int age; //年龄
    private boolean male; //是不是男性

    public String getName() {
        return name;
    }

    public void setName(String str) {
        name = str;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int num) {
        age = num;
    }

    public boolean isMale() {
        return male;
    }

    public void setMale(boolean b) {
        male = b;
    }
}

StudentTest2.java

public class StudentTest2 {
    public static void main(String[] args) {
        Student2 student = new Student2();

        student.setName("鹿晗");
        student.setAge(20);
        student.setMale(true);

        System.out.println("姓名: " + student.getName());
        System.out.println("年龄: " + student.getAge());
        System.out.println("是不是男性: " + student.isMale());

    }
}

运行结果:

image.png

(五)封装的两点优化

1.this关键字

(1) 为什么要使用this关键字
我们发现 setXxx 方法中的形参名字并不符合见名知意的规定,那么如果修改与成员变量名一致,是否就见名知意了呢?
代码:
Person.java

public class Person {
    String name; // 我自己的名字

    // 参数who是对方的名字
    // 成员变量name是自己的名字
    public void sayHello(String name) {
        // 错误写法,成员变量被隐藏
        System.out.println(name + ",你好.我是" + name);
    }
}

PersonTest.java

public class PersonTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "王健林";
        person.sayHello("王思聪");
    }
}

运行结果:

image.png

当方法的局部变量和类的成员变量重名的时候,根据“就近原则”,优先使用局部变量。

由于形参变量名与成员变量名重名,导致成员变量名被隐藏,方法中的变量名,无法访问到成员变量,从而赋值失败。所以,我们只能使用this关键字,来解决这个重名问题。

(2) this的含义
this代表所在类的当前对象的引用(地址值),即对象自己的引用

方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。

(3) this使用格式:
this.成员变量名;
使用 this 修饰方法中的变量,解决成员变量被隐藏的问题。
代码:
Person.java

public class Person {
    String name; // 我自己的名字

    // 参数who是对方的名字
    // 成员变量name是自己的名字
    public void sayHello(String name) {
        // 错误写法,成员变量被隐藏
        System.out.println(name + ",你好.我是" + this.name);
        System.out.println(this);
    }

PersonTest.java

public class PersonTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "王健林";
        person.sayHello("王思聪");
        System.out.println(person);
    }
}

运行结果:

image.png
2.构造方法

当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。

小贴士: 无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法,一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。

(1) 构造方法的定义格式

修饰符 构造方法名(参数列表){
// 方法体
}

(2) 无参构造方法与有参构造方法
代码:
Student3.java

public class Student3 {
    // 成员变量
    private String name;
    private int age;

    // 无参数的构造方法
    public Student3() {
        System.out.println("无参构造方法执行啦!");
    }

    // 全参数的构造方法
    public Student3(String name, int age) {
        System.out.println("全参构造方法执行啦!");
        this.name = name;
        this.age = age;
    }

    // Getter Setter
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

StudentTest3.java

public class StudentTest3 {
    public static void main(String[] args) {
        Student3 student1 = new Student3(); // 无参构造
        System.out.println("================");

        Student3 student2 = new Student3("赵丽颖", 20); // 全参构造
        System.out.println("姓名: " + student2.getName() + ",年龄: " + student2.getAge());
    }
}

运行结果:

image.png

注意事项:

  • 构造方法的名称必须和所在的类名称完全一样,就连大小写也要一样。
  • 构造方法不要写返回值类型,连void都不写。
  • 构造方法不能return一个具体的返回值。
  • 如果你不提供构造方法,系统会给出无参数构造方法。
  • 如果你提供了构造方法,系统将不再提供无参数构造方法。
  • 构造方法也是可以进行重载的。

六.标准类(JavaBean)

(一)什么是标准类

JavaBean 是 Java语言编写类的一种标准规范。符合 JavaBean 的类,要求类必须是具体的和公共的,并且具有无参数的构造方法,提供用来操作成员变量的 set 和 get 方法。

(二)标准类的组成

一个标准的类通常要拥有下面四个组成部分:

  • 所有的成员变量都要使用private关键字修饰
  • 为每一个成员变量编写一对儿Getter/Setter方法
  • 编写一个无参数的构造方法
  • 编写一个全参数的构造方法

代码:
StudentStandardClass.java

public class StudentStandardClass {
    private String name; // 姓名
    private int age; // 年龄

    // 无参构造方法
    public StudentStandardClass() {
    }

    // 全参构造方法
    public StudentStandardClass(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 姓名的访问器
    public String getName() {
        return name;
    }

    // 姓名的修改器
    public void setName(String name) {
        this.name = name;
    }

    // 年龄的访问器
    public int getAge() {
        return age;
    }

    // 年龄的修改器
    public void setAge(int age) {
        this.age = age;
    }
}

StudentStandardTest.java

public class StudentStandardTest {
    public static void main(String[] args) {
        StudentStandardClass student1 = new StudentStandardClass();
        student1.setName("迪丽热巴");
        student1.setAge(20);
        System.out.println("姓名: " + student1.getName() + ", 年龄: " + student1.getAge());
        System.out.println("======================");

        StudentStandardClass student2 = new StudentStandardClass("古力娜扎",21);
        System.out.println("姓名: " + student2.getName() + ", 年龄: " + student2.getAge());
    }
}

运行结果:

image.png

七.匿名对象

(一)概念

创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量。虽然是创建对象的简化写法,但是应用场景非常有限。

  • 匿名对象 :没有变量名的对象。
  • 注意事项,匿名对象只能使用唯一的一次,下次再用不得不再创建一个新对象。
  • 使用建议:如果确定有一个对象只需要使用唯一的一 次,就可以用匿名对象。

格式:new 类名(参数列表);
举例:new Scanner(System.in);

(二)应用场景

1. 匿名对象直接调用方法

创建匿名对象直接调用方法,没有变量名。
例:new Scanner(System.in).nextInt();
代码:

public class Anoymous {
    public static void main(String[] args) {
        // 匿名对象
        System.out.println(new Scanner(System.in).nextInt());
    }
}

运行结果:

输入10:
image.png

一旦调用两次方法,就是创建了两个对象,造成浪费。

new Scanner(System.in).nextInt();
new Scanner(System.in).nextInt();
2.作为方法的参数和返回值

(1) 作为参数:

代码:

    public static void main(String[] args) {
        // 普通方式
        // Scanner sc = new Scanner(System.in);
        // input(sc);

        //匿名对象作为方法接收的参数
        input(new Scanner(System.in));
    }

    public static void input(Scanner sc) {
        System.out.println(sc.nextInt());
    }
}

运行结果:

输入10:
image.png

(2) 作为返回值:
代码:

public class AnonymousTest2 {
    public static void main(String[] args) {
        Scanner sc = getScanner();
        System.out.println(sc.nextInt());
    }

    public static Scanner getScanner() {
        //普通方式
        //Scanner sc = new Scanner(System.in);
        //return sc;

        //匿名对象作为方法返回值
        return new Scanner(System.in);
    }

}

运行结果:

输入10:
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容