面向对象的三大特征
1. 封装
2. 继承
3. 多态
1.封装
思想
将一个事物进行包装,提供对外使用的方法
概念
尽可能隐藏对象的内部实现细节,控制对象的修改及访问的权限
优点
1.保护内部
2.方便使用
3.降低耦合度(解耦合)
是不是感觉有点晦涩难懂?其实我们已经接触过了封装,它也并没有想象中的那么高大上,我们经常会使用到封装的思想。比如,方法(函数),类,包,项目的创建,一个个功能模块的划分就是利用了封装的思想。
2.继承
1.思想
真是生活中的继承,获得长辈存留的事物
代码中的继承,是类与类之间行为(方法)和特征(属性)的一种赠予和获得。
2.继承关键字以及语法
关键字:extends
语法:
访问权限修饰符 class 子类名 extends 父类名{}
//例如
public class Dog extends Animals{}
我们发现这似乎就是我们在创建类的时候加的代码,只是加了extends 和父类的名字。
和现实生活中一样,代码里的继承也是晚辈(子类)继承自己的长辈(父类)
3.特点
1.子类拥有父类的所用属性与方法
2.子类只能拥有一个直属父类(直接继承的父类),但是可以多级继承,属性和方法逐级增加(父类它自己还有它的父类可对应于现实生活中,儿子,父亲,爷爷依次类推)
3.产生继承关系后,子类可以使用父类中的属性和方法,也可以定义子类独有的属性和方法
4.父类
父类就是根据多个类,进行共性的抽取,从而定义的类
例如:
狗、鱼、鸟、蛇,都拥用一些相同的属性和方法,那么如果在每个类里都重新定义一遍,是不是很傻?所以我们抽取这些属性和方法,把它们封装到一个动物类里,其他的类继承动物类,这样狗、鱼、鸟、蛇,就继承了动物类的属性和方法,从而提高代码的复用性和可扩展性。
而后狗、鱼、鸟、蛇,又都拥有自身独有的一些方法,所以在继承动物类的属性和方法后,再对自身独有的属性和方法进行定义就好了。
注1.所有类都有父类,2.如果没有明确写出所继承的父类,那么默认继承于Object(“祖宗类”)
5.不可使用
也有的地方称为不可继承,但是经过实验后,我们会发现其实已经继承了,但是没有访问的权限,所以这在,我们叫它不可使用
1.构造函数不可直接使用
2.使用private修饰的方法或属性不可直接使用
(private,访问权限修饰符的一种,仅本类可见)
3.父子类不在同一个包里且由默认权限修饰符(default)修饰的属性和方法不可直接使用
(default,访问权限修饰符的一种,仅本包可见)
实验:
父类Animals,name为private修饰,但是加了get,set方法
public class Animals {
private String name;
public Animals() {
System.out.println("这里是Animals类的无参构造函数");
}
public Animals(String name) {
System.out.println("这里是Animals类的有参构造函数");
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
子类:继承父类
public class Cat extends Animals{
public Cat() {
super();
}
public Cat(String name) {
super(name);
}
}
测试类
public class Text {
public static void main(String[] args) {
Cat cat1 = new Cat();
Cat cat2 = new Cat("Tom");
System.out.println(cat1.getName());
System.out.println(cat2.getName());
}
}
执行结果:
我们可以发现,name虽然是private修饰的,但是我们使用了get和set方法可以继承name属性
6.访问权限修饰符
本类 | 同包 | 非同包子类 | 其他 | |
---|---|---|---|---|
private | √ | × | × | × |
default | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
public:当前项目皆可使用,可以修饰类
protected:同一个包或继承关系中可以使用,不可以修饰类
default:同一个包中可以使用,可以修饰类
private:只能在当前类中使用,不可以修饰类
7.重写与重载
重写 | 重载 |
---|---|
在继承关系中,子类方法与父类方法 | 在同一个类中 |
访问权限修饰符(范围)只能变大或不变 | 访问权限修饰符不管 (可以相同,可以不同) |
返回值类型相同 | 返回值类型不管(可以相同,可以不同) |
方法名相同 | 方法名相同 |
形参列表相同 | 形参列表不同 |
8.super和this
上面的代码里,我们发现了super,那么它的作用是什么呢?它的功能和this相似,同时我们也来复习一下this的作用。
this:调用本类的构造函数,调用本类方法,调用本类属性,区分成员变量和局部变量
super:调用父类构造函数,调用父类的方法(谁调用super所在的方法,super就表示他的父类对象)
注:super和this调用构造函数时,要放在构造函数内的首行,如果super和this同时存在,super在this之前
9.继承后对象的创建过程
- new开辟内存空间
- 加载父类
- 加载子类
- 调用父类构造函数
- 调用子类构造函数
- 赋值给变量(如果没有赋值,则这一步不执行)
3.多态
1.思想
在现实生活中,多态就是一个事物的多种形态,怎么解释呢?比如你在老师面前你是学生,在领导面前你是员工,在父母面前你是孩子,但是你就是你,你没变。
那么映射到代码中,多态就是,不同的类的对象对同一个消息做出的响应,即同一个消息可以根据发送对象的不同而采取多种不同行为的方式。
2.多态存在的条件
1.要有继承
2.要有重写
3.父类对象引用指向子类对象
3.多态的转型
多态的转型分为向上转型和向下转型两种
向上转型(装箱)
父类引用中保存真实子类对象称为向上转型(多态的核心概念)
语法:
父类类型 变量名 = new 子类对象();
向下转型(拆箱)
将父类引用中的真实子类对象,强转回子类本身类型,称为向下转型
语法:
子类类型 变量名 = (子类类型) 父类类型的变量
注:向下转型时,需要强转,且如果父类引用中的子类对象类型和目标类型不匹配,会报错,ClassCastException(类型转换异常)
4.instanceof关键字
判断该对象是否属于该类
语法
变量名 instanceof 类名
注:该表达式是boolean类型的,如果该对象属于该类,返回true,不属于返回false
该关键字常用于向下转型前。
5.实例
之前在网上看到一个很厉害的例子,如果大家把它搞懂的话,对多态的理解就差不多了。
//题目相关的类
public class A {
public String show(D d) {
return("A and D");
}
public String show(A a) {
return("A and A");
}
}
public class B extends A{
public String show(B b) {
return("B and B");
}
public String show(A a) {
return("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
//问题
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
1. System.out.println(a1.show(b));
2. System.out.println(a1.show(c));
3. System.out.println(a1.show(d));
4. System.out.println(a2.show(b));
5. System.out.println(a2.show(c));
6. System.out.println(a2.show(d));
7. System.out.println(b.show(b));
8. System.out.println(b.show(c));
9. System.out.println(b.show(d));
}
//答案
1. A and A
2. A and A
3. A and D
4. B and A
5. B and A
6. A and D
7. B and B
8. B and B
9. A and D
这是为什么呢?我们来分析一波
a1是A类对象,比较清晰,不用特别的分析,a1的两个方法:
public String show(D d) {
return("A and D");
}
public String show(A a) {
return("A and A");
}
1 . a1是A类对象,所以只拥有A类的两个show方法,但是参数b是B类对象,A类的两个对象的参数没有B的,但是B类又继承A 类,所以b也可以说是A类对象,所以使用show(A a)
的方法
2 . 同理,C类继承B类,B类又继承A类,一级一级判断,所以show(A a)
的方法
3 . 这里A类中已经存在了参数为D类对象的方法,所以直接就使用了show(D d)
的方法
我们先对a2分析一波
a2使用了多态,向上转型,它本身是B类对象,想要转型成A类对象,(我们可以认为a2本身是B类对象,但是要假装A类对象)所以它只拥有B类对象的方法,但是呢,假装就要装的像一点,B类对象有的,A类没有的,它没法使用(不然就露馅了),所以它只有show(A a)
一个方法,然后B类对象又继承A类对象,所以A类对象的方法它也可以使用,A类中也有一个show(A a)
方法,两个show(A a)
用哪个?因为B继承了A,B类对A的方法进行了重写,所以使用B类的show(A a)
方法,这时a2的两个方法就是:
public String show(A a) {
return("B and A");
}
public String show(D d) {
return("A and D");
}
4 . 经过上面的分析,知道a2的方法后,因为参数b继承A类,所以返回B and A
5 . 同理,参数c继承B类,B类又继承A类,所i有返回B and A
6 . d为D类对象,调用show(D d)
方法
对b进行分析
b是B类对象,拥有B类对象的两个方法,B类继承A类,b也拥有A类的两个方法,B类对A类的show(A a)
方法进行了重写,所以b就有三个方法
public String show(D d) {
return("A and D");
}
public String show(B b) {
return("B and B");
}
public String show(A a) {
return("B and A");
}
7 . b是B类对象,直接调用show(B b)方法
8 . c继承B类,到这就可以直接调用show(B b)方法了(继承是逐级继承的)
9 . d是D类对象,直接调用show(D d)方法