Java基础(7):面向对象三大特性—封装、继承和多态的详解

来源:互联网 发布:淘宝类目属性数据库 编辑:程序博客网 时间:2024/05/21 13:22

一、封装(encapsulation)

从表面意思来看就是封闭的包装。而Java中,一个类有属性和方法,但是不可能想修改就修改,毫无安全性可言,而且有的类只适用于某一场景,其内部的方法和属性不对外开放。这就是封装的作用,用来设置访问权限。

下图为Java的访问权限符和其作用域

访问范围从大到小:public --> proetected --> default --> private

public:修饰之后,能被所有类访问,访问权限最宽松。

protected: 作用域只在同类、同包和子类中,protected使用最多场景就是父类方法给子类重写。

default: 作用域只在同类和同包中。未使用权限修饰符,默认采用。

private: 作用域只在同一个类中。常用的就是成员变量私有化,只有同一个类中才能访问。即暴露出来的setter 和 getter方法来访问,保证了安全性。还有对构造器私有化。工厂模式或者单例模式中有用到。注意,默认构造器私有时,其子类的构造器无法使用,这涉及到子类初始化时会对父类初始化。


import 与 package 关键字的区别:

package 表示当前类属于那个包中。从作用域来看,包也是一种权限,不同包的类是无法相互访问的,包的作用域和default差不多。

import是用来导入别的包。比如要使用Math类,但Math类不属于同一个包中,那相当于不存在,所以无法使用。这就需要import 来导入一个Math类所在的包,这样才可以使用该包中的类。

在Java中,java.lang包是默认导入的,里面都是java的核心类,如String 类等。

二、继承(extend)

使用继承,子类可以得到父类所有字段和方法,除了private所修饰的。继承增加了代码的复用。而且继承是多态实现的基础。
多说一下,继承只能单继承,但是接口却可以实现多个,接口相当于是多继承。但是接口是一个特别抽象类,只提供规范,不提供具体实现。而且接口中只能定义常量。
下面代码可以看出继承和包权限的作用:
package com.test1; //使用com.test1 包//A类作为父类public class A {private int a; //私有化protected int b; //子类能访问public int c;//访问权限最高public static int d = 10086; //A的静态变量public static void infoPub() {System.out.println("A类的public方法 :" + new A().a);} //a是私有的,在同类中可以访问protected static void infoPro() {System.out.println("A类的protected方法");}private static void infoPri() {System.out.println("A类的private方法");}}
package com.test2;//使用com.test2 包import com.test1.A; //A类不在同包中,所以要导入。//继承A类public class B extends A {//调用继承A类的方法public void testB() {infoPro(); //A类的protected修饰的方法infoPub(); //A类的public修饰的方法System.out.println(d);//子类也能获得父类的类变量}//在B中类中启动主方法来测试public static void main(String[] args) {B b = new B();//B类中只能得到A类的 b变量和c变量 //b 是 protected修饰的,子类中能访问//c 是public修饰的,哪里都能访问System.out.println(b.b);System.out.println(b.c);b.testB();}}
使用另一个非子类来测试,可以看到只有c变量能被访问到,而b变量已经无法访问了,因为b变量是protected修饰。
下图会看到有equals() 、getClass()、hasCode()等方法 。这是因为在Java中,有一个基类,那就是Object类,他是所有类的父类,只要创建一个类就默认继承了Object类,所以会得到Object类的方法。在类型转换中,所有类都可以转换成Object类。





三、多态(Ploymorphism)

多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。

按个人理解,就是做同样的事情,呈现不同的结果。而且多态提高了代码的通用性和灵活性,在面向对象中,多态是重点。

要实现多态的前提:
一、要有继承关系;
二、子类对父类进行重写;
三、父类引用指向子类对象
下面给上一个简单的多态实现代码:
package com.test.polymorphsim;//父类public class Father {public int a;protected Father() {System.out.println("Father类的默认构造器");}//看书protected void  readBook() {System.out.println("Father喜欢看科学书");}//玩游戏protected void playGame() {System.out.println("Father喜欢玩体育游戏");}}//大儿子类class Son1 extends Father{public Son1() {System.out.println("Son1默认构造器");}//重写父类方法@Overrideprotected void readBook() {System.out.println("大儿子喜欢看游戏书");}//如果Son1类不重写父类的playGame(),多态时调用就会调用父类的该方法@Overrideprotected void playGame() {// TODO Auto-generated method stubsuper.playGame();}}//二儿子类class Son2 extends Father{public Son2() {System.out.println("Son2默认构造器");}@Overridepublic void readBook() {System.out.println("二儿子看编程书");}@Overridepublic void playGame() {System.out.println("二儿子喜欢玩单机游戏");}}//三儿子类class Son3 extends Father{public Son3() {System.out.println("Son3默认构造器");}@Overrideprotected void readBook() {System.out.println("三儿子看数学书");}@Overrideprotected void playGame() {System.out.println("三儿子玩数字游戏");}}
package com.test.polymorphsim;public class Test {public static void main(String[] args) {//父类引用指向子类对象Father son1 = new Son1();Father son2 = new Son2();Father son3 = new Son3();//传入上面参数show(son1);show(son2);show(son3);}//根据传入的Father对象,呈现不同结果//传入一个Father类型参数,调用Father类中的方法。public static void show(Father fa) {fa.readBook();fa.playGame();}}
//输出结果Father类的默认构造器Son1默认构造器Father类的默认构造器Son2默认构造器Father类的默认构造器Son3默认构造器大儿子喜欢看游戏书Father喜欢玩体育游戏二儿子看编程书二儿子喜欢玩单机游戏三儿子看数学书三儿子玩数字游戏
在show()方法中,只要传入一个Father参数,就可以调用其中的readBook() 和 playGame() 方法。也就是方法是固定的,但是根据我们传入的参数,会出现不同的结果。这就是多态的灵活性和通用性。

在输出结果中会看到出现三次Father类的默认构造器。这是因为在Java中,只要创建一个类的对象,就意味着该类会被初始化。
这要提到Java的类加载机制,步骤简要分为三步,加载--连接--初始化,一般情况都是直接完成三步。在初始化一个类时,会先初始化该类的父类,保证一整个继承体系都初始化完成,才能开始使用该类。
在上面代码中创建了三个子类对象,所以父类的无参构造器会被调用三次。






0 0