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);
}
}