java面向对象三大特征:封装、继承、多态

目录

 

一、封装(encapsulation)

封装要点

二、继承

三、多态(polymorphism)

多态要点


一、封装(encapsulation)

       什么是封装?举个例子,比如一台电视机,电视机内部有复杂的各种器械,而展现在外部的只有开关和几个按键。封装可以抽象的理解为就是那个电视机壳子,它将复杂的东西“包”起来,只保留简单的对外接口。

       专业一点来说,封装就是将对象的属性和方法尽可能隐藏内部的复杂性,只保留有限的简单的对外接口便于外界的调用。封装的特性使得对象以外的部分不能随意存取对象的内部数据(属性),保证了程序和数据不受外部干扰且不被误用,从而提高系统的可扩展性、可维护性。我们的程序设计要追求“高内聚,低耦合”,高内聚 :就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合 :仅暴露少量的方法给外部使用

       那么我们如何去实现封装呢?实现封装,需要使用访问控制符,访问控制符一共有四种,public(公共的),protected(受保护的),default/friendly(默认的/友好的),private(私有的)。

       对于类的访问权限只有两种:

              1、public   可被同一项目中所有的类访问。 (必须与文件名同名) 

              2、default/friendly  可被同一个包中的类访问

       对于类中成员(成员变量或成员方法)访问权限共有四种:

              1、public  可以被项目中所有的类访问。(项目可见性) 

              2、protected   可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问

              3、default/friendly  可以被这个类本身访问;被同一个包中的类访问。(包可见性) •

              4、private   只能被这个类本身访问。(类可见性) 

封装要点:

       类的属性的处理: 

              1、一般使用private。 (除非本属性确定会让子类继承)

              2、提供相应的get/set方法来访问相关属性。这些方法通常是public,从而提供对属性的读取操作。

              3、boolean变量的get方法是用:is开头! 

              4、一些只用于本类的辅助性方法可以用private, 

              5、希望其他类调用的方法用public

接下来我们用一个程序去具体的理解封装:
 

package cn.cou.pack;

public class TestEncapsulation {  //此类可被同一项目中所有的类访问
	public static void main(String[] args) {

		Human h = new Human();
	      //h.age = 13;  //在此处age用不了
		h.age1 = 13;
		h.age2 = 14;
		h.age3 = 15;
                h.sayAge();
	}

}

class Human {   //此类为默认权限default,可被同一个包中的类访问

	private   int age;   //只在此类(Human)中可用
	          int age1;  //可被同一包中的类访问
	protected int age2;  //可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问
	public    int age3;  //可以被项目中所有的类访问
	
	void sayAge() {
		System.out.println(age);
	}
}

二、继承

       java的继承通过extends关键字来实现,实现继承的类被称为子类,被继承的类称为父类,父类和子类的继承关系是从一般到特殊的关系,比如说,水果和苹果的关系,苹果继承了水果,苹果是水果的子类,水果是苹果的父类。另外,extends的英文意思是“扩展”,至于为何国内把他翻译成继承就不知道了,因此,我们可以理解为,子类是父类的扩展,子类会获得父类的全部属性和方法,但是要注意的是子类不能获得父类的构造方法,以及父类中被private修饰的变量或方法。

       java中只有单继承,也就是说,一个子类只能继承自一个父类,每个子类只有一个直接父类,不过,一个父类是可以有多个子类的,这一点可以联想到树形图。java中可以通过接口实现多继承。不过多继承是有弊端的,多继承会引起混乱,使得继承链过于复杂,系统难于维护。就像我们现实中,如果你有多个父母亲,那是一个多么混乱的世界。多继承,就是为了实现代码的复用性,却引入了复杂性,使得系统类之间的关系混乱。 

       如果定义一个类时,没有调用extends,则它的父类默认是:java.lang.Object。

我们沿用并加以扩展上面讲述封装时的程序,进行详细描述:

package cn.cou.pack;

public class TestExtends {  //此类可被同一项目中所有的类访问
	public static void main(String[] args) {
		
		Human1 h = new Human1();
	      //h.age = 13;  //在此处age用不了
		h.age1 = 13;
		h.age2 = 14;
		h.age3 = 15;
		h.sayAge();
		
		Man man = new Man();
              //man.age = 1;   // 此处age依然不可用,private修饰的age只在Human1类中可用
		man.age1 = 2;
		man.age2 = 3;
		man.age3 = 4;
		man.sayAge();
		man.work();
	}

}

class Human1 {   //此类前没有修饰,说明为默认权限default,可被同一个包中的类访问
	private   int age;   //只在此类(Human1)中可用
	          int age1;  //(默认权限default)可被同一包中的类访问
	protected int age2;  //可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问
	public    int age3;  //可以被项目中所有的类访问
	
	void sayAge() {      //此方法前没有修饰,说明为默认权限default,可被同一个包中的类访问
		System.out.println(age);
	}
}

class Man extends Human1{   //子类Man继承父类Human1
	
	void work() {
		System.out.println("工作工作工作!!!");
	}
}

      接下来详细的说一下,子类与父类在继承后,变量、方法的关系:

        1、子类可以继承父类的所有特性,但其可见性,由父类成员变量、方法的修饰符决定。

                   ①、对于被private修饰的类成员变量或方法,其子类是不可见的,也即不可访问;

                   ②、对于定义为默认访问(没有修饰符修饰)的类成员变量或方法,只有与父类同处于一个包中的子类可以访问;

                   ③、对于定义为public或protected 的类成员变量或方法,所有子类都可以访问。

        2、子类中可以声明与父类同名的成员变量,这时父类的成员变量就被隐藏起来了,在子类中直接访问到的是子类中定义的成员变量。

        3、子类中也可以声明与父类相同的成员方法,包括返回值类型、方法名、形式参数都应保持一致,称为方法的重写(override),重写方法不能使用比被重写方法更严格的访问权限(由于多态)。

        4、被隐藏的父类成员变量、方法是可以被引用的,通过super来实现对被隐藏或被覆盖的父类成员的访问。

               ①、访问父类被隐藏的成员变量和成员方法: super.父类成员变量名

               ②、调用父类被隐藏的方法:super.父类成员方法名([参数列表])

               ③、调用父类的构造方法:super([参数列表]),需要注意到是:super( )只能在子类的构造函数中出现,并且永远都是位于子类构造函数中的第一条语句。

下面用程序举例说明,请详细分析,好好理解:

package cn.cou.pack;

public class TestExtends {  //此类可被同一项目中所有的类访问
	public static void main(String[] args) {
		
		Human h = new Human();
	      //h.age = 13;  //在此处age用不了
		h.age1 = 13;
		h.age2 = 14;
		h.age3 = 15;
		h.sayAge();
		
		Man man = new Man();
              //man.age = 1;   // 此处age依然不可用,private修饰的age只在Human类中可用
		man.age1 = 2;
		man.age2 = 3;
		man.age3 = 4;
		man.sayAge();
		man.work();
	}

}

class Human {   //此类前没有修饰,说明为默认权限default,可被同一个包中的类访问
	private   int age;   //只在此类(Human)中可用
	          int age1;  //(默认权限default)可被同一包中的类访问
	protected int age2;  //可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问
	public    int age3;  //可以被项目中所有的类访问
	
	long number = 8000000000L;
	
	void sayAge() {      //此方法前没有修饰,说明为默认权限default,可被同一个包中的类访问
		System.out.println("age1 = "+age1);
		System.out.println("fnumber = "+number);
	}
	
	Human() //父类的构造方法(每一个类都至少有一个构造方法,如果此处我们不写,系统会默认为我们创建一个无参的构造方法,而且不显示)
	{
	}
}

class Man extends Human{   //子类Man继承父类Human
	
	long number = 40000000000L;//覆盖了父类的number变量
	
	void sayAge() //隐藏了父类的sayAge方法
	{
		System.out.println("age1 = "+age1);
		System.out.println("znumber = "+number);
	}
	
	void work() {
		System.out.println("工作工作工作!!!");
		System.out.println("super.number = "+super.number);//调用父类中被隐藏的成员变量
		
		super.sayAge();//调用父类的sayAge方法
	}
	
	Man()//子类的构造方法
	{
		super();//调用父类的构造方法
	}
}

       值得注意一点是:Object类是所有java类的根基类,如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类 ,比如上述代码中TestExtends类,未指明其父类,则其父类就为Object类。如果你使用的编译软件是eclipse,可以选中TestExtends类,点Ctrl+T,就可以查看他的继承关系。

三、多态(polymorphism)

        多态指的是同一个方法调用,由于对象的不同可能会有不同的行为,比如在我们现实生活中,用同一个方法比如玩,不同的对象,比如男生玩可能就是打游戏,女生玩可能就是逛街买东西。同样都是玩,对象不同,行为可能就会不同。

        多态的定义格式:

                   定义格式:父类类型 变量名 = new 子类类型();

        多态的要点:

               1、多态是方法的多态,不是属性的多态,多态与属性无关。

               2、多态的存在要有3个必要条件:要有继承,要有方法重写,父类引用变量指向子类对象

               3、父类引用变量指向子类对象后,用该父类引用调用子类重写的方法,此时就出现了多态。

       引用变量的两种类型:

               1、编译时类型(一般是一个父类):由声明时的类型决定

               2、运行时类型(运行时,具体是哪个子类就是哪个子类):由实际对应的对象类型决定。 

       对象的转型:

              父类引用变量指向子类对象,这个过程称之为向上转型(子转父),属于自动类型转换,向上转型后的父类引用变量只能调用它编译时类型的方法,不能调用它运行时类型的方法。如果想要调用它运行时类型的方法,需要进行类型的强制转换,我们称之为向下转型(父转子),在向下转型过程中,必须将引用变量转成真实的子类类型(运行时类型),否则会出现类型转换异常。

               1、向上转型,多态本身就是向上转型过的过程

                    使用格式:父类类型   变量名  =  new   子类类型();

                    注意: 上转型对象不能操作子类新增的成员变量和方法,可以操作子类继承或重写的成员变量和方法 ,如果子类重写了父类的某个方法,上转型对象调用该方法时,是调用的重写方法。 

               2、向下转型,一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型

                    使用格式:子类类型   变量名  =(子类类型) 父类类型的变量;

       拓展:instanceof关键字,它的作用是用来判断某个对象是否属于某种数据类型。返回值类型为布尔类型。

案例:

package cn.cou.pack;

public class TestPolymorphism {  //此类可被同一项目中所有的类访问
	public static void main(String[] args) {
	
		Human2 h = new Human2();
		System.out.println("-----------父类:");
		h.Hu();
		h.stu();

		
		Man1 man = new Man1();
                System.out.println("-----------子类:");
                man.Hu();
                man.study();
        
        
                Human2 m = new Man1();//自动向上转型(编译时系统认为 m 是Human2的类型,只有在运行时才知道是Man1的类型)
        
                System.out.println("----------子转父:");
                m.Hu();    //调用的是子类重写的方法
                m.stu();   //父类方法
              //m.study(); //不能使用子类新增的成员变量和方法

                if(m instanceof Man1)
                	System.out.println("m是Man1的类型");
                else
                	System.out.println("m是Human2的类型");
        
       
        
                Man1 n = (Man1) m;//强制向下转型
        
                System.out.println("----------父转子:");
                n.Hu();    //子类重写的方法
                n.stu();   //父类方法
                n.study(); //子类方法
                System.out.println(n instanceof Man1);//判断n是否是Man1的类型
	}

}


class Human2 {  
	
	void Hu() {
		System.out.println("Hu");
	}
	void stu() {
		System.out.println("学习!");
	}

	
}

class Man1 extends Human2{   //子类Man1继承父类Human2

	
	void Hu() {   //重写Hu方法
		System.out.println("Ma");
	}
	
	void study() {
		System.out.println("好好学习天天向上!");
	}
	
}

结果:

-----------父类:
Hu
学习!
-----------子类:
Ma
好好学习天天向上!
----------子转父:
Ma
学习!
m是Man1的类型
----------父转子:
Ma
学习!
好好学习天天向上!
true


 

 

       

 

 


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值