共计 7890 个字符,预计需要花费 20 分钟才能阅读完成。
1、面向对象
1.1、概念
我们回想一下,这几天我们完成一个需求的步骤:首先是搞清楚我们要做什么,然后在分析怎么做,最后我们再代码体现。一步一步去实现,而具体的每一步都需要我们去实现和操作。这些步骤相互调用和协作,完成我们的需求。
在上面的每一个具体步骤中我们都是参与者,并且需要面对具体的每一个步骤和过程,这就是面向过程最直接的体现。
那么什么是面向过程开发呢? 面向过程开发,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。面向过程的代表语言:C 语言
当需求单一,或者简单时,我们一步一步去操作没问题,并且效率也挺高。可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻烦了,这时就开始思索,能不能把这些步骤和功能在进行封装,封装时根据不同的功能,进行不同的封装,功能类似的封装在一起。这样结构就清晰了很多。用的时候,找到对应的类就可以了。这就是面向对象的思想。
1.2、特点
(1)是一种更符合我们思想习惯的思想;
(2)可以将复杂的事情简单化;
(3)将我们从执行者变成了指挥者,角色发生了转换;
1.3、举例
买电脑:在买电脑的流程中,我们只关注电脑的性能和价格,而不关心电脑是怎么生产的,如何组装的,此时就是将电脑当作一个对象,而人可以有去购买电脑的操作。
洗衣服:在洗衣服的流程中,我们将衣服和人可以看作为对象,而人可以有洗的动作,衣服则是洗的对象。
1.4、面向对象的特征
(1)封装:封装是把对象的属性、操作结合在一起,构成一个独立的对象。一旦封装,内部信息对外界是隐藏的,也就象一个四周密封的房子一样,不允许直接对对象的属性进行操作,要想操作,只能通过局部接口(相当于房子的大门)。外部只能看到对象对操作的反应,而不知道对象是如何做出这一反应的。所以封装包含两个方面的含义,一个是信息隐藏,另一个局部开放。会在接下来的课程中详细学习。
(2)继承:继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。会在接下来的课程中详细学习。
(3)多态:指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。会在接下来的课程中详细学习。
2、类与对象
面向对象的思维方式在 Java 代码中表现为类的定义与对象的使用。理清类与对象的概念与关系是面向对象的重点。
2.1、类的概念
类是具有相同特征(属性)和行为 (功能) 的一类事物的抽象。
我们将现实事物的特征抽象为类中的成员变量,现实事物的行为功能抽象为类中的成员方法。
** 注意:** 实际上所属关系是直接属于类的,均称为成员,如成员变量、成员方法、后边学习的成员内部类,并不单指成员变量。
2.2、类的声明格式
2.2.1、格式
public class 类名{private 数据类型 变量名1;
private 数据类型 变量名2;
…其他成员变量
public 返回值类型 方法名(参数类型 参数名,参数类型 参数名2…){方法体;}
每个属性对应的 get/set 方法, 使用 this 区分成员变量与局部变量
}
说明:
(1)使用 class(类)来抽象一个现实生活中的事物
(2)定义成员变量对应事物的属性,一般使用 private 修饰,提供 get/set 方法
(3)定义成员方法对应事物的功能,一般使用 public 修饰
2.2.2、修饰符
Java 中访问修饰符 public、private、protected、default 范围
public: Java 语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包(package)访问。
private: Java 语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的类、属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
protected: 介于 public 和 private 之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类、属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
**default:** 即不加任何访问修饰符,通常称为“默认访问模式“。该模式下,只允许在同一个包中进行访问。
2.2.3、案例
需求:声明一个人类,声明他的姓名和年龄,并声明他的行为吃。
public class Person {private String name;
private int age;
public void eat() {System.out.println("吃过了!");
}
public void setName(String name) {this.name = name;
}
public String getName() {return name;
}
public void setAge (int age) {this.age = age;
}
public int getAge() {return age;
}
}
2.3、类的使用格式
类的使用非常简单,一般分为两个动作:创建对象与调用方法。
类的定义是现实事物的抽象,真正使用的是类创建的对象。通常使用对象来调用方法。
2.3.1、格式
对象创建格式:
数据类型 对象名 = new 数据类型();
对象方法的调用:
** 无返回值:** 对象名. 方法名(参数);
** 有返回值:** 返回值类型 变量名 = 对象名. 方法名(参数);
2.3.2、案例
需求:声明一个人类对象,并调用姓名的 set/get 方法
public class PersonDemo{public static void main(String args[]){Person p=new Person();// 产生对象
p.setName("张三");// 无返回值使用方法
String s=p.getName();// 有返回值使用方法
System.out.println("s="+s);//s= 张三
}
}
3、类中成员
3.1、成员变量
直接定义在类中的变量称为成员变量,在面向对象思想设计上,是类的组成部分。
成员变量通常使用 private 修饰,阻止本类以外的其他类访问。
成员变量不能重名,局部变量不能重名,成员与局部变量可以重名,但是需要使用 this 区分。
使用 this 访问的为成员变量,直接访问的为局部。在方法内访问变量,如果没有该名称的局部变量会自动查找是否有该名称的成员变量。
3.2、成员方法
正常定义成员方法时,一般是不需要添加 static 修饰符的。static 修饰符会在后边详细简介。
成员方法一般可分为两类:
(1)没有业务的属性 get/set 方法,与属性对应
(2)有业务的普通方法,属于类的功能
3.3、案例
需求:定义一个人类,他拥有成员变量(属性):姓名、年龄、性别,成员方法(行为):吃饭、睡觉、打豆豆及属性的 get/set 方法
/*
* 定义自定义类型 Person 类
*
* 属性(成员变量):姓名 String、年龄 int、性别 String
* 行为(成员方法):吃饭、睡觉、打豆豆、为成员变量赋值 / 获取成员变量的值的方法
*
* private 修饰的成员(成员变量,成员方法) 让外界无法直接访问 内部可以访问
* this 区分成员变量与局部变量(注意:这是定义时所展现出来的功能,其功能本质,一会单独说)
*
* 成员方法: 一般不使用 static 修饰
* 分为两种:
* 1.get/set 方法
* 2. 属于类的功能的方法
*/
public class Person {// 定义成员变量
private String name;
private int age;
private String sex;
// 吃饭
public void eat() {System.out.println(name + "吃了");
}
// 睡觉
public void sleep() {System.out.println(name + "睡了");
}
// 打豆豆
public void hitBeanBean() {System.out.println(name + "打了,爽了,敲代码了!");
}
// 为 name 赋值的方法:方法名:setName;参数:String name;返回值:void
public void setName(String name) {this.name = name;
}
// 获取 name 的值的方法:方法名;getName;参数:无;返回值:String name
public String getName() {return name;
}
public void setAge(int age) {this.age = age;
}
public int getAge() {return age;
}
public String getSex() {return sex;
}
public void setSex(String sex) {this.sex = sex;
}
}
Person 类的应用
/*
* 测试 Person 类
*
* 导包:在同一个文件夹下不需要导包
* 创建对象:数据类型 变量名 = new 数据类型()
* 调用方法:返回值类型 新变量名 = 变量名. 方法名(实际参数);
*
* 方法调用时,用 static 修饰的方法调用其他方法时,其他方法必须使用 static 修饰
* 指的是:* 在同一个类中,直接调用其他方法时,其他方法必须使用 static 修饰
* 如果使用对象名. 方法名 () 这种方式,其他方法一般不使用 static 修饰
*/
public class PersonDemo {public static void main(String[] args) {// 创建对象
Person p = new Person();
// 调用方法
p.setName("柳岩");
p.setAge(38);
// 因为 age 用 private 修饰了 所以外界不能直接访问了
//p.age = -1;
// 如果使用对象名. 方法名 () 这种方式 其他方法一般不使用 static 修饰
p.eat();
p.sleep();
p.hitBeanBean();
String name = p.getName();
System.out.println(name);
System.out.println(p.getAge());
//main 方法直接调用 method 方法 method 方法必须使用 static 修饰
//method();
}
public void method() {System.out.println("我是一个方法");
}
}
执行结果:
3.4、成员变量与局部变量区别
(1)在类中的位置不同。
成员变量:类中,方法外;
局部变量:方法中或者方法声明上(形式参数)
(2)在内存中的位置不同。
成员变量:堆内存;
局部变量:栈内存
(3)生命周期不同。
成员变量:随着对象的创建而存在,随着对象的消失而消失;
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
(4)初始化值的不同。
成员变量:有默认值;
局部变量:没有默认值。必须先定义,赋值,最后使用
public class VarDemo {int x;
public void show() {int y = 0;
System.out.println(x);//0
System.out.println(y);//0
}
}
4、类与对象的关系
类是抽象概念,对象是类的具体实例。我们通常真正使用的是某个类的实例对象,进而调用该对象的方法。
一个类可以有多个对象,一个对象只属于一个类(在讲完多态后会有不同的理解)。
可以说创建对象并调用方法是类最主要的使用方式。
我们学习编程语言,就是为了模拟现实世界的事物,实现信息化。
比如:去超市买东西的计费系统,去银行办业务的系统。
我们如何表示一个现实世界事物呢:
属性:就是该事物的描述信息
行为:就是该事物能够做什么
举例:学生拥有班级、年纪等属性,拥有上课、考试等行为
我们学习的 Java 语言最基本单位是类,所以我们就应该把事物用一个类来体现。
类:是一组相关的属性和行为的集合
对象:是该类事物的具体体现
举例:类:学生 对象:小明就是一个对象
5、类作为形参与返回值
5.1、类作为形参
以类作为形参,接收时,接收的是对象地址
5.1.1、案例
学生类:
public class Student {public void study() {System.out.println("好好学习, 天天向上");
}
}
老师类:
public class Teacher {public void test(Student s) {s.study();
}
}
测试类:
public class TestDemo {public static void main(String[] args) {Teacher t = new Teacher();
Student s = new Student();
t.test(s);
}
}
执行结果:
5.2、类作为返回值
以类作为返回值,返回时,返回的其实是该类的对象地址
5.2.1、案例
学生类:
public class Student {public void study() {System.out.println("好好学习, 天天向上");
}
}
老师类:
public class Teacher {public Student getStudent() {Student s = new Student();
return s;
}
}
测试类:
public class TestDemo{public static void main(String[] args) {Teacher t = new Teacher();
Student s = t.getStudent();
s.study();}
}
运行结果:
6、自定义类
6.1、自定义汽车类
6.1.1、分析
** 属性:** 颜色(String)、品牌(String)、价格(double)、车牌号(String)、车主(String)
行为:(1)set/get(2)运输、兜风
6.1.2、案例
汽车类:
public class Car {private String color;// 颜色
private String pinPai;// 品牌
private double price;// 价格
private String number;// 车牌号
private String admin;// 车主
// 运输方法:方法名:yunShu;参数:String 货物;返回值:无
public void yunShu(String huoWu){System.out.println(admin+"开着"+color+pinPai+"价值"+price
+"车牌号为"+number+"的车"+"运输了"+huoWu);
}
// 兜风:方法名:douFeng;参数:String name;返回值:无
public void douFeng(String name){System.out.println(admin+"开着"+color+pinPai+"价值"+price
+"车牌号为"+number+"的车"+"带着"+name+"去兜风");
}
//set/get
public void setColor(String color){this.color = color;
}
public String getColor(){return color;
}
public String getPinPai() {return pinPai;
}
public void setPinPai(String pinPai) {this.pinPai = pinPai;
}
public double getPrice() {return price;
}
public void setPrice(double price) {this.price = price;
}
public String getNumber() {return number;
}
public void setNumber(String number) {this.number = number;
}
public String getAdmin() {return admin;
}
public void setAdmin(String admin) {this.admin = admin;
}
}
测试类:
public class CarDemo{public static void main(String[] args){Car c = new Car();
// 调用方法
c.setAdmin("老王");
c.setColor("绿色");
c.setPinPai("三蹦子");
c.setPrice(250.38);
c.setNumber("JP74110");
c.yunShu("猪");
c.douFeng("柳岩");
}
}
运行结果:
6.2、自定义手机类
6.2.1、分析
** 属性:** 颜色(String)、品牌(String)、价格(double)
** 行为:** 打电话、发短信
6.2.2、案例
手机类:
public class Phone {// 品牌
String brand;
// 价格
int price;
// 颜色
String color;
// 打电话
public void call(String name) {System.out.println("给" + name + "打电话");
}
// 发短信
public void sendMessage() {System.out.println("群发短信");
}
}
测试类:
public class PhoneDemo {public static void main(String[] args) {// 创建对象
Phone p = new Phone();
// 输出成员变量值
System.out.println("品牌:" + p.brand);//null
System.out.println("价格:" + p.price);//0
System.out.println("颜色:" + p.color);//null
System.out.println("------------");
// 给成员变量赋值
p.brand = "锤子";
p.price = 2999;
p.color = "棕色";
// 再次输出成员变量值
System.out.println("品牌:" + p.brand);// 锤子
System.out.println("价格:" + p.price);//2999
System.out.println("颜色:" + p.color);// 棕色
System.out.println("------------");
// 调用成员方法
p.call("唐嫣");
p.sendMessage();}
}
运行结果:
7、对象的内存
7.1、对象在内存中的位置
对象由 new 关键字创建,如同数组,实体存在于堆内存中;任何事物均可以定义成类,创建的对象,属于引用类型;
7.2、一个对象调用一个方法
通过上图,我们可以理解,在栈内存中运行的方法,遵循 ” 先进后出,后进先出 ” 的原则。变量 dw 指向堆内存中的空间,寻找方法信息,去执行该方法。
但是,这里依然有问题存在。创建多个对象时,如果每个对象内部都保存一份方法信息,这就非常浪费内存了,因为所有对象的方法信息都是一样的。
7.3、两个对象调用一个方法
对象调用方法时,根据对象中方法标记(地址值),去类中寻找方法信息。这样哪怕是多个对象,方法信息只保存一份,节约内存空间。
7.4、一个引用,作为参数传递到方法中内存图
引用类型作为参数,传递的是地址值。