Java类和对象,封装

面向对象编程

类和对象

什么是对象?

万物皆对象,客观存在的事物都是对象。

例如:一部手机,一条狗,一只猫,一张火车票,一个订单等等。

什么是类?

类是对具有相同特征和行为的事物的抽象。

例如:手机、狗、猫、火车票、订单、帅哥、美女等。

类其实就是类型。类的存在是为了弥补数据类型不足的问题。

什么是对象的属性?

属性是对象具有的各种特征。对象可以有很多个属性,每个属性都有特定的值。

例如:一部手机有品牌、价格、内存、颜色等属性,不同的手机属性值不同,下面是一部小米手机的属性。

什么是对象的行为?

行为就是对象能做什么事情,即对象能执行的操作。

例如:手机可以打电话,发短信等。

类和对象的关系

类是对象的抽象,用于描述对象,是对象的数据类型。

对象是类的具体体现,是类的实例。

例如: 手机是个类,用于描述什么是手机。手机应该具有品牌、价格、颜色等属性,具有打电话、发短信等功能。小米手机是个对象,华为手机是个对象。

再例如:人是一个类,张三是一个具体的人,是对象。电脑是个类,我的电脑是个对象。

注意:类可以细分,细分后的类也是类。细分的类可以认为是子类。

类是Java程序的基本组成单位,任何代码都要依托于类存在。想要做好Java开发必须要掌握类的定义以及对象的使用。

类的定义

类是对对象的抽象,是对对象的描述。它来定义对象都有哪些属性,有哪些行为。

因为对象包含属性和行为,由于类是对对象的描述,所以类也包含属性和行为。

对象的属性,在定义类的时候称为实例变量或成员变量或属性。

对象的行为,在定义类的时候称为实例方法或成员方法。

类本质上就是一种自定义的数据类型,定义出来类型以后,可以用这个类型去创建变量(创建的变量称为对象)。

类的定义格式

使用class关键字来定义类。

public class 类名{
    //实例变量(或成员变量)
    数据类型 变量1;
    数据类型 变量2;
    ...
    //实例方法(或成员方法)
    方法1;//此方法要去掉static关键字
    方法2;//此方法要去掉static关键字
    ...
}

注意事项:

1. 类名使用大驼峰结构命名,即每个单词首字母大写。

2. 实例方法不能用static修饰。

类的定义示例

1. 需求:定义上述的手机类。手机包含品牌、价格,能打电话、发短信。

2. 代码:

public class Phone {
    //实例变量(成员变量)
    String brand;   //品牌
    int price;      //价格
    //实例方法(成员方法)
    public void call() {
        System.out.println("打电话");
    }
    public void sendMessage() {
        System.out.println("发短信");
    }
}

一个文件中能定义多个类。----只要用class去定义就可以。

但只能有一个public修饰的类。被public修饰的类必须和文件名相同。

之所以只能有一个public修饰的类,是因为一个文件只有一个文件名。

大多数情况下一个文件中只定义一个类。

属性的默认值与数组元素的默认值相同:引用类型的默认值是null,基本数据类型默认值是: 整数是0,小数是0.0,布尔值是false,字符值是0。

对象的使用

对象的使用指的是:使用对象的属性 和 使用对象的方法。

要想使用对象,必须先创建对象。

对象的创建

对象创建的格式:

类名 对象名 = new 类名();

对象创建的示例:

Phone phone = new Phone();

如果在一个类中要使用别的类,分2种情况。

1. 别的类和当前类在同一个包中。不需要导包。

2. 别的类和当前类在不同的包中。需要导包。

对象的使用

使用对象的属性

使用对象的属性包括:给属性赋值、使用属性的值。

给对象的属性赋值格式:

对象名.属性名 = 值;

示例:

phone.brand = "iPhone";
phone.price = 6888;

使用对象的属性值格式:

数据类型 变量名 = 对象名.属性名;

示例:

String yourPhoneBrand = phone.brand;
int yourPhonePrice = phone.price;
使用对象的方法

使用对象的方法指的就是调用对象的方法。

格式:

对象名.方法名();//如果方法有参数,在小括号内写上实参。如果方法有返回值,可以用变量接收返回值。

示例:

phone.call();//调用打电话方法
phone.sendMessage();//调用发短信方法

测试类和对象

1. 新建一个类(ClassTest)用于测试Phone对象的使用,在main方法中创建1部手机,测试其属性和方法。

2. 代码:

public class ClassTest {
    public static void main(String[] args) {
        //创建phone对象
        Phone phone = new Phone();
        //给brand、price赋值
        phone.brand = "iPhone";
        phone.price = 6888;
        //打印手机的brand和price
        System.out.println(phone.brand);
        System.out.println(phone.price);
        //打电话
        phone.call();
        //发信息
        phone.sendMessage();
    }
}

对象在内存中的表示

单个对象在内存中的表示

public static void main(String[] args) {
    //创建phone对象
    Phone phone = new Phone();
    System.out.println(phone);
    //打印手机的brand和price
    System.out.println(phone.brand);
    System.out.println(phone.price);
    //给brand、price赋值
    phone.brand = "iPhone";
    phone.price = 6888;
    //打印手机的brand和price
    System.out.println(phone.brand);
    System.out.println(phone.price);
    //打电话
    phone.call();
    //发信息
    phone.sendMessage();
}

多个对象在内存中的表示

public static void main(String[] args) {
    // 创建phone对象
    Phone phone = new Phone();
    System.out.println(phone);
    // 打印手机的brand和price
    System.out.println(phone.brand);
    System.out.println(phone.price);
    // 给brand、price赋值
    phone.brand = "iPhone";
    phone.price = 6888;
    // 打印手机的brand和price
    System.out.println(phone.brand);
    System.out.println(phone.price);
    // 打电话
    phone.call();
    // 发信息
    phone.sendMessage();
    System.out.println("--------------");
    // 创建phone对象
    Phone phone2 = new Phone();
    System.out.println(phone2);
    // 打印手机的brand和price
    System.out.println(phone2.brand);
    System.out.println(phone2.price);
    // 给brand、price赋值
    phone2.brand = "华为";
    phone2.price = 2999;
    // 打印手机的brand和price
    System.out.println(phone2.brand);
    System.out.println(phone2.price);
    // 打电话
    phone2.call();
    // 发信息
    phone2.sendMessage();
}

多个对象指向相同堆区

public static void main(String[] args) {
    // 创建phone对象
    Phone phone = new Phone();
    System.out.println(phone);
    // 打印手机的brand和price
    System.out.println(phone.brand);
    System.out.println(phone.price);
    // 给brand、price赋值
    phone.brand = "iPhone";
    phone.price = 6888;
    // 打印手机的brand和price
    System.out.println(phone.brand);
    System.out.println(phone.price);
    // 打电话
    phone.call();
    // 发信息
    phone.sendMessage();
    System.out.println("--------------");
    Phone phone2 = phone;
    System.out.println(phone2);
    // 打印手机的brand和price
    System.out.println(phone2.brand);
    System.out.println(phone2.price);
    // 给brand、price赋值
    phone2.brand = "华为";
    phone2.price = 2999;
    // 打印手机的brand和price
    System.out.println(phone2.brand);
    System.out.println(phone2.price);
    // 打电话
    phone2.call();
    // 发信息
    phone2.sendMessage();
}

new出来的内存区域才是真正的对象。

phone和phone2只是保存了对象的地址,相当于phone和phone2代表了对象。我们习惯把这种保存了对象地址的变量叫做对象。

如果多个变量指向同一个对象,那么任何一个变量都可以修改对象的内容。

类和对象练习

学生类

1. 需求:创建一个代表学生的类,并创建学生对象测试效果。属性只写出姓名、年龄即可,方法只写出学习、做作业即可。

2. 代码:

学生类代码:

public class Student {
    //属性
    String name;//姓名
    int age;//年龄

    //方法
    public void study() {
        System.out.println(name + "正字努力学习Java面向对象");
    }

    public void doHomework() {
        System.out.println("十万代码成就十万年薪。" + name + "正在努力做练习,离10万年薪越来越近了");
    }
}

测试代码:

public static void main(String[] args) {
    Student stu = new Student();
    stu.name = "马化腾";
    stu.age = 22;
    stu.study();
    stu.doHomework();
    Student stu2 = new Student();
    stu2.name = "李彦宏";
    stu2.age = 19;
    stu2.study();
    stu2.doHomework();
}

实例变量(成员变量)和局部变量:

1. 实例变量:定义在类中方法外的变量。

2. 局部变量:在方法中定义的变量(包括方法的形参)。

1. 设计一个代表圆的类。要求能计算圆的周长和面积。

2. 代码:

圆类代码:

public class Circle {
    //属性
    double r;   //半径

    //方法
    //计算周长
    public double primeter() {
        return 2 * 3.1415926 * r;
    }

    //计算面积
    public double area() {
        return 3.1415926 * r * r;
    }

}

测试代码:

public static void main(String[] args) {
    Circle c1 = new Circle();
    c1.r = 10;
    System.out.println(c1.primeter());
    System.out.println(c1.area());

    Circle c2 = new Circle();
    c2.r = 4;
    System.out.println(c2.primeter());
    System.out.println(c2.area());
}

教师数组

1. 定义一个教师类,教师包含工号(num)和工资(salary)两个属性。定义一个数组,保存10名教师的信息。教师的编号从100开始,教师的工资是[8k, 15k]之间的一个数。打印出薪资是12k的教师的信息。

2. 代码:

教师类代码:

public class Teacher {
    int num;    //工号
    int salary; //工资

    public void showInfo() {
        System.out.println("工号:" + num + ",工资:" + salary);
    }
}

测试代码:

public static void main(String[] args) {
    // 创建一个数组,保存10个教师
    Teacher[] teachers = new Teacher[10];
    // 创建Random对象,用于随机工资。
    Random random = new Random();
    // 通过循环创建10个教师,并放入数组中。
    for (int i = 0; i < teachers.length; i++) {
        Teacher t = new Teacher();
        t.num = i + 100;
        t.salary = (random.nextInt(15 - 8 + 1) + 8) * 1000;
        teachers[i] = t;
    }
    // 遍历数组
    for (int i = 0; i < teachers.length; i++) {
        teachers[i].showInfo();
    }
    System.out.println("-----------");
    // 查找工资为12k的教师
    for (int i = 0; i < teachers.length; i++) {
        if (teachers[i].salary == 12000) {
            teachers[i].showInfo();
        }
    }
}

面向对象编程、面向过程编程

面向对象编程(Object Oriented Programing)是相对于面向过程编程(Procedure Oriented Programing)而言的。它们是2种不同的编程思想。

面向过程编程(POP)

面向过程编程是一种以功能为中心来进行思考和组织的编程方法,它关注的是功能如何实现,就是分析出解决问题所需要的的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个调用就可以了。----关注的是功能的实现

面向对象编程(OOP)

面向对象编程是一种以事物(对象)为中心的编程思想,它关注的是完成某件事情需要哪些对象参与,这些对象应该具有什么样的属性和方法。通过对象的协作完成某件事情。----关注的是参与者(类)怎么设计

面向对象编程和面向过程编程的区别

需求:把大象关进冰箱里

面向过程编程

1. 编写函数实现打开冰箱门的功能

编写函数实现把大象装进去的功能

编写函数实现把冰箱门关闭的功能

2. 在main函数中依次调用函数:打开冰箱门、把大象装进去、把冰箱门关上。

面向对象编程

1. 分析把大象关进冰箱需要什么对象参与:大象、冰箱、人。

2. 设计各个类

public class 冰箱{
    public void 开门(){
        ...
    }
    public void 关门(){
        ...
    }
}
public class 大象{
    public void 进入(冰箱 icebox){
        ...
    }
}
public class 人{
    public void 打开(冰箱 icebox){
        icebox.开门();
    }
    public void 抬起(大象 elephant){
        ...
        elephant.进入(icebox);
        ...
    }
    public void 关闭(冰箱 icebox){
        icebox.关门();
    }
}

3. 在main方法中:

创建人(张三),创建冰箱(海尔冰箱),创建大象(艾米丽)

张三.打开(海尔冰箱);

张三.抬起(艾米丽);

张三.关闭(海尔冰箱);

无论面向过程,还是面向对象都能实现把大象装进冰箱这么一件事。从上述的过程中,我们不难发现,面向过程编程的核心是完成某件事;而面向对象的核心是设计参与者,最后才去完成具体的事。

项目种类越大,面向对象越有优势,而面向过程这越难以实现。例如:拍一个几分钟的小品,可以使用面向过程的思想,从头到尾设计每个细节。但拍一部电影,或者拍摄一部电视剧就得用面向对象的思想了,对每个参与者进行分工,各自干好自己的事情,镜头也未必从前往后拍摄,今天下雨可以先拍下雨的戏份,今天到场的演员多,可以拍摄演员多的戏份,最后进行剪辑拼接制作成电影和电视剧。

封装

面向对象语言有三大特性:封装、继承和多态

在讲解封装(encapsulation)的概念之前,我们先学习一下private关键字。

private

先看下面的代码:

有一个Student类

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

    //实例方法
    public void study() {
        System.out.println(name + "正在努力学习Java面向对象的知识。");
    }

    public void doHomework() {
        System.out.println(name + "在努力的写作业。十万行代码成就你十万年薪");
    }

    public void showInfo() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }
}

Student类创建了2个对象。

public static void main(String[] args) {
    Student stu1 = new Student();
    stu1.name = "马化腾";
    stu1.age = 22;
    stu1.showInfo();
    Student stu2 = new Student();
    stu2.name = "李彦宏";
    stu2.age = -20;
    stu2.showInfo();
}

输出结果:

上述的输出结果是没有错的,程序也正常执行的。但是人的年龄是-20是有点违背逻辑的。

之所以出现这种问题,是因为外界可以直接操作属性。想要避免这种问题,最好的办法是不让外界直接操作属性,把属性隐藏起来,给外界提供访问属性的方法。

通过private把属性隐藏起来

private单词的含义是私有的。private可以修饰类中的属性和方法,修饰属性的时候,表示属性私有,外界无法直接访问(所谓的直接访问是通过对象名.属性名访问),但是在本类中可以访问。

public class Student {
    //实例变量
    private String name;//姓名
    private int age;//年龄

    //实例方法
    public void study() {
        System.out.println(name + "正在努力学习Java面向对象的知识。");
    }

    public void doHomework() {
        System.out.println(name + "在努力的写作业。十万行代码成就你十万年薪");
    }

    public void showInfo() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }
}

上述代码实现了属性的私有,一旦私有,外界将不能使用对象名.属性名去访问对象的属性。

通过setter、getter方法访问属性

setter方法:为属性(实例变量)赋值的方法。

getter方法:获取属性(实例变量)值的方法。

由于getter、setter方法是我们特意为外界定义的方法,方便外界能访问属性,因此要有public修饰。

public String getName() {
    return name;
}
public void setName(String n) {
    name = n;
}
public int getAge() {
    return age;
}
public void setAge(int a) {
    age = a;
}

setter方法既然是为属性赋值,就必须要有参数,而且参数的类型和属性的类型相同。setter方法的方法名是set+首字母大写的属性名。例如:属性名是name,setter方法的方法名是setName,属性名是age,setter方法的方法名是setAge。

getter方法既然是要获取属性的值,就必须有返回值,而且返回值的类型和属性的类型相同。getter方法的方法名是get+首字母大写的属性名。例如:属性名是name,getter方法的方法名是getName,属性名是age,getter方法的方法名是getAge。

提供了方法以后,外界就可以通过方法去访问属性。

public static void main(String[] args) {

    Student stu1 = new Student();
    stu1.setName("马化腾");
    stu1.setAge(22);
    stu1.showInfo();

    Student stu2 = new Student();
    stu2.setName("李彦宏");
    stu2.setAge(-20);
    stu2.showInfo();
}

输出结果:

输出结果还是-20,并没有解决任何问题呀!稍作改进,改进代码如下:

public void setAge(int a) {
    if(a < 0) {
        System.out.println("您输入的年龄有误。");
    }else {
        age = a;
    }
}

输出结果:

setter/getter和直接访问的异同

相同点:都是在访问属性,包括赋值和取值。

不同点:1.直接访问属性优势是简单快捷,一步到位;劣势是有可能会出现数据错误。2.通过setter/getter访问属性优势是数据没有直接赋值给属性,在赋值之前可以做一些操作和处理;劣势是代码量略大。

在开发中属性一般情况下都定义private,对外提供pulic的getter和setter方法。

this

讲解this之前,先看一下刚才写的setter、getter方法

public String getName() {
    return name;
}
public void setName(String n) {
    name = n;
}
public int getAge() {
    return age;
}
public void setAge(int a) {
    if(a < 0) {
        System.out.println("您输入的年龄有误。");
    }else {
        age = a;
    }
}

上面方法中的参数并没有做到见名知意。如果做到见名知意,应改为:

public String getName() {
    return name;
}
public void setName(String name) {
    name = name;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    if(age < 0) {
        System.out.println("您输入的年龄有误。");
    }else {
        age = age;
    }
}

改成这样以后,确实见名知意了,但是程序的结果却不对了。

这是因为:在一个类中,如果局部变量和实例变量名称相同,在方法中使用变量的时候,使用的是局部变量,而不是实例变量。想要在方法中使用实例变量的话,需要使用this.实例变量名

public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    if(age < 0) {
        System.out.println("您输入的年龄有误。");
    }else {
        this.age = age;
    }
}

this的英文含义是这个,在代码中this是一个特殊的对象,它始终指的是调用方法的对象,即谁调用方法,this就是谁。

可以通过打印内存地址的方式,来检验this究竟是谁。

this关键字

1. this修饰的变量用于指代实例变量。方法的形参如果与实例变量同名,不带this的变量是形参,而不是实例变量。方法的形参如果和实例变量不同名,不需要用this修饰。

2. this代表的就是调用方法的那个对象。

构造方法

构造方法是一种特殊的方法,它是创建对象时调用的方法,用于在创建对象的时候对属性进行初始化。

Student stu1 = new Student();//Student()就是一个构造方法。
构造方法的特点

1. 构造方法只能用在对象创建的时候。

2. 构造方法的作用是对属性进行初始化。

3. 构造方法的方法名必须和类名相同。

4. 构造方法没有返回值,连void都不能写。

5. 如果自己没有提供构造方法,系统会默认生成一个无参数的构造方法。

6. 如果自己提供了任何一个构造方法,系统将不再生成无参数的构造方法。

7. 构造方法可以重载。

构造方法的书写格式
public 类名(参数列表){
 
}
构造方法示例
public Student() {

}
public Student(String name) {
    this.name = name;
}
public Student(String name, int age) {
    this.name = name;
    this.age = age;
}

上面的三个方法都是构造方法。

构造方法的使用
public static void main(String[] args) {
    Student stu1 = new Student("马化腾", 22);
    stu1.showInfo();
    Student stu2 = new Student("李彦宏");
    stu2.setAge(20);
    stu2.showInfo();
    Student stu3 = new Student();
    stu3.setName("马云");
    stu3.setAge(25);
    stu3.showInfo();
}

在开发过程中,我们通过会至少给2个构造方法。其中一个是无参构造方法,另外一个是全参的构造方法。除此以外根据需求添加别的构造方法。

标准的Java类

标准Java类的定义原则

1. 属性用private修饰

2. 提供属性对应的setter、getter方法

3. 提供1个或多个构造方法

4. 提供正常的功能性方法

标准Java类示例
public class Circle {
    //属性
    private double r;   //半径
    public double getR() {
        return r;
    }
    public void setR(double r) {
        this.r = r;
    }
    public Circle() {
    }
    public Circle(double r) {
        this.r = r;
    }
    //实例方法
    public double perimeter() {
        return 2 * Math.PI * r;
    }
    public double area() {
        return Math.PI * r * r;
    }
}

使用圆的时候:

public static void main(String[] args) {
    // 使用无参构造创建对象
    Circle c1 = new Circle();
    c1.setR(10);
    c1.perimeter();
    c1.area();
    // 使用有参构造创建对象
    Circle c2 = new Circle(4);
    c2.perimeter();
    c2.area();
}

封装

封装:隐藏对象的内部细节,对外提供接口(访问方式)。

封装的原则:将类的某些信息隐藏在类内部,不允许外界直接访问,而是给外界提供接口(方法)。外界通过接口访问内部的数据以及类的功能。

1. getter、setter封装了实例变量。

2. 方法封装了功能的实现细节。

3. 类封装了属性和方法。

封装的好处:

1. 通过方法来控制实例变量的操作,提高了代码的安全性。

2. 把代码用方法进行封装,提高了代码的复用性。

常用

定义类使用class关键字。

类中的属性通常用private修饰,对外提供setter/getter方法。

类中的方法通常用public修饰。

类中应根据需要提供适当数量的构造方法。

对象需要先创建再使用,创建对象的语法是: 类名 对象名 = new 类名();// 类名()指的是类的构造方法。

  • 16
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值