day06
一、面向对象
1.1 面向过程
回想之前写的代码,我们想要完成某个功能,肯定会先分析这个功能是如何实现的,然后通过代码一步步去实现,而这一步步的代码我们都是亲自参与的,这些代码之间进行相互的调用和协调完成我们想要的功能。这个解决问题的方式用的就是面向过程。
代表性的语言:C语言
1.2 面向对象
我们之前写的代码都是比较简单的,但是随着功能的增多,代码肯定也会相应的增多。这样后期使用和维护会非常麻烦,所以我们必须得想办法解决、简化。这个解决方式就是面向对象。
之前写数组遍历是用for循环来改进的。但要是有10个数组都需要遍历,我们就需要写10个for循环,这样也比较麻烦,所以后面我们用了方法来进行改进。但是对于数组的操作不止一个(还有数组的最值、反转、排序),这些功能我们也用方法进行改进了。我们又知道类中是可以存放方法的,所以我们可以将这些对数组操作的方法放在关于一个数组的类中,以后想要使用这些方法的时候,只需要通过这个类的实例(对象)调用这些方法即可。这种解决问题的方式用的就是面向对象。
例子
吃饭:
面向过程:买菜---择菜---洗菜---炒菜---装盘---吃
面向对象:服务员(点菜)---厨师(做菜)---服务员(上菜)---吃
洗衣服:
面向过程:衣服放盆里---倒水---放洗衣液---搓衣服---晾干
面向对象:全自动洗衣机(洗衣服、脱水)---晾干
1.3 面向对象和面向过程的关系
面向对象是基于面向过程的
1.4 好处
1. 将复杂的问题简单化
2. 更符合人类的思维习惯
3. 将我们由问题的执行者变成问题的指挥者
1.5 面向对象的特征
封装
继承
多态
二、类与对象
如何描述现实中的事物?
属性:一般都是名词。 如:姓名、年龄
行为:一般都是动词。 如:吃、睡
Java语言最基本的单位是类,所以我们使用类来描述现实世界中的事物(现实中的事物用Java中的类描述之后,就可以使用Java来解决现实中的问题了)
成员变量: 相当于现实中的属性 (和之前的局部变量很相似,只不过成员变量是定义在类中方法外的)
成员方法: 相当于现实中的行为 (和之前的方法很相似,只不过可以不用加static修饰了)
package com.ujiuye.oop;
/*
人类:
现实中描述人类:
属性:姓名、年龄
行为:吃、睡
Java中通过类描述人类:
成员变量:姓名、年龄(相当于现实中的属性)
成员方法:吃、睡 (相当于现实中的行为)
*/
/*
人类
*/
public class Person {
//成员变量:姓名、年龄
//姓名
String name;
//年龄
int age;
//成员方法:吃、睡
//吃
public void eat() {
System.out.println("吃饭饭...");
}
//睡
public void sleep() {
System.out.println("睡觉觉...");
}
}
2.1 什么是对象
对象就是类的一个具体表现(实例)
类:
汽车类
对象:
五菱宏光、奔驰、宝马
类:
学生类
对象:
张三、李四
三、如何使用类中的成员
类中的成员(成员变量、成员方法)
使用的前期:得有类中的对象
3.1 创建类的对象
格式:
数据类型 对象名 = new 数据类型();
格式的解释:
数据类型:只能是引用数据类型。(可以是官方存在的(比如:Scanner),也可以是自己定义的(比如:Person))
对象名: 就是一个变量名(准确来说:应该叫做引用),符合变量的命名规范即可。
=: 将new出来内容的地址赋值给左边的引用(对象名)
new: 用来在堆上开辟一个空间
数据类型:同上
(): 构造方法处会讲
3.2 通过对象调用类中的成员变量
对象名.成员变量名;
3.3 通过对象给类中的成员变量赋值
对象名.成员变量名 = 数据;
3.4 通过对象调用类中的成员方法
对象名.成员方法名();
package com.ujiuye.oop;
public class Demo2 {
public static void main(String[] args) {
//1. 创建对象
//格式:数据类型 对象名 = new 数据类型();
Person p = new Person();
//2. 通过对象调用类中的成员变量
//格式:对象名.成员变量名
System.out.println(p.name);
System.out.println(p.age);
System.out.println("--------------");
//3. 通过对象给类中的成员变量赋值
//格式:对象名.成员变量名 = 数据;
p.name = "曹操";
p.age = 50;
System.out.println(p.name);
System.out.println(p.age);
System.out.println("--------------");
//4. 通过对象调用类中的成员方法
//格式:对象名.成员方法名();
p.eat();
p.sleep();
}
}
四、对象的内存图
两个对象的内存图
/*
人类
*/
public class Person {
String name;
int age;
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
//第一个对象p
Person p = new Person();
System.out.println(p.name + "---" + p.age);
p.name = "马化腾";
p.age = 45;
System.out.println(p.name + "---" + p.age);
p.eat();
//第二个对象p2
Person p2 = new Person();
System.out.println(p2.name + "---" + p2.age);
p2.name = "马保国";
p2.age = 60;
System.out.println(p2.name + "---" + p2.age);
p2.eat();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vAJ8YrmJ-1620291010018)(img/image-20210413140921155.png)]
两个引用指向同一个对象
/*
人类
*/
public class Person {
String name;
int age;
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
/*
测试类
*/
public class Demo2 {
public static void main(String[] args) {
//第一个对象(引用)p
Person p = new Person();
System.out.println(p.name + "---" + p.age);
p.name = "马化腾";
p.age = 45;
System.out.println(p.name + "---" + p.age);
p.eat();
//第二个对象(引用)p2
Person p2 = p;
System.out.println(p2.name + "---" + p2.age);
p2.name = "马冬梅";
p2.age = 20;
System.out.println(p2.name + "---" + p2.age);
System.out.println(p.name + "---" + p.age);
p2.eat();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6cYnjuah-1620291010020)(img/image-20210413142433986.png)]
创建对象的过程
1. 将涉及到的类的字节码文件加载到方法区中
2. 定义一个类的引用(通常被称为对象名),用来存储指向类的对象的地址
3. 通过new关键字在堆上创建一个新的对象
4. 将对象的地址赋值给类的引用
五、成员变量和局部变量的区别
局部变量:声明在方法上或者方法内部的变量
成员变量:声明在类中方法外的变量
声明的位置不同:
局部变量:声明在方法上或者方法内部的变量
成员变量:声明在类中方法外的变量.
在内存上的位置不同:
局部变量:栈上
成员变量:堆上
生命周期不同:
局部变量:随着方法的调用而存在,随着方法的调用结束而消失
成员变量:随着对象的创建而存在,随着对象的回收而消失
初始化值的不同:
局部变量:必须得进行初始化才可以使用
成员变量:有默认的初始化值
整数类型 0
小数类型 0.0
布尔类型 false
字符类型 '\u000'
引用数据类型 null
六、封装
隐藏了事物的属性及具体的实现细节,而只对外提供公共的访问方式。
疑问:用private修饰了,是不是就不想让外界访问了。
答:不是。变量定义出来就是让别人使用的,但是不加private修饰的话,访问不安全,有可能会传入一些非法的数据。如果加了private修饰,那么别人使用的时候,就只能通过我们定义的方法来访问变量(因为方法是我们自己定义的,所以安全性有保障)
/*
在给类的成员变量赋值的过程中,出现了一个问题:可以赋值一些非法的数据。
那么如何解决这个问题?
1. 可以通过判断语句解决(如果在合理的范围内就赋值,否则不赋值)
2. 又因为判断语句只能放在方法中,所以我们需要建立一个方法,方法的功能如下:
1. 可以获取一个外界传入的年龄
2. 在方法中判断这个年龄,如果是合法的年龄,则赋值给成员变量age
3. 如果不合法,则不赋值
这个方法定义在哪个类中比较合适?
测试类中和Person类中都可以写这个方法,但是测试类一般是用来做功能测试的,而不是定义功能的。
所以这个判断应该放在Person类中
方法写好了,功能也完善了。但是发现了一个问题:别人还是可以直接使用对象名访问成员变量。这个问题如何解决?
解决方案如下:Java中提供了一个关键字private,被private修饰的变量只能在本类中访问
*/
public class Demo {
public static void main(String[] args) {
Person p = new Person();
p.name = "张三";
// p.age = 200; //age已经被私有了,所以无法访问。
p.setAge(50);
// System.out.println(p.name + "---" + p.age); //age已经被私有了,所以无法访问。
System.out.println(p.name + "---" + p.getAge());
}
}
public class Person {
//成员变量
String name;
private int age;
//判断年龄是否合法的方法,如果合法就赋值
public void setAge(int a){
if(a >= 0 && a <= 130){
age = a;
}
}
//获取年龄的方法
public int getAge(){
return age;
}
//成员方法
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
6.1 好处
1. 提高了代码的安全性
2. 提高了代码的复用性(多次调用)
6.2 private关键字
private关键字可以修饰成员变量及成员方法,被修饰的成员只能在本类中被访问
6.3 getXxx和setXxx方法
被private修饰的成员变量只能在本类中被访问,出了这个类就不能使用了。但是我们又想在本类之外使用怎么办? 可以在本类中定义公共的setXxx方法来给本类私有的成员变量设置值,定义公共的getXxx方法来获取本类私有成员的值(因为方法和私有的成员变量都在同一个类中,所以可以正常访问)
外界虽然不能直接访问本类私有的成员变量,但是可以通过访问本类公共的setXxx和getXxx方法来间接的访问本类的私有成员。
6.4 this关键字
哪个对象调用this,这个方法中的this就代表哪个对象
package com.ujiuye.getsetdemo;
public class Person {
//成员变量
private String name;
private int age;
//getXxx和setXxx方法
public void setName(String name){
/*
变量访问的规律:
1. 一个局部范围内的变量,会首先找局部范围内的定义,如果找到了就使用
2. 如果找不到,就去成员位置去找
*/
this.name = name;
System.out.println("方法中的this:" + this); //第二、四行打印
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p); //第一行打印对象p
p.setName("曹操");
p.setAge(50);
System.out.println(p.getName() + "---" + p.getAge());
Person p2 = new Person();
System.out.println(p2); //第三行打印对象p2
p2.setName("刘备");
p2.setAge(30);
System.out.println(p2.getName() + "---" + p2.getAge());
}
}
/*
运行结果如下图:
*/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PCKGC4ow-1620291010022)(img/image-20210413163820176.png)]
练习:
定义一个手机类:属性(品牌、颜色、价格)行为(打电话、玩游戏)并在测试类中进行测试。
注意:定义手机类的时候要使用所学的this及private改进
package com.ujiuye.thisdemo;
/*
手机类
*/
public class Phone {
//成员变量:品牌、颜色、价格
//品牌
private String brand;
//颜色
private String color;
//价格
private int price;
//getXxx和setXxx方法
public void setBrand(String brand){
this.brand = brand;
}
public String getBrand(){
return brand;
}
public void setColor(String color){
this.color = color;
}
public String getColor(){
return color;
}
public void setPrice(int price){
this.price = price;
}
public int getPrice(){
return price;
}
//成员方法:打电话、玩游戏
//打电话
public void call(){
System.out.println("打电话");
}
//玩游戏
public void playLOL(){
System.out.println("玩游戏");
}
}
public class Demo {
public static void main(String[] args) {
//1. 创建对象
Phone p = new Phone();
//2. 通过对象调用set方法来给成员变量设置值
p.setBrand("Mi");
p.setColor("Black");
p.setPrice(6999);
//3. 通过对象调用get方法来获取成员变量的值
System.out.println(p.getBrand() + "---" + p.getColor() + "---" + p.getPrice());
System.out.println("----------------------");
Phone p2 = new Phone();
p2.setBrand("iphone12 pro max 1T");
p2.setColor("tuhao Gold");
p2.setPrice(22999);
System.out.println(p2.getBrand() + "---" + p2.getColor() + "---" + p2.getPrice());
}
}
/*
运行结果:
Mi---Black---6999
----------------------
iphone12 pro max 1T---tuhao Gold---22999
*/
//3. 通过对象调用get方法来获取成员变量的值
System.out.println(p.getBrand() + “—” + p.getColor() + “—” + p.getPrice());
System.out.println("----------------------");
Phone p2 = new Phone();
p2.setBrand("iphone12 pro max 1T");
p2.setColor("tuhao Gold");
p2.setPrice(22999);
System.out.println(p2.getBrand() + "---" + p2.getColor() + "---" + p2.getPrice());
}
}
/*
运行结果:
Mi—Black—6999
----------------------
iphone12 pro max 1T—tuhao Gold—22999
*/