day06
1. 面向对象思想
- 面向对象 : 就是一种编程思想, 编程思维
- 面向过程与面向对象比较:
a : 面向过程 : 有一个需求要实现, 我需要如何实现, 强调需求实现过程, 实现步骤
b : 面向对象 : 有一个需求要实现, 让谁去实现
举例 : 打扫卫生需求实现
a : 面向过程思维 : 想象自己如何能够将打扫卫生过程实现, 摆桌子, 摆凳子, 扫地, 拖地, 关空调, 关门
b : 面向对象思维 : 让小红打扫卫生
面向过程是面向对象的基础, 面向对象基于面向过程
- 面向对象优势:
1) 更符合人类的思考习惯
2) 简化代码的设计难度
3) 由实施者变成指挥者
- 面向对象特征:
1) 封装
2) 继承
3) 多态
2. 类与对象
2.1 类与对象的比较
- 类 : 对于事物的抽象描述, 抽象表现形式
举例 : 玩具模型, 有两只眼睛, 一张嘴巴, 能说话
- 对象 : 对于事物具体表现形式
举例 : 葫芦娃, 就是对于玩具模型事物的具体表现形式
2.2 类的组成
- 类的组成 : 类是属性和行为的集合
a : 属性, 表示对于事物的特征描述, 将事物具有的属性以变量形式定义, 只不过需要将这个变量定义在类中方法外的位置上, 称为成员变量或者全局变量
b : 行为, 就是方法功能的定义
修饰符 返回值类型 方法名(参数列表){
}
注意 : 前面的代码,方法的修饰符写成public static, 现在方法修饰符可以直接使用public, 暂且不需要写static
举例 : 人类Person
属性 : 姓名, 年龄
行为 : 吃饭, 睡觉...
代码
package com.ujiuye.object; public class Person { // 1. 定义出成员变量, 表示Person人类的属性(特征) // 数据类型 变量名 = 变量值; // 1) 姓名 String name = "张三"; // 2) 年龄, 通常类中的成员变量一般不给值 // 类型中的成员变量, 定义的时候可以不赋值, JVM虚拟机会给每一个成员变量 // 进行一个默认的赋初值动作 int age; // 默认值为0 // 2. 定义出Person人类具有方法功能 public void eat() { System.out.println(name+"一天吃三顿饭"); } public void sleep() { System.out.println(name + "一共睡觉" + age + "年"); } } |
2.3 对象的创建和使用
- 创建对象语法结构:
数据类型 变量名 = new 数据类型();
类名 对象名 = new 类名();
- 说明: 类名 对象名 = new 类名();
1) 类名 : 表示对象是属于什么数据类型, 自定义类, JDK提供的核心类库,都是引用数据类型
2) 对象名 : 变量名, 符合标识符组成规范, 小驼峰原则, 第一个英文单词全小写, 从第二个英文单词开始首字母大写 getSum
3) = : 赋值运算符, 将对象在内存中占有的空间地址赋值给等号左边的变量名
4) new : 关键字, 表示新建概念, 为对象在内存中开辟空间存储对象中的数据
5) 类名 : 与前面的类名保持一致
6) () : 表示构造方法调用(铺垫)
举例 : Person p = new Person();
- 使用对象:
对象名.属性 = 值; // 给对象中的成员变量赋值
变量 = 对象名.属性; // 获取对象中的成员变量值
对象名.方法名(实际参数); // 调用对象中的方法功能
代码
package com.ujiuye.object; public class TestPerson { public static void main(String[] args) { // 1. 创建出一个Person类型对象 // 类名 对象名 = new 类名(); Person p = new Person(); // 2. 使用对象中成员变量 System.out.println(p.name);// 张三 System.out.println(p.age);// 0 Person p1 = new Person(); p1.name = "小红"; p1.age = 20; System.out.println(p1.name); System.out.println(p1.age); // 3. 对象中的方法调用 p1.eat(); p1.sleep(); } } |
案例 : 定义一个小汽车类Car, 小汽车具有属性 : 轮胎个数(num), 和颜色(color), 小汽车具有run功能, 要求run方法运行时, 能将小汽车的属性描述出来
代码
package com.ujiuye.object; public class Car { // 轮胎个数(num) int num; // 颜色(color) String color; public void run() { System.out.println(color+"颜色的小汽车,有" + num + "个轮子,正在马路上跑"); } } |
package com.ujiuye.object; public class TestCar { public static void main(String[] args) { // 1. 创建出一个Car对象 Car c = new Car(); System.out.println(c); c.num = 4; c.color = "红"; c.run(); Car c1 = new Car(); c1.num = 8; c1.color = "绿"; c1.run(); } } |
2.4 创建对象在内存中的理解
JVM虚拟机将其在内存中所占有空间区域进行划分, 分成了5块空间, 每块不同的空间对于java代码有不同的执行作用
- 栈内存 : 方法调用进栈内存中运行, 方法运行完毕, 弹出栈内存, 释放空间
- 堆内存 : 引用数据类型创建对象在堆内存中开辟空间, 当对象再无可用之处, 堆内存空间需要释放掉
- 方法区(数据共享) : 类型的.class字节码文件存储在方法区中, 方法区中存储静态成员, 常量池也存储在方法区中
2.4.1 两个对象在内存中的存储
- 先将Car.class字节码文件加载进方法区中, 进入内存一次即可让Car类型任意使用
- main方法需要运行, 于是进入到栈内存中运行
- main方法中第一句代码 : Car c = new Car();
a : 通过new关键字在堆内存中开辟空间, 存储Car对象中的成员变量
b : JVM虚拟机,将Car对象中的所有非静态成员变量加载进堆内存中, 为每一个成员进行默认的赋初值动作
int--->0
double--->0.0
char--->’ ’
boolean---> false
引用数据类型--->null
c : 将对象在堆内存中空间赋值, 赋值到栈内存中的对象引用处
- 使用对象名.调用方法, 方法进栈内存运行, 方法会记录调用的对象地址, 为了找到对应的变量使用的出处
- 引用数据类型,每次通过new关键字创建对象, 每次都是在堆内存中创建新的地址空间
2.4.2 两个引用指向同一块内存
代码
package com.ujiuye.object; public class Car { // 轮胎个数(num) int num; // 颜色(color) String color; public void run() { System.out.println(color+"颜色的小汽车,有" + num + "个轮子,正在马路上跑"); } } |
package com.ujiuye.object; public class TestCar { public static void main(String[] args) { // 1. 创建出一个Car对象 Car c = new Car(); System.out.println(c); c.num = 4; c.color = "红"; c.run(); Car c1 = new Car(); System.out.println(c1+"----"); c1.num = 8; c1.color = "绿"; c1.run(); // c1是一个对象引用, c2也是一个对象引用, 现在c1和c2两个引用指向同一块内存空间 Car c2 = c1;// 表示赋值, 将c1的地址值赋值给c2, 证明c1和c2指向同一块内存空间 System.out.println(c2 + "-----"); System.out.println(c2.color);// 绿 } } |
2.5 匿名对象
- 匿名对象 : 没有名字的对象
a : 有名对象 Person p = new Person(); // p表示Person类型对象(对象名)
b : 匿名对象 new Person(); 匿名对象一样在堆内存中开辟空间, JVM虚拟机一样将对象非静态成员变量加载进内存, 默认赋初值
- 匿名对象如何使用:
a : 匿名对象只能使用一次, new Person().调用属性或者调用方法功能;
b : 虽然匿名对象只能使用一次, 但是如果一个对象无法再使用, 那么这个对象在堆内存中占有的空间很快就会变成垃圾, 等待JVM虚拟机垃圾回收机制将空间清理掉,于是匿名对象在内存中占有时间很短, 因此变相优化内存的使用
c : 如果某一个类型中的属性或者方法, 只调用一次, 那么可以使用匿名对象实现
注意 : 通常不会使用匿名对象给成员变量进行赋值, 因为赋值之后其值无法保存, 因此赋值就没有意义
代码
package com.ujiuye.object; public class Demo01_匿名对象 { public static void main(String[] args) { //引用数据类型,每次通过new关键字创建对象, 每次都是在堆内存中创建新的地址空间 // 1. 定义出一个匿名对象 new Car().run(); System.out.println(new Car().color); // 2. 通常不会使用匿名对象给成员变量进行赋值 new Car().num = 8; System.out.println(new Car().num); Car c1 = new Car(); Car c2 = new Car(); } } |
2.6 基本数据类型和引用数据类型作为方法参数
- 基本数据类型作为方法参数案例1
2.基本数据类型作为方法参数案例2
3.引用:
2.7 成员变量和局部变量的比较
- 定义位置不同:
a : 成员变量, 定义在类中,方法外
b : 局部变量, 定义在方法内部的变量,或者是定义在方法的参数列表上的变量
- 内存中存储的位置不同:
a : 成员变量, 跟着对象存储在堆内存中
b : 局部变量, 跟着方法存储在栈内存中
- 生命周期不同:
a : 成员变量, 对象创建时成员变量跟着进入内存出现, 当对象再无使用地方, 对象内存空间变成垃圾,成员变量生命也随之结束
b : 局部变量, 方法调用局部变量进入内存,当方法运行完毕, 方法弹栈死亡, 局部变量跟着方法消亡
- JVM虚拟机初始化值不同
a : 成员变量, 当创建对象时, JVM虚拟机自动给所有非静态成员变量进行默认的赋初值
b : 局部变量, JVM不会默认赋初值, 于是定义在方法中的变量, 不赋值不能使用
3. 封装
3.1 封装的概述
- 封装面向对象中的一大特征
- 封装 : 隐藏事物属性或者实现细节, 对外提供公共访问方式
- 封装在java代码中的体现形式, 非常多种, 举例 : 方法本身就是一种封装概念,类本身也是一种封装概念...
- 封装优势:
1) 因为隐藏事物的实现细节, 提高代码的安全性
2) 提高代码的复用性
3.2 private关键字
- private : 关键字, 表示私有的, 私密的
- private关键字修饰:
1) 修饰成员变量(最常见使用方式, 今天掌握第一种使用)
2) 修饰方法
3) 构造方法
4) 内部类
- 使用private修饰后的效果 : 只能在当前类型中使用, 出了当前类之外的所有类型,不能直接使用private修饰的成员
- private关键字的使用只是封装的其中一种表现方式
案例 : 定义Student学生类, 属性 : 姓名, 年龄, 学号, 功能 : 学习study
代码
package com.ujiuye.privatedemo; public class Student { // 属性 : 姓名, 年龄, 学号 String name; // age只能在Student类中使用 private int age; String id; // 定义出学习功能 public void study() { System.out.println(name + "学生在学习"); } } |
package com.ujiuye.privatedemo; public class TestStudent { public static void main(String[] args) { // 1. 定义出一个学生对象 Student s = new Student(); // 问题 : -20的年龄不安全的数据,于是在Student中私有修饰 // 因为age使用private修饰, 外类中不能直接操作使用 // s.age = -20; // System.out.println(s.age); s.age = 25; s.name = "张三"; s.id = "001"; s.study(); } } |
3.3 Setter和Getter方法
- 给私有成员变量提供对外的公共的访问方式
- Setter方法 : 给私有成员变量赋值的方法功能, 外界无法直接访问私有成员, 只能通过set方法对私有变量进行赋值, 因此set方法中, 逻辑如何要求进行赋值,只能如何赋值, 提高代码的安全性
- Getter 方法 : 获取私有成员变量的值
- 实际开发中, 实体类(真真正正存在的事物)中的属性(成员变量),通常都会使用private进行私有修饰, 为了不让外界直接给成员进行赋值, 从而提高代码的安全性
代码
package com.ujiuye.privatedemo; public class Student { // 属性 : 姓名, 年龄, 学号 String name; // age只能在Student类中使用 private int age; String id; // 为私有成员变量age提供对外的公共的访问方式 // 1) Setter方法 : 给成员变量age赋值 public void setAge(int a) { if(a > 0 && a <= 150) { age = a; }else { System.out.println("输入的年龄有误,使用默认年龄0"); } } // 2) Getter 方法 : 获取成员变量age的值 public int getAge() { return age; } // 定义出学习功能 public void study() { System.out.println(name + "学生在学习"); } } |
package com.ujiuye.privatedemo; public class TestStudent { public static void main(String[] args) { // 1. 定义出一个学生对象 Student s = new Student(); // 问题 : -20的年龄不安全的数据 // 因为age使用private修饰, 外类中不能直接操作使用 // s.age = -20; // System.out.println(s.age); // s.age = 25; /*s.setAge(-90); System.out.println(s.getAge());*/ s.setAge(27); System.out.println(s.getAge()); s.name = "张三"; s.id = "001"; s.study(); } } |
3.4 变量访问原则和this关键字
- 变量访问就近原则 :
使用一个变量时, 优先寻找最近的一次变量定义使用, 如果局部变量有定义,优先使用局部变量, 如果没有局部变量定义, 使用成员变量
- this关键字 : 表示当前类型对象的使用, this关键字表示一个对象
功能1 : 主要可以进行成员变量和局部变量重名问题的区分
带有this关键字的变量表示成员变量的使用
- 一个类,可以创建出无数对象, 每次new都是一个新对象, this关键字到底可以表示哪一个对象
哪个对象调用了带有this的方法, 那么this关键字就代码哪个对象
代码
package com.ujiuye.privatedemo; public class Demo01_变量访问原则 { // 成员变量 int i = 10; public void useI() { // 局部变量 int i = 99; // 2. i值的使用利用了变量的就近访问原则 System.out.println(i);// 99 // 3. 调用重名的成员变量i System.out.println(this.i);// 10 System.out.println(this + "this-------------"); } public static void main(String[] args) { // 1. 创建出一个当前类型对象 Demo01_变量访问原则 demo = new Demo01_变量访问原则(); System.out.println(demo.i);// 10 // 哪个对象调用了带有this的方法, 那么this关键字就代码哪个对象 demo.useI();// 99 System.out.println(demo+"----"); Demo01_变量访问原则 demo1 = new Demo01_变量访问原则(); System.out.println(demo1); demo1.useI(); } } |
3.5 构造方法
- 构造方法 : 构造器, 构造函数, 使用英文单词Constructor 表示
- Person p = new Person();
对象创建的过程中, ()表示构造方法的调用
构造方法主要功能就是为了给对象的成员变量进行赋值, 当创建对象时, JVM虚拟机主动调用构造方法, 当构造执行完, 对象也创建完毕, 对象中成员变量有值
- 构造方法的语法结构:
修饰符 构造方法名(参数列表){
// 给成员变量进行赋值;
}
- 说明:
1) 修饰符 : 通常使用public公共修饰
2) 构造方法没有返回值类型, 连void都不写
3) 构造方法名 : 必须和类名一致
4) 因为构造方法没有返回值类型, 所以不需要写return ,如果一定要写return;
- 构造方法运行机制:
1) 每次创建对象, JVM虚拟机主动调用指定构造方法一次
2) 构造方法无法通过对象名.主动调用
代码
package com.ujiuye.constructor; public class ConstructorClass { private String name; private int age;
// 定义出构造方法 /* 修饰符 构造方法名(参数列表){ // 给成员变量进行赋值; }*/ public ConstructorClass(String name, int age) { this.name = name; this.age = age; }
/* public ConstructorClass() { System.out.println("我是构造,执行了"); }*/
// alt + shift + s : 快捷键, 可以到里面选择需要生成的代码, 包括set和get 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; } } |
package com.ujiuye.constructor; public class TestCon { public static void main(String[] args) { // ConstructorClass(): 表示调用ConstructorClass()空参数构造 // ConstructorClass cc = new ConstructorClass(); // 构造方法调用需要传递实际参数 ConstructorClass cc1 = new ConstructorClass("张三",20); System.out.println(cc1.getName()); System.out.println(cc1.getAge()); // 构造方法不能主动调用, 只能依靠每次创建对象JVM虚拟机主动调一次 // cc1.ConstructorClass("张三",20); } } |