黑马程序员——Java基础知识——面向对象(二)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!

 一、继承

       什么是继承:

        面向对象的一个重要特征,在以后的操作中会经常使用。当多个类中存在相同属性或行为时,将这些相同的内容抽取到单独一个类中,那么多个类无需再定义这  些属性和行为,只要继承这个类即可。那个单独的类称之为父类,其他的类就是子类。例如工人和学生都可以向上抽取出人这个父类,在父类中定义姓名、年龄等属  性,然后通过继承,工人和学生也具备了这种属性。在代码中通过extends表示继承关系。当类与类之间有了继承的关系,子类可以直接访问父类中的非私有的属性  和行为。继  承的出现提高了代码的复用性。让类和类之间产生了关系,有了这个关系,提供了多态的前提。在Java语言中,只支持单继承,不支持多继承,但Java  中有另一种体现  方式,叫多实现,在以后会学习到。注意,当类与类之间有所属关系时才可以继承。这种所属关系称为is a.

      如何使用继承:

            Java中可以多层继承,就是建立一个继承体系,如同爷爷、父亲和孩子的关系,例如:

            class A{}

           class B extendsA{}

            class C extendsB{}

        当要使用一个继承体系中所具备的功能时,要先查体系中父类的描述,因为父类中定义的是该体系中的共性功能。通过了解共性功能,就可以知道该体系中的  基本功能。这样这个体系就可以基本使用了;而在具体调用时,要创建最子类的对象,因为父类可能无法创建对象,而子类对象中又有更多的功能,除了基本功能外  还有其特有的。总结为一句话就是:查阅父类功能,创建子类对象使用功能。

 例如:

class Person
{
   //在父类中定义都共同具有的姓名、年龄属性以及睡觉的方法。
   String name;
   int age;
   public void sleep(){
	 System.out.println("sleep");}
}
class Worker extends Person
{  //因为继承父类,也具备父类的属性以及睡觉的方法,并定义工人特有的方法
   public void work(){
	 System.out.println("work");}
}
class Student extends Person
{  //因为继承父类,也具备的属性以及睡觉的方法,并定义学生特有的方法
   public void study(){
	 System.out.println("study");}
}

   3.继承中成员的特点

     (1)成员变量:如果子类中出现非私有的同名成员变量时,子类访问本类中的变量,用this,访问父类中的同名变量,则要用super。super和this都存在于方法  区中,使用方法相似。this表示本类的引用,super表示父类的引用。

     (2)成员方法:当子类和父类有一模一样的方法时,当子类对象调用该方法,会运行子类方法的内容,如同父类的方法被覆盖,这种情况称为:重写(覆盖)。

 当子类继承父类,沿袭了父类的方法,在子类中方法的内容却与父类不同,这时就可以用到重写,保留父类的方法定义,重写方法内容。子类的方法中同时具有父类

 方法中的内容时,可以用super.方法。例如:

class Person
{
     public void sleep(){
	 System.out.println("sleep");
     }
}
class Worker extends Person
{  //复写父类方法
   public void  sleep(){
	   System.out.println(" earlier to sleep");
   }
}
class Student extends Person
{  //复写父类方法,并调用父类方法。
   public void sleep(){
       super.sleep();
       System.out.println("第二天早起读书");
   }

}
     要注意几点:子类要覆盖父类,必须保证子类权限大于或等于父类权限,才可以覆盖,否则编译失败;静态只能覆盖静态;父类中的私有方法不能被重写。

      (3)构造函数

        在对子类对象进行初始化时,父类的构造函数也会运行,因为子类的每一个构造函数默认的第一行都有一条隐式的super()。通过super()语句,会访问父类中空  参数的构造函数。子类对象在初始化时一定要访问父类中的构造函数,是因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这  些数据进行初始化的。所以子类在对象初始化时,要先访问父类中的构造函数。如果要访问父类中非空参数的构造函数,需要通过定义super语句来指定,同this语句  一样,super语句也必须定义在构造函数中的第一行。子类的构造函数第一行也可以定义this语句来访问本类中的构造函数。总之,子类中至少会有一个构造函数访问  父类中的构造函数。

  final关键字

        final(最终),作为一个修饰符。具有以下特点:

        1、可以修饰类、函数、变量。

        2、被final修饰的类不可以被继承。这样就可以避免被继承、被子类复写功能。

        3、被final修饰的方法不可以被覆盖。

        4、被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,又可以修饰局部变量。

       当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便于阅读。而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成,单词间通过_连接。

        5、内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。

 

 二、抽象类

           多个类中出现相同功能,但功能具体内容不同,那么在抽取过程中,只抽取了功能定义,并没抽取功能主体,那么只有功能声明,没有功能主体的方位称为抽  象方法。抽象方法没有方法主体,方法的具体实现由该类的子类去完成。包含抽象方法的类叫做抽象类。例如:

abstract class Person
{
	//定义表示睡觉的抽象方法
	public abstract void sleep();
}

class Worker extends Person
{
	//工人睡觉的具体方法
	public void sleep(){
	    System.out.println("早睡");
	}
}

class Student extends Person
{
	//学生睡觉的具体方法
	public void sleep(){
	    System.out.println("晚睡");
	}
}
        从上面的代码可以看出,抽象类和抽象方法都必须用abstract修饰。抽象方法定义在抽象类中,但同时抽象类中也可以有非抽象方法,抽象方法没有方法主体,只  有方法声明。抽象类不可以被创建对象,因为调 用抽象方法没有意义。抽象类中的抽象方法要被使用,必须由子类覆盖抽象类中的所有抽象方法,然后建立子类对象  调用,否则子类还是抽象类。

       抽象类与一般类相比,没有太大的不同,都是描述事物,只不过该事物中出现了一些不知道具体内容的方法部分。这些不确定的部分,也是该事物的功  能,需要明确出来,但是无法定义主体。通过抽象方法表示;抽象类比一般类多了一个或多个抽象函数,并且不可以被实例化;抽象类虽然不能创建对  象,但是也有构造函数,供子类实例化调用。

         注意的是,抽象类中也可以没有抽象函数,这样做是为了不让建立该类的对象。在使用abstract关键字修饰方法和类时,不能同时使用private、final、  static进行修饰。因为final修饰的类不能被继承,而抽象类是一个父类;private修饰的方法不能被复写,而抽象方法必须被复写;static修饰的方法,不需要  对象调用,而抽象方法运行没有意义。

          下面就通过一段代码,说明抽象类的使用。如下:

  

/**

需求:开发一个系统时需要对员工进行建模,员工包含3个属性:姓名、工号以及工资。
      经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。请使用继承的思
      想设计出员工类和经理类。

员工类:name id pay

经理类:继承了员工,并有自己特有的bonus。

*/
//定义员工类,定义所有公司成员的共同属性和方法
class Employee
{
	//定义共同的姓名、工号、工资的属性
	private String name;
	private String id;
	private double pay;

	Employee(String name,String id,double pay)
	{
		this.name = name;
		this.id = id;
		this.pay = pay;
	}
	//定义工作的抽象方法,工作内容由员工根据工作范围自己去实现。
	public abstract void work();

}

class Manager extends Employee
{    
	//定义经理类特有的奖金属性
	private int bonus;
	Manager(String name,String id,double pay,int bonus)
	{   
		super(name,id,pay);
		this.bonus = bonus;
	}
	//经理的具体工作内容
	public void work()
	{
		System.out.println("manager work");
	}
}

class Pro extends Employee
{
	Pro(String name,String id,double pay)
	{
		super(name,id,pay);
	}
	//普通员工的具体工作内容
	public void work()
	{
		System.out.println("pro work");
	}
}
      模板方法:在定义功能时,功能的一部分是确定,但是有一部分是不确定的,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去。由该类的 的子类去完成。如果不确定的方法没有默认的方法主体,就用抽象方法表示,然后由子类去复写。例如:

/**
需求:获取一段程序运行的时间。
原理:获取程序开始和结束的时间并相减即可。

*/

abstract class GetTime
{   
	public final void getTime()
	{
		//表示程序开始时的时间
		long start = System.currentTimeMillis();

		runProgram();

		//表示程序结束时的时间
		long end = System.currentTimeMillis();

		System.out.println("毫秒:"+(end-start));
	}
	//具体程序未知,用抽象方法表示
	public abstract void runProgram();

}


class SubTime extends GetTime
{
    //定义具体的运行程序 
	public void runProgram()
	{
	        for(int x=0; x<3000; x++)
		{
			System.out.print(x);
		}
	}
}
  

 三、接口
       
可以理解为一个特殊的抽象类,但接口中的方法都是抽象的。当一个类中所有的方法都是抽象时就可以用接口来表示,接口用interface关键字来表示,而子类与接口通过implements(实现)产生关系,并必须覆盖其所有抽象方法,才能创建子类对象,否则该类是个抽象类。接口中常见的定义是常量和抽象方法。两者都有固定的修饰符,常量:public static final ;方法:public abstract;也可以在常量和方法前不写这些修饰符,编译时会自动添加,但为了提高阅读性,一般时候都加上。下面通过一段简单的代码,了解一下接口及其子类的格式,如下:

//定义一个类表示男子的接口
interface Man
{
	//定义性别属性,常量用大写字母表示
	public static final String SEX="man";
	//定义表示工作的抽象方法
	public abstract void work();
}
//定义一个类表示年轻男子,实现Man接口
class YoungMan implements Man
{
  //覆盖接口中的抽象方法
  public void work()
  {
    System.out.println("工作时间长");
  }
}
        接口是对外暴露的规则,接口的出现降低了耦合性,能对程序的功能进行扩展;类与接口是实现关系,java支持多实现,一个类可以继承一个类的同时 实现多个接口; 而接口和接口之间是继承关系。在使用接口时要注意,子类需覆盖接口中的所有抽象方法,否则子类还是个抽象类;当一个类实现多个接口时,多个接口中不能有返回值类型不同的同名抽象函数,这样子类无法实现复写。
        接口与抽象类都是由下向上抽取出来的。但两者又有很多区别:抽象类体检继承关系,父类与子类是"is a"的关系,一个类只能继承一个抽象类,而接口体现实现关系,接口与子类是"like a"关系,一个类可以实现多个接口;抽象类中可以定义非抽象方法,子类可以直接使用,类中可以定义私有变量和方法。而接口中所有的方法都是抽象的,并且所有成员都有固定的修饰符,所有成员的权限都是公有的;下面看一个接口与抽象类都有应用的程序,例如:

//定义一个抽象类,表示人  
abstract class Person  
{     
    //定义抽象的饮食方法  
    abstract void eat();  
    //定义共同的睡觉方法  
    void sleep()  
    {  
        System.out.println("sleep");  
    }  
}  
  
//定义一个接口,表示训练 
interface Training
{  
    public abstract void train();  
}  
  
//定义表示运动员的Athlete类,继承Person类,实现训练接口  
class Athlete extends Person implements Training  
{  
    //复写饮食方法  
    void eat()  
    {  
        System.out.println("多吃牛肉");  
    }  
  
    //复写训练方法  
    public void train()  
    {  
        System.out.println("每天都要训练");  
    }  
}  
  
//定义表示学生的Student的类,不训练
class Student extends Person 
{     
    //复写饮食方法  
    void eat()  
    {  
        System.out.println("多吃蔬菜");  
    }  
}  
  
  


  -------------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值