我们回想一下, 前面我们完成一个需求的步骤是怎样的?
上述的每一个步骤, 我们都是参与者, 并且需要面对具体的每一个步骤和过程, 这就是面向过程最直接的体现.
面向过程思想其实就是一种编程思想. 所谓的面向过程开发, 指的就是面向着具体的每一个步骤和过程, 把每一个步骤和过程完成, 然后由这些功能方法相互调用, 完成需求.
记忆: 面向过程的代表语言是: C语言.
当需求单一, 或者简单时, 我们一步一步去操作是没问题的, 并且效率也挺高. 可随着需求的更改, 功能的增多, 发现需要面对每一个步骤就很麻烦了, 于是我们就想着, 能不能把这些步骤和功能在进行封装, 封装时根据不同的功能, 进行不同的封装, 功能类似的用一个类封装在一起, 这样结构就清晰了很多. 用的时候, 找到对应的类就可以了. 这就是面向对象的思想.
Int[] arr = {11, 22, 33, 44, 55};
sop(Arrays.toString(arr)); -> “[11, 22, 33, 44, 55]”
面向对象思想是一种编程思想, 它是基于面向过程的, 强调的是以对象为基础完成各种操作.
总结来讲, 万物皆对象.
问题一: 你为什么学习编程语言?
我们学习编程语言, 其实就是为了把现实世界的事物通过代码模拟出来, 实现信息化.
例如:
问题二: 我们是如何表示现实世界的事物呢?
例如: 学生
问题三: Java语言是如何表示现实世界的事物呢?
举例:
类 学生 大象
对象 张三, 23 北京动物园叫图图的大象
定义类其实就是定义类的成员(成员变量和成员方法)
public class 类名 { //成员变量 //成员方法 }
需求
定义一个学生类.
参考代码
所谓类的使用, 就是使用类中定义的成员(成员变量和成员方法).
需求
使用学生类中的成员.
参考代码
//手机类
public class Phone {
//属性, 成员变量
//品牌
String brand;
//价格
int price;
//颜色
String color;
//行为, 成员方法
//打电话
public void call(String name) {
System.out.println("给" + name + "打电话!...");
}
//发短信
public void sendMessage(String name) {
System.out.println("给" + name + "发短信!...");
}
}
//手机类的测试类
public class PhoneTest {
public static void main(String[] args) {
//1. 创建手机类的对象.
Phone p = new Phone();
//2. 设置成员变量值.
p.brand = "华为";
p.price = 6666;
p.color = "黑色";
//3. 打印成员变量.
System.out.println(p.brand);
System.out.println(p.price);
System.out.println(p.color);
//4. 调用成员方法.
p.call("夯哥");
p.sendMessage("夯哥");
}
}
代码
//手机类
public class Phone {
//属性, 成员变量
String brand; //品牌
int price; //价格
String color; //颜色
//行为, 成员方法
//打电话
public void call(String name) {
System.out.println("给" + name + "打电话!...");
}
//发短信
public void sendMessage(String name) {
System.out.println("给" + name + "发短信!...");
}
}
//手机类的测试类
public class PhoneTest {
public static void main(String[] args) {
//1. 创建手机类的对象.
Phone p = new Phone();
//2. 设置成员变量值.
p.brand = "华为";
p.price = 6666;
p.color = "黑色";
//3. 打印成员变量.
System.out.println(p.brand + "--" + p.price + "--" + p.color);
//4. 调用成员方法.
p.call("夯哥");
p.sendMessage("夯哥");
}
}
代码
//手机类
public class Phone {
//属性, 成员变量
String brand; //品牌
int price; //价格
String color; //颜色
//行为, 成员方法
//打电话
public void call(String name) {
System.out.println("给" + name + "打电话!...");
}
//发短信
public void sendMessage(String name) {
System.out.println("给" + name + "发短信!...");
}
}
//手机类的测试类
public class PhoneTest {
public static void main(String[] args) {
//1. 创建手机类的对象.
Phone p = new Phone();
//2. 设置成员变量值.
p.brand = "华为";
p.price = 6666;
p.color = "黑色";
//3. 打印成员变量.
System.out.println(p.brand + "--" + p.price + "--" + p.color);
//4. 调用成员方法.
p.call("传智播客");
p.sendMessage("传智播客");
Phone p2 = new Phone();
p2.brand = "小米";
p2.price = 3333;
p2.color = "白色";
System.out.println(p2.brand + "--" + p2.price + "--" + p2.color);
p2.call("黑马程序员");
p2.sendMessage("黑马程序员");
}
}
代码
//手机类
public class Phone {
//属性, 成员变量
String brand; //品牌
int price; //价格
String color; //颜色
//行为, 成员方法
//打电话
public void call(String name) {
System.out.println("给" + name + "打电话!...");
}
//发短信
public void sendMessage(String name) {
System.out.println("给" + name + "发短信!...");
}
}
//手机类的测试类
public class PhoneTest {
public static void main(String[] args) {
//1. 创建手机类的对象.
Phone p = new Phone();
//2. 设置成员变量值.
p.brand = "华为";
p.price = 6666;
p.color = "黑色";
//3. 打印成员变量.
System.out.println(p.brand + "--" + p.price + "--" + p.color);
//4. 调用成员方法.
p.call("传智播客");
p.sendMessage("传智播客");
Phone p2 = p;
p2.brand = "小米";
p2.price = 3333;
p2.color = "白色";
System.out.println(p.brand + "--" + p.price + "--" + p.color);
System.out.println(p2.brand + "--" + p2.price + "--" + p2.color);
p2.call("黑马程序员");
p2.sendMessage("黑马程序员");
}
}
它们的区别如下:
public class VariableDemo{
int x;
public void show() {
int y = 10;
System.out.println(x);
System.out.println(y);
}
}
上述的代码中, 我们可以任意的设置属性的值, 包括我们可以设置一些非法值, 例如: 把年龄设置成负数, 这样做程序就容易出问题, 针对于这种情况, 我们可以通过private关键字来优化它.
private是一个关键字, 也是访问权限修饰符的一种, 它可以用来修饰类的成员(成员变量和成员方法).
被private修饰的内容只能在本类中直接使用.
需求
参考代码
//学生类
public class Student{
//属性
String name; //姓名
private int age; //年龄
//getXxx()和setXxx()方法
public void setAge(int a) {
if(a >= 0 && age <= 150) {
//年龄合法, 就赋值.
age = a;
}
}
public int getAge() {
return age;
}
//行为
public void show() {
//被private修饰的内容, 可以在本类中直接访问.
System.out.println(name + "..." + age);
}
}
//学生类的测试类
public class StudentTest{
public static void main(String[] args) {
//1. 创建学生类的对象
Student s = new Student();
//2. 给成员变量赋值.
s.name = "张三";
//s.age = -23; //被private修饰的内容, 外界无法直接访问.
s.setAge(-23);
//3. 调用成员方法.
s.show();
}
}
刚才的代码, 为了讲解private关键字, 只给年龄属性加了private, 而在实际开发中, 除非必要, 否则成员变量都要用private来修饰, 然后提供对应的getXxx()和setXxx()方法, 方便用户访问对应的成员变量, 接下来, 我们来写一个实际开发中的标准代码.
需求
参考代码
public class Student {
//属性, 全部用private修饰.
//姓名
private String name;
//年龄
private int age;
public String getName() {
return name;
}
public void setName(String n) {
name = n;
}
public int getAge() {
return age;
}
public void setAge(int a) {
age = a;
}
//行为, 也就是成员方法.
public void study() {
System.out.println("键盘敲烂, 月薪过万!");
}
public void eat() {
System.out.println("学习饿了就要吃饭!.");
}
}
//测试类
public class StudentTest {
public static void main(String[] args) {
//1. 创建学生对象.
Student s = new Student();
//2. 设置成员变量值.
s.setName("张三");
s.setAge(23);
//3. 打印成员变量值.
System.out.println(s.getName() + "..." + s.getAge());
//4. 调用成员方法.
s.study();
s.eat();
}
}
封装是面向对象编程思想的三大特征之一, 所谓的封装指的就是隐藏对象的属性和实现细节, 仅对外提供一个公共的访问方式.
记忆:
面向对象的三大特征: 封装, 继承, 多态.
问题一: 怎么隐藏?
通过private关键字实现.
问题二: 公共的访问方式是什么?
getXxx() 和 setXxx()方法.
this代表本类当前对象的引用, 大白话翻译: 谁调用, this就代表谁.
6.4.2 作用
用来解决局部变量和成员变量重名问题的.
需求
参考代码
public class Student {
//属性, 全部用private修饰.
//姓名
private String name;
//年龄
private int 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;
//s.age = 23;
}
//行为, 也就是成员方法.
public void study() {
System.out.println("键盘敲烂, 月薪过万!");
}
public void eat() {
System.out.println("学习饿了就要吃饭!.");
}
}
//测试类
public class StudentTest {
public static void main(String[] args) {
//1. 创建学生对象.
Student s = new Student();
//2. 设置成员变量值.
s.setName("张三");
s.setAge(23);
//3. 打印成员变量值.
System.out.println(s.getName() + "..." + s.getAge());
//4. 调用成员方法.
s.study();
s.eat();
}
}
Java中, 使用变量遵循就近原则, 局部位置有就使用, 没有就去本类的成员位置找, 有就使用, 没有就报错.
解释: 先这么记忆, 不严谨, 因为本类没有, 还会去父类中查找, 这点在继承部分再解释.
构造方法是用来创建对象的, 捎带着可以给对象的各个成员变量赋值.
大白话:
构造方法就是用来快速对对象的各个属性赋值的.
public 类名(参数类型 参数名1, 参数类型 参数名2) { //这里可以写多个参数. //给对象的各个属性赋值即可. }
需求
参考代码
//学生类.
public class Student{
//类的空参构造.
public Student() {
System.out.println("这是构造方法");
}
}
//学生类的测试类
public class StudentTest{
public static void main(String[] args) {
Student s = new Student();
}
}
思考题
问: 给成员变量赋值有几种方式?
答: 1. 通过setXxx()方法实现(该方式不会创建新对象).
2. 通过构造方法实现(该方式会创建新对象).
以后在实际开发中, 也都是这样写的, 即: 标准的类的定义格式如下:
public class 类名{ //属性(成员变量), 全部用private修饰. //构造方法, 一般提供两个(无参, 全参) //getXxx()和setXxx()方法 //行为(成员方法), 根据需求来定义. }
需求
参考代码
//学生类
public class Student {
//属性(成员变量), 全部用private修饰.
private String name; //姓名
private int age; //年龄
//构造方法, 一般提供两个(无参, 全参)
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//getXxx()和setXxx()方法
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;
}
//行为(成员方法), 根据需求来定义.
public void study() {
System.out.println("键盘敲烂, 月薪过万!");
}
public void eat() {
System.out.println("学习饿了要吃饭");
}
}
//学生类的测试类
public class StudentTest {
public static void main(String[] args) {
//1. 创建学生对象.
Student s = new Student();
//2. 设置成员变量值.
s.setName("张三");
s.setAge(23);
//3. 打印成员变量值.
System.out.println(s.getName() + "..." + s.getAge());
//4. 调用成员方法.
s.study();
s.eat();
}
}
多个类中存在相同属性和行为时, 将这些内容抽取到单独的一个类中, 那么这多个类就无需再定义这些属性和行为了, 只要继承那个类即可. 这个关系, 就叫继承.
注意:
有了继承以后, 我们在定义一个类的时候, 可以在一个已经存在的类的基础上, 还可以定义自己的新成员.
在Java中, 可以通过extends关键字来实现类与类的继承, 具体格式如下:
public class 类A extends 类B { //子承父业 }
解释:
我们一般会念做: 子类和父类.
需求
参考代码
略
让类与类之间产生了关系, 也就让类的耦合性增强了.
解释:
开发原则: 高内聚, 低耦合.
//爷爷类,
//一个类如果没有显式的写父类, 默认就继承自Object类.
//Object类, 是所有类的父类.
public class GrandFather {
public void grandFather() {
System.out.println("grandFather....");
}
}
//父亲类
public class Father extends GrandFather{
public void father() {
System.out.println("father....");
}
}
//儿子类
public class Son extends Father {
}
//测试类
public class SonTest {
public static void main(String[] args) {
//创建子类对象.
Son s = new Son();
//问: Son的对象, 可以调用哪些方法?
s.father(); //从Father类继承过来的.
s.grandFather(); //从Father类继承过来的, 而Father类又从GrandFather类继承过来了.
}
}
public class Father {
int age = 30;
}
public class Son extends Father {
int age = 20;
}
public class FatherTest {
public static void main(String[] args) {
int age = 10;
System.out.println(age); //这里打印结果会是多少呢?
}
}
Java中使用变量遵循就近原则, 局部位置有就使用, 没有就去本类的成员位置找. 有就使用, 没有就去父类的成员位置找, 有就使用, 没有就报错.
注意: 不考虑父类的父类这种情况, 因为会一直往上找, 直到把所有的父类都找完, 还找不到, 就报错了.
super的用法和this很像:
功能 | 本类 | 父类 |
---|---|---|
访问成员变量 | this.成员变量名 | super.成员变量名 |
访问构造方法 | this(...) | super(...) |
访问成员方法 | this.成员方法名(参数值...) | super.成员方法名(参数值...) |
略.
略.
调用成员方法时, 也遵循就近原则, 本类中有, 就直接调用, 本类中没有, 就去父类中查找, 有就使用, 没有就报错.
子类中出现和父类一模一样的方法时, 称为方法重写. 方法重写要求返回值的数据类型也必须一样.
当子类需要使用父类的功能, 而功能主体又有自己独有需求的时候, 就可以考虑重写父类中的方法了, 这样, 即沿袭了父类的功能, 又定义了子类特有的内容.
需求
参考代码
略.
略.
注意: 子类继承父类时, 一般构造方法也要手动生成, 目的是为了帮助我们快速创建对象并赋值.
多态指的是同一个事物(或者对象)在不同时刻表现出来的不同状态.
例如: 一杯水.
但是水还是那杯水, 只不过在不同的环境下, 表现出来的状态不同.
需求
参考代码
略.
需求
参考代码
略.
提高了程序的扩展性.
父类引用不能访问子类的特有功能.
问: 那如何解决这个问题呢?
答: 通过向下转型来解决这个问题.
需求
参考代码
略.
向上转型
//格式 父类型 对象名 = new 子类型(); //例如 Animal an = new Cat();
向下转型
//格式 子类型 对象名 = (子类型)父类引用; //例如 Cat c = (Cat)an;
小Bug
//下述代码会报: ClassCastException(类型转换异常) Animal an = new Cat(); Cat c = (Cat)an; //这样写不报错. Dog d = (Dog)an; //这样写会报错.
需求
参考代码
略.
final是一个关键字, 表示最终的意思, 可以修饰类, 成员变量, 成员方法.
需求
参考代码
略
static是一个关键字, 表示静态的意思, 可以修饰成员变量, 成员方法.
需求
参考代码
//学生类
public class Student {
//属性
String name;
int age;
static String graduateFrom;
//行为
public void show() {
System.out.println(name + ".." + age + ".." + graduateFrom);
}
}
//测试类
public class StudentTest {
public static void main(String[] args) {
//1. 设置学生的毕业院校.
Student.graduateFrom = "传智学院";
//2. 创建学生对象s1.
Student s1 = new Student();
s1.name = "刘亦菲";
s1.age = 33;
//3. 创建学生对象s2.
Student s2 = new Student();
s2.name = "赵丽颖";
s2.age = 31;
//4. 打印属性值.
s1.show();
s2.show();
}
}
需求
参考代码
略.
回想前面我们的猫狗案例, 提取出了一个动物类, 这个时候我们可以通过Animal an = new Animal();来创建动物对象, 其实这是不对的, 因为, 我说动物, 你知道我说的是什么动物吗? 只有看到了具体的动物, 你才知道, 这是什么动物. 所以说, 动物本身并不是一个具体的事物, 而是一个抽象的事物. 只有真正的猫, 狗才是具体的动物. 同理, 我们也可以推想, 不同的动物吃的东西应该是不一样的, 所以, 我们不应该在动物类中给出具体的体现, 而是应该给出一个声明即可. 在Java中, 一个没有方法体的方法应该定义为抽象方法, 而类中如果有抽象方法, 该类必须定义为抽象类.
需求
参考代码
//抽象的动物类.
public abstract class Animal {
//抽象方法, 吃.
public abstract void eat();
}
需求
参考代码
略
抽象类中可以有变量, 常量, 构造方法, 抽象方法和非抽象方法.
思考: 既然抽象类不能实例化, 那要构造方法有什么用?
答: 用于子类对象访问父类数据前, 对父类数据进行初始化.
需求
参考代码
略
略.
继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。
所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被训练,只需要这部分猫狗把这些额外功能实现即可。
需求
参考代码
略.
接口中有且只能有常量或者抽象方法, 原因是因为:
注意: 因为接口主要是扩展功能的, 而没有具体存在, 所有接口中是没有构造方法的.
记忆: JDK1.8的时候, 接口中加入了两个新的成员: 静态方法, 默认方法(必须用default修饰).
需求
定义接口Inter, 测试接口中的成员特点.
参考代码
略.
11.6.2 参考代码
略.
略
包(package)就是文件夹, 用来对类进行分类管理的. 例如:
package 包名1.包名2.包名3; //多级包之间用.隔开
注意:
不同包下的类之间的访问,我们发现,每次使用不同包下的类的时候,都需要加包的全路径。比较麻烦。这个时候,java就提供了导包的功能。
import 包名;
需求
参考代码
略.
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。