Java中的封装、继承、多态

面向对象语言中都有三大属性:封装、继承、多态。
此处记录一下我对三者的理解,以后会不断修正!

编程就是登山!

封装

封装是面向对象语言的基础属性。从包、类、方法的创建中:我们一直在做一件事,将某一个功能的具体实现尽量隐藏,只提供少量的外部接口来给用户使用。现实生活中,我们使用的很多东西都是如此,比如说手机。普通用户不需要知道手机内部电路板是如何走线,芯片是如何排布,软件是如何运行的;我们只需要使用它的打电话软件、上网用的浏览器就够了。实现过程交给工程师已然足够!

包(package)

我们在引入类时,有时会出现类名相同的情况,我们需要更精确地界定类的出处。因此,包的存在必不可少,它将向我们区分相同名称的类的区别!

包的使用

首先看如下代码:

public class Demo {
    public static void main(String[] args) {
        java.util.ArrayList list = new java.util.ArrayList();
        java.util.ArrayList list1 = new java.util.ArrayList();
    }
}

我们实例化了java.util包中的ArrayList类,如果我们要是创建了自己的ArrayList,包名的介入会将两者区分。但如果我们总是带上包名引用该类的话就显得太过繁杂;因此,我们可以使用导入命令(import)来简化代码,当我们在导入包后就可以直接使用类名了。(如果真的存在同时调用不同包中的同名类,还是得加上包名,但这种情况比较少见):

import java.util.ArrayList;
public class Demo {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
    }
}

当我们要导入包中多个类时,可以使用包名.*

import java.util.*;
public class Demo {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
    }
}

这样我们就能够直接使用java.util中的所有类了。

包的创建

程序员一般将自己创建的轮子保存在本公司的包中以待以后使用,避免重复工作。为了防止包名也重复,大家默认包名一般以公司域名倒写+项目名来命名,如果没有域名,那就起一个非常难见到的包名。比如说我要创建一个包,可以命名为online.suiyu.test要注意包名一般都是小写的。
那我们如何在代码中实现呢?看下方代码:

package online.suiyu.test;
public class Demo {
    public static void main(String[] args) {
        System.out.println("hello");
    }
}

这样,我们就将Demo.java放入到了online.suiyu.test包中。但这还没结束,我们需要使用如下方法编译源文件:

javac -d . Demo.java

这样,我们就编译了包与类文件。此时我们查看文件将会发现当前目录下存在如下目录:

D:.
├─online
│  └─suiyu
│      └─test

这是包的表现形式,Demo.java就存在于test文件夹中!当然,如果想保存到其他路径可以直接指定目录即可:

//将包保存到D:\java目录
javac -d D:\java DemoClass.java

如果使用eclipse的话,直接在创建类的时候也能指定包,不指定的话就是default包。

JAR包的创建与使用

jar包其实也是压缩包的一种,可以使用压缩软件打开。

在命令行中,输入jar,可以看到以下提示

$ jar
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] fi                                                                     les ...
选项:
    -c  创建新档案
    -t  列出档案目录
    -x  从档案中提取指定的 (或所有) 文件
    -u  更新现有档案
    -v  在标准输出中生成详细输出
    -f  指定档案文件名
    -m  包含指定清单文件中的清单信息
    -n  创建新档案后执行 Pack200 规范化
    -e  为捆绑到可执行 jar 文件的独立应用程序
        指定应用程序入口点
    -0  仅存储; 不使用任何 ZIP 压缩
    -P  保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件
    -M  不创建条目的清单文件
    -i  为指定的 jar 文件生成索引信息
    -C  更改为指定的目录并包含以下文件
如果任何文件为目录, 则对其进行递归处理。
清单文件名, 档案文件名和入口点名称的指定顺序
与 'm', 'f' 和 'e' 标记的指定顺序相同。

示例 1: 将两个类文件归档到一个名为 classes.jar 的档案中:
       jar cvf classes.jar Foo.class Bar.class
示例 2: 使用现有的清单文件 'mymanifest' 并
           将 foo/ 目录中的所有文件归档到 'classes.jar' 中:
       jar cvfm classes.jar mymanifest -C foo/ .

根据提示:

压缩指定文件(多个文件或文件夹):

jar -cf Demo.jar online

生成了名为Demo.jar的jar包。

查看jar包中的文件列表

$ jar -tf Demo.jar
META-INF/
META-INF/MANIFEST.MF
online/
online/suiyu/
online/suiyu/test/
online/suiyu/test/Demo.class

可以看到已经压缩的文件夹与文件(其中添加了一些特殊文件及文件夹)

运行jar中的class文件

$ java online.suiyu.test.Demo
hello

和没压缩一样,只要指定包名+类名直接使用就行了。

类的存在隐藏了具体实现,防止别人更改代码,更加安全!

类中使用以下控制符控制访问权限:

private default protected public
同一类中
同一包中
子类中
全局范围内

继承

简单介绍

当我们创建了类时,就已经完成继承了,因为所有类的标准根类都是Object类,编译器会自动完成继承的过程。我们要实现继承的话一般使用extends关键字。这里记录一般类的特点:

  • 就像是人都有一个亲生父亲,而一个父亲可以有很多儿子一样,类可以有很多子类,但只能有一个父类
  • 子类继承父类后,可以拥有父类的方法和属性,并且可以添加、覆盖、重写父类的方法
  • 子父类的继承受类的控制符约束
  • 父类有非默认构造器时,子类也必须写出构造器,并在子类构造器第一行调用super来加载父类构造器
  • 子类可以在重写父类方法后依然调用父类方法,需要加入super区分;为了区分调用的是自己的方法可以加上this(也可省略)
  • 父类与父类的父类等都是子类的基类型

举例介绍

水果的重量、颜色、种类不同。其中苹果就是其中一个种类。

代码实现

class Fruit {
    public double weight;
    String color ;
    Fruit(double weight, String color) {
        this.weight = weight;
        this.color = color;
    }
    protected void info() {
        System.out.println("这个水果是" + color + "的,有" + weight + "kg");
    }
}

class Apple extends Fruit {

    Apple(double weight, String color) {
        super(weight, color);
    }

    //重写
    public void info() {
        System.out.println("这个苹果是" + color + "的,有" + weight + "kg");
    }
    // 重载
    void info(String addInfo) {
        System.out.println("这个苹果是" + color + "的,有" + weight + "kg," + addInfo);
    }
    void anotherInfo() {
        this.info();
        System.out.print("对于上面这句话我们也可以说成");
        super.info();
    }
}


public class Test {
    public static void main(String[] args) {
        new Fruit(10.5, "紫色").info();
        new Apple(0.5, "红色").info();
        new Apple(0.6, "红色").info("我最喜欢吃苹果!");
        new Apple(0.3, "青色").anotherInfo();
    }
}

运行结果:

这个水果是紫色的,有10.5kg
这个苹果是红色的,有0.5kg
这个苹果是红色的,有0.6kg,我最喜欢吃苹果!
这个苹果是青色的,有0.3kg
对于上面这句话我们也可以说成这个水果是青色的,有0.3kg

多态

简单说明

继承允许将对象视为它自己本身的类型或其基类型来加以处理。比如上方代码中苹果可以被当做苹果同时也可以被当做水果来处理!而多态的存在能够消除类型之间的耦合性,并且能够改善代码的组织结构和可读性,同时它还能使得后续的代码随着后续的需求不断"生长"!

多态的建立要满足三个条件:继承、重写、向上转型!
向上转型就是把某个对象的引用视为对其基类型的引用!

举例说明

我们还拿学生的例子来说。小明是一个光荣的小学生,他喜欢和他们班的同学一起去读书。他的邻居大明是一名大学生,很喜欢旅游。

代码实现

//Test.java
abstract class Student {
  public abstract void learnMath();
}

class Pupil extends Student {
  public void learnMath() {
    System.out.println("我是一个小学生,我们学小学数学");
  }
  //休闲方式
  void reading() {
    System.out.println("我喜欢和同学一起去读书");
  }
}

class Undergraduate extends Student {
  public void learnMath() {
    System.out.println("我是一个大学生,我们学高等数学");
  }
  //休闲方式
  void tour() {
    System.out.println("我喜欢和同学一起去旅游");
  }
}

public class Test {

  public static void main(String[] args) {

    aboutMe(new Pupil());

    System.out.println();

    Undergraduate daHua = new Undergraduate();
    aboutMe(daHua);

  }
  public static void aboutMe(Student stu) {
    stu.learnMath();

    if (stu instanceof Pupil) {
      Pupil pu = (Pupil)stu;
      pu.reading();
    } else if (stu instanceof Undergraduate) {
      ((Undergraduate)stu).tour();
    }
  }
}


运行结果

我是一个小学生,我们学小学数学
我喜欢和同学一起去读书

我是一个大学生,我们学高等数学
我喜欢和同学一起去旅游

代码解析

使用了aboutMe函数来对象的相关行为。形参Student是两个实参PupilUndergraduate的基类。因此,当两个子类对象分别传入进来后就实现了向上转型,此时就相当于执行了如下代码:

Student stu = new Pupil();
Student stu = new Undergraduate();

Student stu = new Pupil();Student stu会在栈中创建一个基类的基本变量,它指向右边子类new Pupil()创建的对象的内容!
看如下图,子类和父类都有learnMath方法,我们调用stu.learnMath时,其实也是调用xiaoming.learnMath①。但当我们调用stu.reading时,由于父类中没有该方法,因此,他也不会有索引指向子类的reading方法,就会出错。如果我们想要调用该方法,应该将父类强制向下转型成子类,此时就有了②③。这就是Test.java中的aboutMe方法实现原理。一个方可可以处理不同的类,这就是多态的有点。为什么说多态能够使代码不断"成长"呢?因为现在即使我们再加入其它类(但必须是Student的子类),比如说研究生也可以直接使用aboutMe方法!

演示

此处的代码解析可能有些欠妥,不过便于理解,以后会逐步修正!

小例题

class A {
  public String show(D obj) {
    return ("A and D");
  }
  public String show(A obj) {
    return ("A and A");
  }

}

class B extends A {
  public String show(B obj) {
    return ("B and B");
  }
  public String show(A obj) {
    return ("B and A");
  }
}

class C extends B {

}

class D extends B {

}

public class Test {
  public static void main(String[] args) {
    A a1 = new A();
    A a2 = new B();
    B b = new B();
    C c = new C();
    D d = new D();
     
    System.out.println("1--" + a1.show(b)); 
    System.out.println("2--" + a1.show(c)); 
    System.out.println("3--" + a1.show(d)); 
    System.out.println("4--" + a2.show(b)); 
    System.out.println("5--" + a2.show(c)); 
    System.out.println("6--" + a2.show(d)); 
    System.out.println("7--" + b.show(b));  
    System.out.println("8--" + b.show(c));  
    System.out.println("9--" + b.show(d));  
  }
}

以上会输出什么?
答案:

1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D

此题引用于该博客,该博主讲的够全面了,可以跳过去看看。在这说一些我的解题思路:拿4来说吧,a2.show(b)

1、我们需要找到子父类(A,B)都已经存在的方法,要知道,多态中父类没有的方法,即使子类有,我们也不会调用,此处找到show(A obj)
2、此处子类的方法覆盖了父类的方法。我们传递的参数是b(class B),b的基类是A。多态中子类可以当做基类使用,所以会调用子类中的show(A obj)方法!

总结起来就是:父子都有才可调用,优先调用子类方法,形参子类可当父类!

本人小白一个,欢迎访问我的个人博客,同时也欢迎来相互交流学习!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • 一、继承 当两个事物之间存在一定的所属关系,即就像孩子从父母那里得到遗传基因一样,当然,java要遗传的更完美,这...
    玉圣阅读 1,048评论 0 2
  • 1 面向对象No6 面向对象 OO Object Oriented 编程时以对象为单元,封装数据和逻辑,以此提...
    征程_Journey阅读 1,132评论 0 2
  • 1.import static是Java 5增加的功能,就是将Import类中的静态方法,可以作为本类的静态方法来...
    XLsn0w阅读 1,217评论 0 2
  • 郑荣禄博士说:在寿险行业,态度往往可以马上转化为技能。 从业人员一定要明白在这个行业长期生存,要掌握几...
    轩铭杂谈阅读 825评论 0 0