面向对象
😀day13
8.1. 认识面向过程
c语言 面向过程
c++ 一半面向对象 一半面向过程
java 完全面向对象
面向过程(耦合度高,可扩展性差):注重功能的步骤以及整个过程一体机,某个零部件坏了,所有的都坏了。
缺点:面向过程最主要是每一步与每一步的因果关系,假设其中任何一个因果关系出现问题(错 误),此时
整个系统的运转都会出现问题。(代码和代码之间的耦合度太高,扩展力太差。)
优点:对于小型项目(功能),采用面向过程的方式进行开发,效率较高耦合度:就是粘连程度。
8.2. 认识面向对象
面向对象(耦合度底,可扩展性高):关注度在对象,更符合人类的组装电脑,某个零件坏了,只需要更换那某个零件。采用面向对象开发,更符合人类的思维方式
- 采用面向对象的方式贯穿整个系统的话,涉及到三个术语:
OOA面向对象分析
OOD面向对象设计
OOP面向对象编程
整个软件开发的过程,都是采用OO进行贯穿的。
实现一个软件的过程:分析(A) --> 设计(D) --> 编程(P)
8.3. 面向对象三大特征
封装 继承 多态
任何一个面向对象的编程语言都包括这三个特征
8.4. 类和对象
8.4.1. 类
- 什么是类:类实际上在现实世界当中是不存在的,是一个抽象的概念。类就是是一个模板,通过一个 类,是可以创建N多个对象的。
- java中所有的“类”都属于引用数据类型。
8.4.2. 对象
- 什么是对象:对象是实际存在的个体。(真实存在的个体)
- 在java语言中,要想得到“对象”,必须先定义“类”,“对象”是通过“类”这个模板创造出来的。
- 这几个术语你需要自己能够阐述出来:
- 类:不存在的,人类大脑思考总结一个模板(这个模板当中描述了共同特征。)
- 对象:实际存在的个体。
- 实例:对象还有另一个名字叫做实例。
- 实例化:通过类这个模板创建对象的过程,叫做:实例化。
- 抽象:多个对象具有共同特征,进行思考总结抽取共同特征的过程。
类 --【实例化】--> 对象(实例)
对象 --【抽象】--> 类 - 类 = 属性 + 方法
属性来源于:状态 n 属性其实就是成员变量 方法来源于:动作v
😸思考:“java软件工程师”在开发中起到的一个作用是什么?
- 软件开发既然是为了解决现实世界当中的问题,那么首先java软件必须能够模拟现实世界。
- 其实软件是一个虚拟的世界。这个虚拟的世界需要和现实世界一一对应,这才叫模拟。
8.4.3. 类的定义
- 语法格式:
[修饰符列表] class 类名 {
//类体 = 属性 + 方法
// 属性在代码上以变量的形式存在(描述状态),属性其实就是变量。
// 方法描述动作/行为
}
- 属性对应的是“数据”,数据在程序中只能放到变量中。属性其实就是对象级别的变量。
- 变量根据出现位置进行划分:
方法体当中声明的变量:局部变量。
方法体外声明的变量:成员变量。(这里的成员变量就是属性)
8.5. 编译的过程
第一种方式:
javac XueSheng.java javac XueShengTest.java
第二种方式:
java XueShengTest.java jdk14的新特性
第三种方式:
javac *.java
8.6. 对象的创建
语法级别上是怎么完成对象创建: 类名 变量名 = new 类名();这样就完成了对象的创建。
new是一个运算符。专门负责对象的创建。
public class XueSheng{ // 这个程序编译之后,会生成XueSheng.class字节码文件。
// 属性
// 学号(成员变量)
int xueHao;
// 姓名
String xingMing;
// 年龄
int nianLing;
// 性别
boolean xingBie;
// 住址
String zhuZhi;
}
public class XueShengTest{
public static void main(String[] args){
int i = 100;
System.out.println("i =" + i);
// 在这里可以访问XueSheng类吗?
// 当然可以。
/*
创建对象的语法是什么? new 类名();
目前死记硬背,先记住。后面你就理解了。
XueSheng s1 = new XueSheng();
和
int i = 100;
解释一下:i是变量名
int是变量的数据类型
100是具体的数据。
s1是变量名(s1不能叫做对象。s1只是一个变量名字。)
XueSheng是变量s1的数据类型(引用数据类型)
new XueSheng() 这是一个对象。(学生类创建出来的学生对象。)
数据类型包括两种:
基本数据类型:byte short int long float double boolean char
引用数据类型:String、XueSheng.....
java中所有的“类”都属于引用数据类型。
*/
XueSheng s1 = new XueSheng(); // 和 int i = 10;一个道理。
// 再通过该类创建一个全新的对象
XueSheng s2 = new XueSheng();
// 再创建一个呢?
XueSheng xsh = new XueSheng();
// 以上的这个程序就相当于通过XueSheng类实例化了3个XueSheng对象。
// 创建对象的个数没有限制,可以随意。只要有模板类就行。
// 3个对象都属于学生类型。
}
}
- 什么是实例变量?
对象又被称为实例。
实例变量实际上就是:对象级别的变量。
成员变量也叫实例变量。
- 对象和引用的区别
对象是通过new出来的,在堆内存中存储。
引用是:但凡是变量,并且该变量中保存了内存地址指向了堆内存当中的对象的。
- 对象级的变量(实例变量)的调用 引用.实例变量 ;
- 实例变量的赋值
引用.实例变量 = ;
通过“=”赋值的方式将内存中实例变量的值修改一下。 - 实例变量的访问
先创建对象,然后""引用."的方式访问。
8.7. 对象的使用
public class StudentTest{
public static void main(String[] args){
//局部变量,错误: 可能尚未初始化变量k
/*
int k;
System.out.println(k);
*/
/ 创建学生对象1
// s1属于局部变量吗?当然是。
// s1这个局部变量叫做引用
Student s1 = new Student();
// 怎么访问实例变量?
// 语法:引用.实例变量名
System.out.println(s1.no);
System.out.println(s1.name);
System.out.println(s1.age);
System.out.println(s1.sex);
System.out.println(s1.addr);
// 程序执行到此处我可以修改s1这个学生的学号吗?
// 通过“
=
”赋值的方式将内存中实例变量的值修改一下。
s1.no = 110;
s1.name =
"张三";
s1.age = 20;
s1.sex = true;
s1.addr =
"深圳宝安区";
System.out.println("学号=
" + s1.no);
System.out.println("姓名=
" + s1.name);
System.out.println("年龄=
" + s1.age);
System.out.println("性别=
" + s1.sex);
System.out.println("住址=
" + s1.addr);
}
public static void method(){
// i s1 s2都是main方法中的局部变量,在这里是无法访问的。
/*
System.out.println(i);
System.out.println(s1);
*/
}
}
- Student s1 = new Student();
- s1属于局部变量 ,叫做引用。
- s1是变量名
- Student是数据类型(引用数据类型)
- new Student() 这是一个对象(学生类创建出来的学生对象。)
8.8 对象和引用
- jvm内存执行图
- java中没有指针概念,没法直接使用堆内存
- 将堆内存中对应的对象地址复制一份,赋值给s1变量,实现间接调用
- 引用和对象的区分:
引用是存储对象地址的一个变量,引用不一定是局部变量
对象是堆里new出来的。成员变量里面包含实例变量
- 此图中的代码只是为了方便理解,画内存图是应没有代码,只有数据。
- 引用 指向对象的过程 在c语言里面叫指针。
8.9. 成员变量的默认值
注意:对于成员变量来说,没有手动赋值时,系统默认赋值
- 引用数据类型是null。
- null是一个java关键字,全部小写,表示空。是引用类型的默认值。byte、short、int是0。
- long 是 0L
- float 是 0f double是0.0
- Boolean 是 false
- char是 \u0000
系统赋的默认值会接近与0
8.10. JVM内存图复习
- 注意:只要是方法,不管静态方法、实例方法、构造方法,它们在运行的时候都会在栈内存压栈。
8.11. Homework
题目1:根据程序画执行内存图
答案:
只有地址指向对象,没有对象指向地址。
题目二:难度较大 画程序执行内存图 并完成思考题
思考题:
答案:Address.u.city;
正确答案:u.addr.city
拆分代码:
内存图:
9. 面向对象 (二)
💡day 14
9.1. 内存图 (重要)
9.1.1. 画内存图注意事项
- 不要在内存图体现代码,应该体现数据
- 画图时,应分析代码。根据代码一行一行的去画。
- 引用的箭头永远指向对象。
9.1.2. HomeWork1
画内存图
// 把这个内存图画出来。
一定要按照程序的执行顺序一步一步画。
public class T{
A o1; // 成员变量中的实例变量。必须先创建对象,通过“引用”来访问。
public static void main(String[] args){
D d = new D();
C c = new C();
B b = new B();
A a = new A();
T t = new T();
//这里不写代码会出现 NullPointerException 异常。(空指针异常。)
c.o4 = d;
b.o3 = c;
a.o2 = b;
t.o1 = a;
// 编写代码通过 t 来访问 d 中的 i
//System.out.println(T.a); //错误的。
System.out.println(t.o1.o2.o3.o4.i);
}
}
class A{
B o2;
}
class B{
C o3;
}
class C{
D o4;
}
class D{
int i;
}
- 为什么要画内存图(非常重要)?
第一:有了内存图,程序不运行,我也知道结果。(可以推算出结果)
第二:有了内存图,有助于你调试程序。
9.2. 空指针异常( NullPointerException )
- 关于垃圾回收器:GC机制
在java语言中,垃圾回收器主要针对的是堆内存。当一个java对象没有任何引用指向该对象 的时候,GC会考虑将该垃圾数据释放回收掉。
- 出现空指针异常的前提条件是?
"空引用"访问实例【对象相关】相关的数据时,都会出现空指针异常。
空引用: 引用 = null ,没有指向对象,即为空引用。
语法上是可以通过空指针异常。
public class NullPointerTest{
public static void main(String[] args){
// 创建客户对象
Customer c = new Customer();
// 访问这个客户的id
System.out.println(c.id); // 0
// 重新给id赋值
c.id = 9521; // 终身代号
System.out.println("客户的id是= " + c.id);
c = null; // 没用引用指向对象 Gc机制清理堆内存的对象
// NullPointerException 空指针异常
// 编译器没问题,因为编译器只检查语法,编译器发现c是Customer类型,
// Customer类型中有id属性,所以可以:c.id。语法过了。
// 但是运行的时候需要对象的存在,但是对象没了,尴尬了,就只能出现一个异常。
System.out.println(c.id);
}
}
class Customer{
// 客户id
int id; // 成员变量中的实例变量,应该先创建对象,然后通过“引用.
”的方式访问。
}
内存图:
9.3. 方法调用时参数传递的问题
- java中规定:参数传递的时候,和类型无关,不管是基本数据类型还是引用数据类型,统一都是将 盒子中保存的那个“值”复制一份,传递下去。
- java中只有一个规定:参数传递的时候,一定是将”盒子”中的东西复制一份传递过去。 内存地址也是值,也是盒子中保存的一个东西。
- 方法的参数可以是引用数据类型也可以是基本数据类型
- 分析以下代码
- int x = 1; int y = x;
分析:把x中保存1复制一份传给y,x和y都是两个局部变量。 - Person p1 = 0x1234; Person p2 = p1;
分析:把p1中保存的0x1234复制一份传给p2,p1和p2都是两个局部变量。
public class Test1{
public static void main(String[] args){
int x = 100;
int y = x; // x赋值给y,是怎么传递的?将x变量中保存的100这个值复制一份传给y
// 局部变量,域是main
int i = 10;
// 将i变量中保存的10复制一份,传给add方法。
add(i);
System.out.println("main ---> " + i); //10
}
/*
public static void add(int i){ // i是局部变量,域是add
i++;
System.out.println("add ----> " + i); //11
}
*/
public static void add(int k){
k++;
System.out.println("add ----> " + k);
}
}
public class Test2{
public static void main(String[] args){
Person p = new Person();
p.age = 10;
add(p);
System.out.println("main--->" + p.age); //11
}
// 方法的参数可以是基本数据类型,也可以是引用数据类型,只要是合法的数据类型就行。
public static void add(Person p){ // p是add方法的局部变量。
p.age++;
System.out.println("add--->" + p.age); //11
}
}
class Person{
// 年龄属性,成员变量中的实例变量。
int age;
}
内存图Test1:
内存图Test2
9.4. 构造方法(重点)
9.4.1. 构造方法特点( Constructor )
- 什么是构造方法?
- 构造方法是用来创建对象,并同时给对象的属性赋值。(注意:实例变量没有手动赋值的时候,系统会赋默认值。)
- 构造方法语法:
[修饰符列表] 构造方法名(形式参数列表){
构造方法体;
通常在构造方法体当中给属性赋值,完成属性的初始化。
}
- 修饰符列表目前统一写:public,千万不要写public static,
- 构造方法名和类名必须一致。
- 构造方法不需要指定返回值类型,也不能写void,写上void表示普通方法,就不是构造方法了。
- 当一个类中没有提供任何构造方法,系统默认提供一个无参数的构造方法。这个无参数的构造方法叫做缺省构造器。
- 调用构造方法:使用new运算符来调用构造方法。语法格式:new 构造方法名(实际参数列表);
- 当一个类中手动的提供了构造方法,那么系统将不再默认提供无参数构造方法。建议将无参数构造 方法手动的写出来,这样一定不会出问题。
- 无参数构造方法和有参数的构造方法都可以调用。
Student x = new Student();
Student y = new Student(123);
- 构造方法支持方法重载吗?
- 构造方法是支持方法重载的。在一个类当中构造方法可以有多个。并且所有的构造方法名字 都是一样的。
- 方法重载特点:在同一个类中,方法名相同,参数列表不同。
- 对于实例变量来说,只要你在构造方法中没有手动给它赋值,统一都会默认赋值。默认赋系统值。 并且在构造方法中不显示,但存在。
public class ConstructorTest01{
public static void main(String[] args){
// 调用Student类的无参数构造方法
new Student(); // 没用引用指向 会被自动清理
// 调用普通方法
ConstructorTest01.doSome();
doSome();
// 创建Student类型的对象
Student s1 = new Student();
// 输出“引用”
//只要输出结果不是null,说明这个对象一定是创建完成了。
// 此处的输出结果大家目前是看不懂的,后期再说。
System.out.println(s1); //Student@54bedef2
// 这是调用另一个有参数的构造方法。
Student s3 = new Student(100);
System.out.println(s3); //Student@5caf905d
}
public static void doSome(){
System.out.println("do some!!!!");
}
}
- 思考:实例变量没有手动赋值的时候,系统会默认赋值,那么这个默认赋值操作是在什么时间进行的?
实例变量是在构造方法执行的过程中完成初始化的,完成赋值的。
public class User{
// 3个属性,3个实例变量【对象变量】
// 用户id
int id; //System.out.println(User.id);错误的。需要先new对象,只有对象有
了才能谈id
// 用户名
String name;
// 年龄
int age;
// 手动定义有参数的构造方法,无参数构造方法将消失。
public User(int a){
}
public User(){
//这里实际上有三行代码你看不见。
// 无参数构造方法体当中虽然什么代码都没写,
// 但是实际上是在这个方法体里面进行的实例变量默认值初始化
/*
id = 0;
name = null;
age = 0;
*/
// 这就表示不再采用系统默认值,手动赋值了。
id = 111;
name =
"lisi";
age = 30;
}
}
- 构造方法需要掌握的知识点:
- 构造方法有什么作用?
- 构造方法怎么定义,语法是什么?
- 构造方法怎么调用,使用哪个运算符? 什么是缺省构造器?
- 怎么防止缺省构造器丢失?
- 实例变量在类加载是初始化吗?实例变量在什么时候初始化?