Day008--java中的面向对象程序设计的特点

目录

一,面向对象的封装性 

二,面向对象的继承性 

三,面向对象的多态性 

四,方法的重写覆盖 

五,接口 

文章后记:实现书店买书程序


 

面向对象其实就是一种编程思想。【编程思想:一种看待问题,解决问题的思维方式。】

在开始学习面向对象之前,就不得不提一下我们一直接触的编程思想:面向过程。学习java的时候,相信大家在打代码之前都会分析一下自己的代码需要解决什么问题,并且怎么一步一步的实现。面向对象却不是这样,我们可以不用去一步一步解决它,而是让一个实体来进行后期的操作。

下面是对两者之间的比较:

面向过程:着眼于问题是怎样一步一步解决的,然后亲力亲为的解决这个问题

面向对象:着眼于找到一个能够帮助解决问题的实体,然后委托这个实体解决问题

有些人说java是面向对象的语言,其实也不是很对,因为,面向对象是一种思想,不是语言。而使用面向对象的语言对于我们来说有什么好处呢?好处是:使用它会更容易写出具有面向对象编程思想的代码。

前面也提到了,我们的面向对象的编程思想是要找一个实体来解决问题的,那么一定会衍生对象和类的概念(在前面的Day004博客后半段我们已经认识了对象的含义以及类的组成和方法的使用,这里我们就讲一些前面没有提到的知识点,也会稍微带一点前面的知识点,巩固一下),在我们的java中是不用程序员自己手动的去销毁对象的,因为它有一个析构方法--finalize(),可以随时来销毁一个对象。析构方法没有任何参数和返回值,每个类有且只有一个析构方法。

 接下来我们开始步入正题,面向对象程序设计的特点有三个:1, 封装性(面向对象的核心思想)            2,继承性              3,多态性

一,面向对象的封装性 

 首先我们来讲解一下封装性

为什么要说封装性是java面向对象的核心思想呢?那是因为我们的面向对象的编程思想在看待,解决问题时是找实体来帮忙解决问题的,而这个实体在我们的java中就叫做对象,我们找实体来帮忙解决问题也不一定就找那么一个,可能会是一群实体:就好比一个公司,里面的员工不会只有一个来在进行运营,可能会有几百上千个人。在这里,员工就是在解决问题的实体----对象,公司就是若干个具有相同特征或行为的实体的集合----类。而世界很大,公司很多,员工可能就只会在一家公司勤勤恳恳的工作,不会到另外一家,那么,每个公司之间就需要有相应的区分,员工才能知道自己属于哪个公司。所以很多公司的企业名都会不同,以此来进行区分-----在这里公司的企业名就叫做类名。

言归正传,封装的特点有三:其一,属性和方法都使用private访问修饰符来进行修饰;其二,类作为载体将私有化的属性和方法封装了起来;其三,可以构建公有的访问接口来给用户访问私有的属性。

 下面我们创建一个名为AACompanyClass公司类

  我们的公司还只是一个空壳公司,没有员工以及运营的业务,结果我们发现ALiCompanyClass这个公司类竟然没有进行相应的封装,好的,那么现在,我们去撬它的墙角(挖员工) 

 现在我们挖到了,然后让我们来揭晓他的名字和年龄

阿里表示:哪里来的杂碎,竟然敢撬阿里的墙角?(╯‵□′)╯︵┻━┻

之后立即启动了项目组将所有属性都进行了封装(即使用private私有访问权限来进行修饰属性)

 好吧,现在我们不能轻而易举的挖墙脚了,之后马云表示公司名称不用私有化---因为其他合作企业有义务知道公司名称,于是技术部立马为这个aliCompanyName属性添加了公共访问接口

当我们与阿里合作时,就可以用它的名字。

所以,我们可以通过公有访问的接口来进行调用阿里私有化的公司名

综上,相信大家也发现了Java封装的益处------ 首先应用该类的用户不能轻易直接操作里面的(私有的)数据结构,只能通过执行类允许公开的数据(以及通过公开的访问接口),这样避免了外部对内部数据的影响。其次,提高了程序的可维护性

二,面向对象的继承性 

接下来我们去认识面向对象的第二个特点----继承性

类与类之间的关系(关联)有很多种,继承是关联中的一种。继承性利用的是特定对象之间 的共有属性。

接下来我们用代码来看看继承性的特点

知识集锦抽象类是给其它类继承用的,抽象类只有被继承了才有意义,因为抽象类不能进行实例化,类中包含有只做声明不去实现,且在抽象类中没有实际意义但对子类有意义,需要子类去重写的抽象方法。定义一个抽象类时要在class关键字前加上‘abstract’关键字。

首先,我们创建一个LovelyCat类,来包裹我们的抽象类,具体类和main方法。如下:

 

 当我们的一个类继承了另外一个类时,这个类可以调用另外一个类里面的属性。接下来让我们看看如何继承:首先,大家仔细观察,上面我们定义的Cat和AiJiCat类它们都是没有使用static关键字进行修饰的动态内部类,而我们创建类的目的就是要实例化一个对象作为一个实体来帮我们解决问题,那么就会不得不在main方法里面进行实例化,而我们的主程序main方法是使用static进行修饰的,如果直接在里面进行实例化一个动态的内部类,就会出现以下错误:

  并给出一个如下的错误提示:

No enclosing instance of type LovelyCat is accessible. Must qualify the allocation with an enclosing

翻译:无法访问LovelyCat类型的封闭实例。必须用一个封闭的。

在我们的java中,静态方法是不能直接调用动态方法的。

面对如上问题,我们可以将之前的所有动态内部类修改成静态(加上static关键字),这样子我们就可以在静态方法中来进行类的实例化了。

出现这种情况的主要原因是因为我们将所有的类都写在了一个LovelyCat类里面,造成了它们成为了内部动态类。当然了,我们也可以如下编写

 我们已经创建好了对象,那么就让它来帮我们解决一些问题吧。现在用这个对象来进行调用父类中的属性,我们可以看到,在父类中的Cat是没有名字的,而我们想要改名字,就需要对这个属性进行重写。还有其他的属性也都可以进行相应的重写操作,如下:

 java面向对象的编程思想里面有这种特点,也是有它存在的必要性的。首先我们使用子类继承父类这种单继承机制,可以让一些具有相同特征或属性的对象(类)重复使用同一个特征或属性,而不用再去频繁的定义该特征或属性的数据类型。如上我们的埃及猫类继承了猫的名字,毛长,性格等属性,就不需要在埃及猫类里面再重新去定义一个字符串类型的名字,字符串类型的性格,布尔型的毛长,我们可以直接去调用父类的属性即可,可能会有人说,他不想继承,就想独立的类依旧是独立的类,没有继承关系。其实也可以,但是当属性很多,多到有几十上百个属性时,每个具有相同特征或属性的类,都自己去定义这几十上百个属性,委实是太累了。类与类之间的这种单继承虽然存在一些单继承机制的限制和缺点,但总体上还是优点要常说点的。

三,面向对象的多态性 

说完了继承,我们接着讲讲多态性

多态性是指在基类中定义的属性和方法子类继承之后,可以具有不用的数据类型,或表现为不同的行为。通常使用方法的重载和方法的覆盖来实现类的多态性。方法的重载请参考Day004,在Day008这一篇博客里面我们着重去认识和使用方法的覆盖。

我们为什么要去使用方法的覆盖呢?那是因为父类中的功能有些并不适合子类(于是子类就重写了父类中的同名方法)。

存在多态,就必然会存在继承。比方说我们Cat类里面的叫声方法里面返回了猫咪都会叫的‘喵喵’声,但是不同类型的猫咪返回的‘喵喵’声肯定是会有所不同的,因此我们就用到了多态,即重写父类的方法。那么我们该怎么使用多态呢?在继承里面因为我们需要的仅仅只是父类的属性,因此我们用的是子类的类型,子类的对象来进行创建对象。但在多态里面想要实现父类的方法,我们就需要使用形如以下的格式来进行创建对象:

父类类名    对象名   =new  子类类名;

如下代码实现:我们去调用类Cat里面的叫声方法jiaoSheng()并进行相应的重写(覆盖)

 我们先给Cat类(父类)的name属性赋值为‘猫咪’,maoChangf赋值‘false’,xingGe赋值为‘优雅温柔’然后再去进行调用(引用)。再对其进行进一步的整理,进行对比,让我们来看看继承和多态的作用及区别:

 

  如上,我们使用了java的继承和多态的特点,都或多或少的会去重写父类的属性或方法。如埃及猫有自己的名字和自己的叫声,但不了解它的人一般都不会知道这些,都习惯性的统称为‘猫咪’,以及认为它的叫声就是‘喵喵’,那么,我们如果想要使用父类的属性以及父类的方法时就需要使用关键字:super。在图中我们可以看到,调用含有super关键字的showMember方法是aj01对象而不是aj02对象。主要是因为我们使用的是父类引用指向子类对象,在多态中,调用成员方法是编译看左,运行看右。(即首先要判断左边的父类里面有没有我们要使用的方法,如果左边的父类里的成员方法被右边的子类重写覆盖,那么我们运行时执行的就是右边子类的方法)。从图上我们可以看到父类Cat中没有showMember,而showMember构建在AiJiCat里面,因此我们只能使用左边为子类类型创建的对象来进行调用。在上面,属性的重写是放在main方法中的,也就是说我们的这个属性重写只针对某一个对象,如果想要所有的对象都可以调用的话,可以直接在子类里面进行重写

如下代码所示:

四,方法的重写覆盖 

 在进行方法的覆盖时需要注意:

1,子类不能覆盖父类中声明为final或static的方法。

2,子类必须覆盖父类中声明为abstract的方法或子类也应声明为abstract。

3,覆盖同名方法时,子类的方法声明也必须和父类中被覆盖的方法的声明相同。

 1,子类不能覆盖父类中声明为final或static的方法。

常用的修饰方法的关键字(修饰符)有五种:public,static,private,final,abstract。

 上面只使用了四种的原因是因为我们的框框比较小,就只能先展示四种,后面我们会讲abstract修饰的方法的。

 运行结果如下所示:

public class FinalMethodsParents {
	public static void main(String[] args) {
		FinalMethodsParents f1=new subClass();
		f1.method();
		f1.PrivateMethod();
		f1.methodStatic();
		f1.FinalMethod();
	}
	public final void FinalMethod(){
		System.out.println("我是个被final关键字修饰的成员方法,即使是作为我的子类,也不能修改哦");
	}
    private  void PrivateMethod(){
		System.out.println("我是个被private关键字修饰的成员方法,即使是作为我的子类,也不能修改哦");
	}
    public  void method() {
		System.out.println("我是个普普通通没有被任何修饰的成员方法,子类可以重写方法来对我进行覆盖");
	}
	public static void methodStatic() {
		System.out.println("我是个被static修饰的成员方法,子类不可以重写方法来对我进行覆盖哦");
	}																																																																																																																																																																																																																																									
}
class  subClass  extends FinalMethodsParents{
//	对父类中被final关键字修饰的方法进行重写
//	public  void FinalMethod() {
//		System.out.println("重写父类final修饰的成员方法成功!!!");		
//	}
	private   void PrivateMethod() {
		System.out.println("重写父类private修饰的成员方法成功!!!");		
	}
	public static  void methodStatic() {
		System.out.println("重写父类中static修饰的成员方法成功!!!");
	}
	 public  void method() {
			System.out.println("重写普通方法成功!!!");
		}
}

 如上图,只有用public修饰而没有用其他修饰符的方法被重写成功。其他的都不能修改,final修饰的直接不能使用--所以注释掉了。因此父类中的方法被final修饰后,子类不能对其进行覆盖,可以防止任何子类修改该类的定义与实现方式【定义为final的方法执行效率要高于非final方法】使用private关键字修饰父类方法时,会隐式的指定为final类型(即子类也不可以修改父类的成员方法)。既然讲到了final方法,那么我们就不得不提一下final类了,如下定义了一个final类: 

 我们去创建一个类来继承它看看:

出现了 爆红,并给出提示:The type SubClass cannot subclass the final class FinalClass。说明了我们不能用一个类去继承final类(即final类不允许其他类继承,不能有子类)。为什么会被定义为final的类呢?其实final类的类型我们也用过,比方说System和String类。这两个类对编译器和解释器的运行起着很大的作用,不能被轻易改变,所以被声明为final类。

2,子类必须覆盖父类中声明为abstract的方法或子类也应声明为abstract。这种情况一般出现在jdk7及以前的版本的接口中--因为它的接口里面,所有的方法都是用public  abstract来进行修饰的,而在jdk8及以后的版本中,支持了静态方法和默认方法。下面我们来看看父类的抽象方法是怎么在子类中覆盖的:

五,接口 

最后,让我们来认识接口。相信大家对接口并不陌生,在我们生活中最常见的是USB接口,USB接口不管你插入的是有线的鼠标,手机数据线,还是优盘,它都能够接纳,那它为什么会有这种通用性呢?主要的原因是因为接口是一种规范,人们在制造这个接口的时候会给一个统一的标准,大家生产的时候就会是同一种接口。java中的接口是抽象方法(方法特征)的集合,接口并不是类,但比编写的方式和类相似,都有属性和方法。

【接口类型可以用来声明一个变量,它们可以成为一个空指针或是绑定在一个以此接口实现的对象】

在接口中也有抽象方法------只有方法的特征,没有方法的实现的一种方法。在java中,有了接口之后会更加的灵活,因为一个对象(类)可以实现多个接口,就类似于c语言中的多继承,扩展了java中类与类之间单继承机制的限制。我们的接口可以用类去实现。如下代码:

接口的特性:

1,不能被实例化,所以是肯定没有构造方法的(即不能通过new来构建对象)

2,实现类可以使用关键字implements实现多个接口(接口之间使用逗号隔开),实现类(普通类)必须实现接口的所有抽象方法。普通类不是抽象类,如果我们使用的是抽象类来实现接口,那么我们可以不必实现接口里面的所有抽象方法。

3,接口中的变量都是公共(全局),静态的常量--既然是常量那就需要给一个初始化值,并且变量名字母都要大写。方法都是全局抽象方法。

【接口一般使用大写的I来作为首字母来命名,表明当前为一个接口】

1,类与类之间是继承关系,用extends连接。

2,类与接口之间是实现关系,用implements连接。

3,接口与接口之间是也继承关系,也用extends连接。【只要是继承关系就是单继承机制】

抽象类与接口两者的优点

1,抽象类因为可以被继承而不会被实例化,所以利于代码复用。

2,接口因为只对外提供一个接口和规格,所以利于代码维护。

首先,我们创建一个用来继承的抽象类Door,并在里面创建抽象方法notLock。

 接着我们分别创建两个功能不同的接口,一个拿来提醒电量,一个拿来提醒我们离开时门的状态

 

 之后我们去写一个实现类来实现接口并继承Door类,代码实现如下:

如果我们在编写代码时,常量或方法冲突了,我们用如下的方案进行解决:

1)常量冲突:需要明确指定常量的接口【接口名.常量名】

2)方法冲突:则只要实现一个方法就行。

 Day008的博客就结束了,想要源代码的评论区回复,到时候我发一个不要钱的资源---之前不小心发了一个资源,里面Day008的资源不足,大家不要去下载,那个没啥用。

文章后记:实现书店买书程序

留下一个小问题:设计一个新华书店买书程序---描述:如果购买者买到自己需要的的书籍则提示购买者在该新华书店买到了该书籍,反之没有则提示购买者白跑一趟。

有代码实现和头绪的可以自己去尝试一下,如果结果出来了可以发评论圈大家一起品读。

✿✿ヽ(°▽°)ノ✿

模板案例:

 代码实现:
 

public class Object1 {  //测试类
	public static void main(String[] args) {
		Product product1 =new Product();
		Product product2 =new Product();
		product1.setP_name("《三年高考五年模拟》");
		product2.setP_name("《一千零一夜》");
		Market market =new Market();
		market.setM_name("新华书店");
		market.setProductArr(new Product[] {product1,product2});
		Person person=new Person();
		person.setName("小明");
		String result=person.shopping(market, market.sell("《scala编程》"));
		if(result ==null) {
			System.out.printf("%s白跑一趟",person.getName());
		}else {
			System.out.printf("%s在%s买到他想要的%s", person.getName(),market.getM_name(),person.getProduct_name());
		}
	}

}
class Market {   //店铺类
	private String m_name;   //私有化的店铺名
	
	public String getM_name() {   
		return m_name;
	}

	public void setM_name(String m_name) {
		this.m_name = m_name;
	}

	private Product[] productArr;   //商品列表

	public Product[] getProductArr() {
		return productArr;
	}

	public void setProductArr(Product[] productArr) {
		this.productArr = productArr;
	}
	String sell(String name) {      //店铺卖书
		for(int i=0;i<productArr.length;i++) {
			if(productArr[i].getP_name()==name) {   //遍历商品列表,如果有则返回商品名字
				return productArr[i].getP_name();
			}
		}
		return null;                                  //没有商品,返回值为空
	}
	
}
class Product{                     //商品类
	private String p_name;

	public String getP_name() {
		return p_name;
	}

	public void setP_name(String p_name) {
		this.p_name = p_name;
	}
	
}
class Person{                         //顾客类
	private  String name;
	private String product_name;
	public String getProduct_name() {
		return product_name;
	}
	public void setProduct_name(String product_name) {
		this.product_name = product_name;
	}
	String  shopping(Market market,String product_name) {     //顾客购买书籍
		this.product_name=product_name;
	 return market.sell(product_name);
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值