终于到了java的关键地方了,面向对象。不好理解,但是必须要理解。
现实世界中,随处可见的一种事物就是对象,对象是存在的实体,如人类、书桌、计算机、高楼大厦等。面向对象实质上就是对现实世界的对象进行建模操作。
一、面向对象概述
概念
所谓的面向对象是一种编程思想,通过这种思想可以把生活中的复杂事情变得简单化,从原来的执行者变成了指挥者,面向对象是基于面向过程而言的。
我们经常说的面向对象的编程实现(OOP,Object Oriented Programming)
- 面向过程强调的是过程,例如:
1、打开冰箱 2、把大象放进去 3、关上冰箱 - 面向对象强调结果,例如:
饿了,去平台点餐,这个动作就是面向对象。你没有去市场买菜洗菜做饭。。。只要有app就可以了。
特征:
- 封装
- 继承
- 多态
二、类和对象
1、概念
- 类:
① Java语言最基本单位就是类,类似于类型;
② 类是一类事物的抽象;
③ 可以理解为模板或者设计图纸; - 对象:
每个对象具有三个特点:对象的状态,对象的行为和对象的标识;
① 对象的状态用来描述对象的基本特征。
② 对象的行为用来描述对象的功能。
③ 对象的标识是指对象在内存中都有一个唯一的地址用来和其他对象区分开来。
④ 类是一类事物的抽象,对象是具体的实现。
2、两者的关系
- 计算机语言是用来描述现实世界的,通过
属性+行为
- 通过类来描述事物,把事物的属性当做成员变量,把行为当做成员方法。
分析手机事物:
- 属性:颜色,尺寸,品牌,价格。。。
- 方法:打电话,发短信,听音乐。。。。
- 类:手机类,抽取相同的属性和行为
- 对象:可以按照模板生产很多个手机,比如1号手机对象,包含特有的成员变量和成员方法
3、类和对象的创建和使用
3.1 单个类和对象的创建与使用
通过class关键字来创建类,通过new关键字创建对象
package cn.tedu.hello.day06;
public class Test_Object1 {
public static void main(String[] args) {
// 4、创建对象测试
//new Phone();//匿名对象
//5、通过new关键字创建对象.引用类型的变量p就保存了一个地址值
Phone phone = new Phone();
//p对象能调用模板里面的属性和行为吗?
phone.call();
phone.message();
phone.music();
//6、设置属性的值
phone.color = "red";
phone.size = 7;
phone.pinpai = "小米";
phone.price = 2999.0;
//7、打印属性的值
System.out.println(phone.color);
System.out.println(phone.size);
System.out.println(phone.pinpai);
System.out.println(phone.price);
}
}
//1、通过class关键字创建类,用来描事物:属性+行为
class Phone {
//2、属性:颜色、尺寸、品牌、价格 -- 用成员变量/成员属性 描述
String color;
int size;
String pinpai;
double price;
//3、行为:打电话、发短信、听音乐 -- 用成员方法 描述
//方法修饰符 方法返回值 方法名(参数列表){方法体}
public void call() {
System.out.println("正在通话中...");
}
public void message() {
System.out.println("正在发送...");
}
public void music() {
System.out.println("正在播放...");
}
}
3.2 对象在内存中的存储
重点关注堆和栈:
- 一般来讲局部变量存在栈中,方法执行完毕内存就被释放;
- 对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放;
- 每个堆内存的元素都有地址值;
- 对象中的属性都是有默认值的;
3.3 单一对象内存图
执行过程:
- 在栈内存,开辟空间存放局部变量/引用变量p;
- 在栈内存中,开辟空间,存放对象,完成初始化;
- 给堆内存中元素,分配一个唯一的标志------地址值,交给p去保存;
- p.color = "red;p.size = 7;等就去堆内存中找唯一的地址值,找到Phone对象,并对其属性进行修改赋值。
- p.call();等方法,就去堆内存中找唯一的地址值,找到Phone对象,执行Phone对象的方法。
3.4 多个类和对象的创建与使用
创建Car类
package cn.tedu.hello.day07;
//1、创建汽车类
class Car {
//成员变量/成员属性 -- 特征
String color;
String pinpai;
String model;
double price;
//成员方法 -- 行为
public void run() {
System.out.println("正在启动...");
}
public void fly() {
System.out.println("正在飞...");
}
}
测试多个对象
package cn.tedu.hello.day07;
//这个类用来测试多个对象
public class Test_Object {
public static void main(String[] args) {
//2、创建汽车对象测试(有名对象)
Car car = new Car();
//匿名对象也可以,但是匿名对象一次只能做一件事
// new Car().run();
// new Car().fly();
//调用模板里面的功能
car.run();
car.fly();
//设置默认值
car.color = "white";
car.model = "H6";
car.pinpai = "哈弗";
car.price = 180000;
System.err.println(car.color);
System.err.println(car.model);
System.err.println(car.pinpai);
System.err.println(car.price);
System.out.println();
//创建多个对象
Car car2 = new Car();
//设置默认值
car.color = "black";
car.model = "H9";
car.pinpai = "哈弗";
car.price = 200000;
System.err.println("c2="+car.color);
System.err.println("c2="+car.model);
System.err.println("c2="+car.pinpai);
System.err.println("c2="+car.price);
System.out.println();
//把car2的属性传递给car3
//把car2记录着的内存地址,交给car3保存,都是引用类型的变量,所以都存地址
//使用的和car2是一个属性
Car car3 = car2;
System.err.println("c3="+car.color);
System.err.println("c3="+car.model);
System.err.println("c3="+car.pinpai);
System.err.println("c3="+car.price);
}
}
3.5 多个对象内存图
三、封装
1、概述
封装是指隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式。
封装的好处:
- 提高安全性
- 提高重用性
2、private关键字
是一个权限修饰符,用于修饰成员变量和成员函数,被私有化的成员只能在本类中访问。
想要修改只能,对外提供公共的,get和set方法。
3、练习封装
仔细阅读代码,慢慢领会面向对象的好处;
package cn.tedu.privatedemo;
public class Test_Student {
//测试封装
public static void main(String[] args) {
//创建学生对象
Student student = new Student();
//调用学生类的方法
//student.study();//私有方法,除了本类,外界无法访问
student.game();//调用game方法的同时,间接调用study方法
// student.age = 20;
student.setAge(13);//私有变量的设置,set方法
student.name = "Daniel";
student.subject = "数学";
System.out.println(student.getAge());//用get方法获取
System.out.println(student.name);
System.out.println(student.subject);
}
}
学生类
package cn.tedu.privatedemo;
//创建一个学生类:属性+行为
class Student {
//修饰符不写,那就是默认default,但是写上就报错
// default int age;
//1、通过private关键字,实现封装
//2、如果被private私有化,只能在本类中访问,其他类看不到,也用不了
private int age;
// int age;
String name;
String subject;
//创建get/set方法,给外界提供全局的访问点
//set设置值,get获取值
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//创建方法
//3、private可以修饰成员变量或者成员方法
//private void study() {}
// public void study() {
// System.out.println("正在学习...");
// }
private void study() {
System.out.println("正在学习...");
}
public void game() {
study();//4、study()方法被私有化,外界无法直接访问,但是可以间接访问
System.out.println("正在吃鸡..");
}
}
知识拓展:
1、创建对象的流程
Person p = new Person();//短短这行代码发生了很多事情
- 把Person.class文件加载进内存
- 在栈内存中,开辟空间,存放变量p
- 在堆内存中,开辟空间,存放Person对象
- 对成员变量进行默认的初始化
- 对成员变量进行显示初始化
- 执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
- 堆内存完成
- 把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值
2、匿名对象
没有名字的对象,是对象的简化表示形式。
使用场景:
当被调用的对象只调用一次时(多次会创建多个对象浪费内存)
Demo d = new Demo();
d.sleep();
d.game();
//这个d就是对象的名字。
也可以写成:
new Demo().show();//创建了一个对象调方法
new Demo().game();//又创建了一个对象调方法
四、构造方法
1、概念
- 构造方法是一种特殊的方法,它是一个与类同名且返回值类型为同名类类型的方法。
- 对象的创建就是通过构造方法来完成,其功能主要是完成对象的创建或者对象的初始化。
- 当类实例化一个对象时会自动调用构造方法。
- 构造方法和其他方法一样也可以重载。
2、创建形式
- 可以创建无参的,也可以创建有参的
修饰符 类名([参数列表]){
方法体;
}
3、构造方法创建对象
仔细阅读代码,重点分析笔记混合在代码中,身临其境更有感觉;
① 创建测试构造方法的类;
package cn.tedu.constructor;
//这个类用来测试构造方法
public class Test_Cons {
public static void main(String[] args) {
//创建person对象
//3、无参创建对象,底层会自动调用--无参的构造方法
Person p = new Person();
//5、触发含参构造
Person p2 = new Person("Daniel");
}
}
② 创建一个Person类;
package cn.tedu.constructor;
//创建person类
public class Person {
//1、提供构造方法:修饰符 类名([参数列表]){方法体}
//2、默认会存在无参构造方法,前提是没有提供含参构造。
//如果类中提供了含参构造,无参构造就真没了
public Person() {
System.out.println("无参构造方法");
}
//4、构造方法的重载形式:方法名相同+参数列表不同
public Person(String name) {
System.out.println("含参构造方法" + name);
}
}
4、构造方法赋值
① 创建测试方法
package cn.tedu.constructor;
//这个类用来测试构造方法
public class Test_Animal {
public static void main(String[] args) {
//3、创建对象测试
Animal a = new Animal();//自动触发无参构造
Animal a2 = new Animal("憨憨");//触发含参构造
}
}
② 创建Animal类
package cn.tedu.constructor;
public class Animal {
//创建成员变量
String name ;
//提供构造方法
//修饰符 类名([参数列表]){}
public Animal() {}//1、空着也得摆好,方便外界创建对象
//2、重载形式的构造方法
public Animal(String n) {//n是形参,也是局部变量
//n是局部变量
System.out.println("含参构造" + n);
//4、拿着局部变量 n 给成员变量 name 赋值
name = n;
System.out.println(name);//憨憨
}
}
切记:无参构造函数就算是摆着好看,也要摆在代码里面
五、构造代码块和局部代码块
1、构造代码块
- 位置:在类里,方法外的代码块
- 作用:提取构造方法的共性
- 优先级:构造代码块 > 构造方法
2、局部代码块
- 位置:在方法里面的代码块
- 作用:控制变量的作用范围,出了括号就失效
☆☆:变量的范围越小越好,成员变量会有线程安全问题 - 优先级:局部代码块顺序执行
总结:执行顺序:构造代码块是最优先的,局部代码块顺序执行
3、测试类
① 创建测试类
package cn.tedu.block;
//测试代码块的使用
public class Test_Block {
public static void main(String[] args) {
//1、在创建对象时做了两件事:执行了代码块 + 构造方法
//2、一定会先触发对应的构造方法。
//3、如果有构造代码块,执行顺序:构造代码块 > 构造方法 > 局部代码块
Teacher teacher = new Teacher();//无参
Teacher teacher2 = new Teacher("Daniel");//含参
//6、触发局部代码块
teacher.show();
}
}
② 创建Teacher类
package cn.tedu.block;
//创建类
public class Teacher {
//构造代码块
//1、位置:如果在类里方法外,是构造代码块
//4、通常构造代码块用于 提取 构造方法的共性,提高了代码的复用性
String country;
{
//提取了共性,只不过,变量的作用范围只在代码块中有效
country = "中国人";
System.out.println("构造代码块");
}
//无参构造
public Teacher() {
System.out.println("无参构造方法" + country);
}
//含参构造
public Teacher(String name) {
System.out.println("重载的构造方法" + name + country);
}
//5、局部代码块:位置是在方法里,作用是控制变量的作用范围
public void show() {
{
int sum = 10;
System.out.println("局部代码块" + sum);
}
//只能在自己的变量范围内使用
//System.out.println(sum);
}
}
问题拓展:
1、构造代码块什么时候触发?-------- 在创建对象的时候触发
2、局部代码块什么时候触发?-------- 在方法被调用时
【下篇预告】
- this关键字
- 继承的使用
- super关键字
- 方法的重写
- 继承中的用法
- …