Java-面向对象之(封装+继承+多态)

一、什么是面向对象

二、类和对象

三、this的作用

this顾名思义就是“我”,“我”指的是某个对象的引用,也就是代表某个对象的名字,下面正式讲解this的用处,从三个方面来进行讲解。

1、this.成员变量名字

当给成员方法传参时,如果方法的形参和成员变量的名字相同时,采用就近原则,会使用形参,而不使用成员变量,如果我们要给成员变量赋值,就要使用成员变量,通过this来指定现在调用的是成员变量。
还有使用this的另一种原因是:一个类可以有很多对象,如果此时有三个对象,调用成员方法给对象的成员变量赋值,站在成员方法的角度来看,现在有三个对象,怎么能知道是给哪个对象的成员变量赋值呢?有两个角度可以看出:第一个角度:哪个对象调用的成员方法,就给哪个对象的成员变量赋值;第二个角度:成员方法有一个隐藏的参数:this,this上面说了,是代表某个对象的引用,当成员方法执行时,编译器会将调用这个方法的对象的引用传给成员方法,this用来接收。

2、this.成员方法名字

this代表某个对象的引用,当调用成员方法,在方法里面调用其他成员方法时,成员方法就能知道
是哪个对象在调用成员方法,不让成员方法糊里糊涂的,要告诉人家,是谁在调用。

3、this.构造方法名字

给成员变量赋值有三种方式
第一种:就地初始化,在定义成员变量的时候,就初始化,这种方式会使所有的对象的成员变量的值都是这个值。
第二种:默认初始化,编译器会自动给成员变量赋上默认的值。
第三种:使用构造方法初始化,在构造对象时,会调用构造方法,构造方法的功能是可以给成员变量初始化。就像是根据图纸建造出一个洗衣机,如果你不给他规定这个洗衣机的各项参数,这个洗衣机怎么被创造出来,构造方法就是创建对象的必要条件,只有调用了构造方法,对象才能说被创建完成,如果我们没有提供构造方法,编译器会默认提供一个无参数的构造方法,如果我们提供了构造方法,程序会执行我们提供的构造方法,可以提供无参构造方法和有参构造方法,当给构造方法传参时,会调用有参构造方法,如果没有传参,会调用无参构造方法。
构造方法的名字和类名是相同的,且用public修饰。
没有返回值,也就没有返回值类型,设置为void也不行,意思就是构造方法没有返回这个功能。
创建一个对象就调用一次构造方法,也就是说构造方法只能被调用一次,当调用

4、this的特性:

可以想象出一个场景:有一个人是雇佣兵杀手,这个杀手可以被雇佣去杀人,当被雇佣的时候,他得知道他是为哪个老板服务,才能精准完成任务,所以老板的管家就告诉杀手,你说是在为谁服务,然后杀手就知道了。
这个类里面的方法就是杀手,编译器就是老板的管家,对象就是老板,当调用这个方法的时候,编译器就将代表对象的引用传给this,此时这个方法就知道他是被调用的了。
特性:1:this只能引用当前对象,不能再引用其他对象,一个杀手不能同时完成好几个任务,只能完成一个任务再继续完成另一个任务。
2:this的类型:哪个对象调用,就是哪个对象的引用的类型。
3:this只能在成员方法中使用,this是杀手的一个标志,是杀手所特有的。

四、封装

1、什么是封装

2、访问权限修饰符

3、

五、继承

六、多态

在这里插入图片描述

1、什么是多态?

多态,顾名思义就是多种状态。
举个例子:
对于打印机来说,现在有两台打印机,两台打印机的具有相同的功能,他俩都能打印,但表现出的行为不一样,一台打印机只能打印黑白纸,但另一台打印机能打印出彩色的纸。
对于人类来说,每个人都能吃东西,但是吃的东西不一样,刚出生的婴儿只能吃奶,成年人则可以吃肉。
对于编程语言的多态来说,实例化出的对象们,调用同一种方法,实现同一种功能,就像是打印机,都能打印,打印是同一种功能,但一个能打印彩色,一个能打印黑白,表现出的行为不一样,这个就叫做多态。

2、形成多态的必要条件是什么?

1. 在继承体系下

继承体系下,是子类继承父类,就像是一个父亲有好几个孩子,这每个孩子都具有不同的行为,构成了多态。
多态就是根据继承得来的,由于继承中的子类继承了父类中的方法,但表现出的行为不一样,就出现了多态这个名词,这里不要有纠结。

2. 子类对父类中的方法进行重写

1、什么是重写

子类是继承父类的,继承了父类中的方法,但每个子类调用方法,要表现出的行为不一样。

就像是刚出生的孩子继承了父亲,吃东西这个方法,但吃的东西不一样,表现出的行为不一样,婴儿只能吃奶,而父亲可以吃肉,就要重新实现这个方法,也就是重写。
方法重写的意思是:对继承的父类中的某一个方法重写,类似于某个人重生。

方法的外壳一般保持不变(方法名+形参名+返回值类型),但是内容变了。

内容变了是什么意思呢? 就比方说,一个父亲的孩子继承了父亲吃东西这个动作,但是吃的东西与父亲不一样,婴儿只能吃奶,这里吃的东西就是方法中的内容。

2、为什么要进行重写
3、重写的规则是什么
  1. 重写出的方法的返回值类型一般与父类保持一致,但有二般,二般的情况是,被重写的方法与重写出的方法的返回值类型必须是具有父子关系。
  2. 重写出的方法的访问权限不能比被重写的方法的访问权限低,这里很好理解的,父亲具有吃东西这个动作,而父亲的孩子,出生之后,也具有吃东西这个动作,但是这个孩子却不能使用这个动作,不能访问这个动作,这不就BBQ了?
  3. 还有一些不能被重写,也就意味着父类当中的方法的内容不能被修改。父类中被static,private修饰的方法不能被重写,构造方法也不能被重写。

为什么被static修饰的方法不能被重写?(一会再说)

为什么被private修饰的方法不能被重写呢?理论上可以被重写,但重写出来之后,使用向上转型的时候,将子类的对象的引用赋给父类的对象的之后,父类对象的引用不能调用这个被private修饰的方法。

为什么构造方法不能被重写呢?重写的意思是:方法的外壳不变,(方法名+形参名+返回值类型),构造方法的要求是:方法的名字要和本类名字相同,子类中重写父类的构造方法和构造方法的要求冲突,子类的构造方法的方法名要和子类的类名相同,而重写父类的构造方法,重写出的方法名要和父类的类名相同。

3. 通过父类对象的引用调用子类中重写的方法

实现这一条件的是向上转型+动态绑定。

1、向上转型
1、什么是向上转型

为了理解向上转型,我抽象出了生活中的一个情景:

在这里插入图片描述
有一个小孩,她现在住在一间房子里,房子的类型是茅屋,现在将她转移到
另一间房子里,这间房子的类型是城堡,并且一间房子只能住一个人。

用Java去理解向上转型:这个小孩相当于引用,引用是类似于地址的一个值,Java为了安全,是不会将真实的地址交出来的。地址由于可以指向一个内存空间,所以地址的别名叫做指针,将地址放到一个变量里面,这个变量叫做指针变量,而将引用放到一个变量中,这个变量就叫做引用。刚开始引用放到一个类型是子类类型的变量中,就像是小孩刚开始住的是一间茅屋的房子里,现在将引用放到一个类型是父类类型的变量中,就像是将小孩转移到一间是城堡的房子里。
引用的类型从子类的类型转变为父类的类型,这一个过程叫做向上转型。

2、完成向上转型的方式

1、直接转

 Dog b1 = new Dog();
 Anail a1 = b1;

2、实参传形参

	public static void function(Anail a1) {
    a1.sleep();
}
    public static void main(String[] args) {
        Dog b1 = new Dog();
        Cat c1 = new Cat();
        function(b1);
        function(c1);
    }
}

3、作为返回值,传过去

	public  static Anail funcction(String var) {
    	if(var.equals("狗")) {
        	return new Dog();
    	} else {
        	return null;
    	}
	} 
    public static void main(String[] args) {
        Dog b1 = new Dog();
        function(b1);
        Anail anail = funcction("狗");
    }
3、向上转型的优点和缺点

缺点:向上转型之后,调用方法,会出现动态绑定(下一小节讲到),产生的后果是子类中特有的方法无法被调用!(联想小卖部那个例子,无法去小卖部B买东西,小孩内心独白:”宝宝心里苦啊“)

优点:向上转型之后,调用方法, 可以出现动态绑定,也可以不出现动态绑定,对于动态绑定这个动作可以控制,所以就使得代码非常的灵活和简单。

2、什么是动态绑定

为了理解动态绑定,我又抽象出来了生活中的情景:
在这里插入图片描述
小孩想要去小卖部A买东西,在去的路上发现,小卖部B也有这个东西,更便宜,就转头去了小卖部B买这个东西。
这样的一个过程就类似于动态绑定。
因为小卖部A是属于城堡的,小卖部B是属于茅屋的,由于现在小孩待在城堡中,当小卖部A没有东西时,而B中有时,这个小孩也不会去B中去买。

用Java知识去解释动态绑定:小孩就是一个引用,买的这个东西就是方法,买这个过程就是调用方法, 小卖部A是父类,小卖部B是子类,
当父类和子类中都有这个方法,在程序编译时,调用的是父类的方法,但在运行时,则调用的子类中重写的这个方法。
这样的一个过程就叫做动态绑定。

上面提到:“当小卖部A没有东西时,而B中有,这个小孩也不会去B中买”
用Java知识去理解这句话的意思:当子类中定义了一个方法,而父类中没有这个方法,向上转型之后,就不能去调用这个方法,如果没有发生向上转型,就可以调。对这一句加粗的话,发生向下转型之后,如果想要调用子类中的方法,就要发生向下转型,原路返回。(向下转型在下下一节会提到,不了解的,可以向下翻翻)。

通过向上转型和动态绑定实现了这一条件。
而这三个条件的综合起来,实现了Java当中伟大的多态!
完成向上转型的方式之一:实参传给形参这一方式,调用两次方法,传的参数的不同,则作为形参接收的就不同,形参作为一个引用,每次所引用的对象不同,所表现出的方式就不同,这一个过程产生的思想就是多态!
在这里插入图片描述

3、向下转型
1、什么是向下转型

为了理解,联想小孩那个情景:
将小孩从一间是城堡的房间中转到一间是茅屋的房间中。

用Java语言去描述:小孩就是引用值,刚开始小孩在一间城堡的房间里,就是引用放在一个类型是父类的变量里面,将小孩转移到茅屋中,就是将引用转移到一个类型是子类的变量当中。
引用的类型从父类变成子类,这样的一个过程就是向下转型。

2、为什么会出现向下转型

联想上面的情景:
因为小孩呆在城堡中,小卖部B是属于茅屋的,无法访问小卖部B的特有的东西,所以就转移去茅屋,就可以去小卖部B中买特有的东西。

是为了弥补向上转型带来的缺点:不能访问子类中特有的方法。
通过向下转型,就可以访问本类中的方法。

3、向下转型的缺点

当小孩从城堡转移到茅屋时,如果没有转移到茅屋,就会发生危险,可能就找不到家了。

所以,当向下转型的时候,如果引用的类型没有变成原来的类型,就会不安全,造成错误,运行时会抛出异常:
在这里插入图片描述

4、如何防止向下转型出现错误

当小孩在转移之前,先检查一下,看看自己终点的房子是不是自己的茅屋,如果不是,就不能去。

Java提供了instanceof关键字,看看即将存放引用的这个变量的类型和之前的类型是否相同,如果相同,才可以转换。

if(animal instanceof Cat){
cat = (Cat)animal;
cat.mew(); 
}

七、多态的优缺点

1、优点

  1. 能够降低代码的圈复杂度,能够避免大量使用if-else语句
    例如:如果现在我们想打印好几个形状,而不是一个形状,不使用多态这个思想。
public static void drawShapes() { 
	Rect rect = new Rect(); 
	Cycle cycle = new Cycle(); 
	Flower flower = new Flower(); 
	String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"}; 
	for (String shape : shapes) { 
		if (shape.equals("cycle")) {
			cycle.draw(); 
		} else if (shape.equals("rect")) { 
			rect.draw(); 
		} else if (shape.equals("flower")) {
		    flower.draw(); 
 		}
 	} 
}

打印三个形状,就要使用一个if语句和两个else if语句。

现在使用多态这个思想:

public static void drawShapes() { 
	Shape[] shapes = {new Cycle(), new Rect(), 
	new Cycle(), new Rect(), new Flower()}; 
	for (Shape shape : shapes) { 
	shape.draw(); 
	}
}

打印三个形状,只需要创建类的对象,通过引用指向不同的对象,调用一种方法,所打印出的形状就不一样,没有使用一个if-else语句。

  1. 可扩展的能力高

将来如果要添加打印新的形状,就要再次添加if-else语句进行判断,然后才打印,对代码的改动成本高。
使用多态这个思想,只需要创建对应的对象就可以,通过引用指向不同的对象,打印出不同的形状,对代码的打印成本很低。

2、缺点

  1. 处于继承体系中时,父类和子类中具有同名的属性时,当引用的类型是父类时,只能访问父类中的属性。
  2. 在子类中不能重写父类的构造方法,所以构造方法不具有多态性,因为构造方法的名字要求和类名相同,重写要求方法名相同,所以就不能重写构造方法。

八、综合

说到构造方法了,在继承体系中,一定要避免在父类的构造方法中调用重写的方法。

因为类加载是在实例化对象之前,类就是一张制造洗衣机图纸,对象是根据图纸制造出来的洗衣机。在制造洗衣机之前,肯定要将类加载出来。

构造方法是在类加载的时候调用的,在调用子类的构造方法的时候,肯定要先调用父类的构造方法,如果父类的构造方法中的方法,子类重写了,那样会调用子类中的这个方法,如果方法中有子类中的成员变量,那么这个变量的值肯定是0,因为子类中的成员变量还没有初始化,还没有调用完子类的构造方法,刚一进去调用子类的构造方法,就去调用父类的构造方法了。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值