继承

概念(is-a)

继承是类与类之间的一种关系,继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

继承的特性

  • 子类拥有父类非private的属性、方法。
  • 子类可以拥有自己的属性和方法,也就是子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。(重写)
  • Java中类只能单继承;接口可以多继承

示例

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
48
49
50
51
52
53
54
55
56
57
58
59
60
public class Person {
public String name;
public int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public Person() {

}

private void god() {
System.out.println("女娲创造了人类");
}

public void eat() {
System.out.println("Person吃饭");
}

public void sleep() {
System.out.println("Person睡觉");
}
}

class Man extends Person {

public Man(String name, int age) {
super(name, age);
}

@Override
public void eat() {
System.out.println("Man狼吞虎咽的吃饭");
}

public void makeMoney() {
System.out.println("Man负责挣钱");
}

public void god() {
System.out.println("什么女娲创造了人类?");
}
}

class Woman extends Person {

public Woman() {
super();
}

public Woman(String name, int age) {
super(name, age);
}

public void spendMoney() {
System.out.println("Woman负责花钱");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String[] args) {
Person person1 = new Man("伏羲", 11);
person1.eat(); // man 中重写了person中的eat方法
Man man = new Man("男人", 20);
man.makeMoney();
man.god();

Woman woman = new Woman("女娲", 12);
woman.eat(); // woman 中未重写调用的是person的eat
woman.spendMoney();
//woman.god(); // 无法访问父类的私有方法
}
}

  1. 一个类中如果不声明构造函数,也会默认存在一个无参的构造函数,除非手动声明后,这个默认无参构造函数也就不存在了。

  2. 构造函数没有返回值,并且不能用void修饰符来修饰。

  3. 子类的构造函数中会默认调用父类的无参构造函数,如果父类中存在有参的构造函数,那么子类就需要显示的调用了。

  4. 注意super()和this()不能同时存在,它们是冲突的,并且都必须在第一行来进行调用。

    super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。

    this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。

  5. 用父类来声明子类的时候,比如Person person = new Man()则person无法调用子类中特有的那些方法,编译器编译的时候默认的认为你这个类型就是Person类型的,虽然无法调用子类中特有的方法,但是重写这个特性还是存在的,如果子类重写了父类的方法,并不会去调用父类的方法,这个应该因为重写是动态分派的一种,在运行期才能决定调用哪个方法,编译阶段无法知道你具体调用的哪个方法,自然不会让你编译通过。

理解

  • 我理解的继承就是使程序的设计变得简单了,它的一个最大的好处就是代码复用,我感觉有了继承这个属性,才是真正面向对象的灵魂,真正的抽象出生活中的各种模型,比如,人,男人,女人,都能吃饭,睡觉,但是男人与女人又有不同,通过继承可以非常好的对此进行描述,大大简化了程序的编写。
  • 过度使用继承,继承层次过深过复杂,就会导致代码可读性、可维护性变差。为了了解一个类的功能,我们不仅需要查看这个类的代码,还需要按照继承关系一层一层地往上查看“父类、父类的父类……”的代码。还有,子类和父类高度耦合,修改父类的代码,会直接影响到子类。 多用组合少用继承。

封装

概念

封装就是把对象的属性和操作结合为一个独立的整体,并尽可能的隐藏对象内部的实现细节。

优点

  • 良好的封装能够减少耦合。
  • 类内部的结构可以自由的修改

封装就是你只管提供接口,就像打印机,我打印东西只需点击打印即可,具体的实现我不去管。封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。

  • 可以对成员变量进行更精确的控制。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Student {
private String name;
private int age;

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

理解

我认为封装就是给你提供接口,让你来使用,你无需知道具体的实现是怎么样的,比如你是一个付费用户,给你提供的接口功能就比免费用户多。不能破坏程序的封装性,破坏了你不是vip成员但是能够使用vip的功能,这个就不好了。

多态

概念

多态是同一个行为具有多个不同表现形式或形态的能力。

这个就好比,键盘的快捷键,相同的按键在不同的应用程序中体现出来的效果也不一样。

就比如ctrl + Y 在idea中是删除快捷键,在eclipse中就可能是别的操作了。

这个多态和虚函数(我在jvm中详细说到这个虚函数非虚函数)。

多态的三个必要条件

  1. 继承
  2. 重写
  3. 父类引用指向子类对象

就像继承中的例子那样Person person = new Man()这样

重载与多态的区别(重载与多态无关)

  1. 多态是建立在重写的基础之上的,是类与类之间的关系,是发生在不同的类之间的,子类重写父类的方法。实现不同的子类,不同的实现形态。
  2. 而重载是类的内部的方法构型上的不同,是发生在同一个类里面的。同一个函数名称,参数不同的多个方法,实现同一类型的功能。

具体可以看:

重载和重写

深入理解重载和重写

知识点之间都是相关的,一开始学的时候只是知道有这个东西,然后随着慢慢的探索就会发现更深入的东西。

多态的表现形式

  1. 重写
  2. 接口
  3. 抽象类抽象方法

这些都很好理解接口只是定义一些规则,每个实现接口的类,实现方式并不相同,抽象类也是这样,继承抽象类的,实现其中的抽象方法,肯定也不一定相同的。

比如:接口是非机动车靠边行驶。这个在中国的具体实现就是靠右行,在外国就不一定了。这个就是多态。

目前我对面向对象的理解还很浅显,或许几年过后,再回头看,会对面向对象有更深层次的理解。

还有一个这里我没写封装,封装这个属性比较特殊,常常不被称为面向对象变成的特性。就是这个思想太过广泛。