# 面向对象
- 程序是对现实世界的建模
- class的概念,object的概念 => 实例(Instance)
- 对应现实世界中的某一类事物
- 人、动物、车、飞机、形状、国家
- 张三、那只猫、这辆汽车、天上飞过的一架飞机、这个正方形、斯里兰卡。。。
- 程序中如何建立一类事物
- class关键字
- 程序中如何建立一个对象
- 有的是new,有的可以省略
// Java
// 形状类
class Shape{
}
public class Shape{
public static void main(String[] args){
new Shape();
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# Python
# 形状类
class Shape:
pass
Shape()
1
2
3
4
5
6
2
3
4
5
6
// C++
#include <iostream>
using namespace std;
class Shape {
};
int main()
{
new Shape();
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 类的构造方法(构造函数)
- 指的是在创建这个类的对象的时候,被自动调用的方法
- Java/C++与类同名,没有返回值
- Python
__init__
- Java默认会提供一个参数为空的构造方法
- 自己写了一个构造方法,Java就不再为你提供构造方法了
// Java
// 形状类
class Shape{
Shape(){
System.out.println("Shape");
}
}
public class Shape{
public static void main(String[] args){
new Shape();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# Python
# 形状类
class Shape:
def __init__(self):
print('Shape')
Shape()
1
2
3
4
5
6
7
2
3
4
5
6
7
// C++
#include <iostream>
using namespace std;
class Shape {
public:
Shape(){
cout << "Shape" << endl;
}
};
int main()
{
new Shape();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 类的属性
- 对应的是现实世界中某一类事物共有的属性
- 人的名字、车的品牌、飞机的翼展
- 创建对象的时候,每一个对象内部都有这些属性的对应值
// Java
// 形状类
class Shape{
String name;
Float area;
Shape(){
System.out.println("Shape");
}
}
public class Shape{
public static void main(String[] args){
new Shape();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# Python
# 形状类
class Shape:
name = 'Shape'
area = 0
def __init__(self):
print('Shape')
Shape()
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
// C++
#include <iostream>
using namespace std;
class Shape {
string name;
float area;
public:
Shape(){
name = "Shape";
cout << "Shape" << endl;
}
};
int main()
{
new Shape();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 操纵对象
- C++的指针、Java的引用、Python中的变量、Windows中的句柄...
- 其实都是同样的东西
- 这些都是存储的对象的地址
- 除Python外,都必须指定这个指针指向的类型
- 通过这个指向对象的指针,可以对对象进行操纵
对象的本质就是一段地址范围,而指针是访问这个范围用的
指定类型、访问属性
// Java
// 形状类
class Shape{
String name;
Float area;
Shape(){
System.out.println("Shape");
}
}
public class Shape{
public static void main(String[] args){
Shape s = new Shape();
s.name = "";
s.area = 1.0f;
System.out.println(s.name);
System.out.println(s.area);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Python
# 形状类
class Shape:
name = 'Shape'
area = 0
def __init__(self):
print('Shape')
s = Shape()
print(s.name)
s.area = 1.0
print(s.area)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
// C++
#include <iostream>
using namespace std;
class Shape {
public:
string name;
float area;
public:
Shape(){
name = "Shape";
cout << "Shape" << endl;
}
};
int main()
{
Shape* s = new Shape();
s->name = "Shape2";
s->area = 1.0;
cout << s->name << endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PS:名称为s的内存里存放着地址指针,地址指针指向着new Shape()对象的内存
问题:变量s的大小是多少?
答:由操作系统是多少位决定,32位则大小为32位,64位则大小为64位
# 回收对象所占用的内存
- Java/Python自动回收
- C++手动回收 delete s 将s指向的那个内存标记已废除,可以用了
- 忘了回收,内存泄漏
- 回收多次,数据丢失
// C++
#include <iostream>
using namespace std;
class Shape {
public:
// 指针为指定对象时 默认是随机的内存地址 这时要是delete的话就可能会发生数据丢失
// 给指针指定为NULL则不是随机的内存地址 而是NULL了
string* name = NULL;
float area;
public:
//构造函数
Shape(){
name = new strin("Shape");
cout << "Shape" << endl;
}
// 析构函数
~Shape() {
cout << "deconstructor" << endl;
if(name)
delete name;
}
};
int main()
{
/*
Shape* s = new Shape();
//s->name = "Shape2";
s->area = 1.0;
cout << s->name << endl;
delete s; // delete s的时候会触发 指向的对象的析构函数
*/
Shape s;
// 会执行构造函数与析构函数 生成对象在栈上 而new出来的对象在堆中
// 由于主函数main结束后和main函数相关的变量都清理 会自动将栈上的对象进行清理
// 所以调用了析构函数
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
复习
- 类、对象
- 构造方法(函数)
- 如何创建对象
- 如何回收对象
- 如何操纵对象
理解了内存就理解了一切
# 成员方法(成员函数)
- 方法名也是指针
- 通过引用或指针访问成员方法
- 通过方法名找到方法代码的过程叫做绑定(binding)
- 编译时vs运行时
- compile-time 编译时(静态)绑定(static、final、private方法、构造方法) 在编译时通过方法名找到方法代码
- run-time 运行时(动态)绑定 在运行时通过方法名找到方法代码
- mian函数开始运行到结束期间
- Java中大多数方法都是动态绑定
- dynamic binding 动态绑定
- run-time binding 运行时绑定 这俩个是一回事
class Person{
String name = "张三";
int age = 16;
public void printName(){
System.out.println(name);
}
}
public class TestPerson{
public static main(String[] args){
Person p = new Person();
p.printName();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
思考:Person p = new Person();在编译的时候就能确定啊,为什么运行时绑定呢?
答:因为在main函数里执行了Person p = new Person(); 当执行Person p调用ClassLoader将class文件装载到内存中,执行new Person()创建Person对象并由p指向这个对象所占的内存空间,当调用p.printName()方法时 会找到类所在内存里中方法代码,所以这个过程时运行时绑定
一个方法(不能被继承=>不会指向多份代码块)(static、final、private方法、构造方法)绑定一块代码块没有歧义,是静态绑定 如构造方法
一个方法绑定一块代码块有歧义,是动态态绑定 如printName()
# 继承、重写、多态
Animal
- 属性:name
- 方法:makeSound()
Dog extends Animal
- name
- swimmingSpeed
- swim()
Cat extends Animal
- name
- tailLength
- climb()
子类对象的布局
调用子类方法的绑定过程
- makeSound()
父类引用可以指向子类对象
通过父类引用只能够"看到"共有的属性或方法
父类引用与子类引用的转换
通过父类引用调用方法的绑定过程
- 多态
先抓核心,再针对核心进行展开
class Animal {
String name;
void makeSound() {
System.out.println("Animal Sound.");
}
}
class Dog extends Animal {
int swimmingSpeed;
void swim() {
}
void makeSound() {
System.out.println("wangwang.");
}
}
class Cat extends Animal {
int tailLength;
void climb() {
}
void makeSound() {
System.out.println("miaomiao.");
}
}
class Goose extends Animal {
void makeSound() {
System.out.println("gagagaga.");
}
}
// 多态 Polymophysm 面向对象的核心优势就是多态
public class Polymophysm {
public static main(String[] args){
//System.out.println("hello");
/*
Dog d = new Dog();
d.name = "wangwang";
d.swim();
d.makeSound();
*/
Animal a = new Dog();
a.makeSound();
a.name = "";
Dog d = (Dog)a;
Animal aa = new Cat();
aa.makeSound();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
私有的属性从父类继承下来了 但是不能访问
高手的定义 要有自己的作品好的项目 这才是强