温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java语言之包和继承的示例分析

发布时间:2021-09-13 12:55:32 来源:亿速云 阅读:118 作者:小新 栏目:开发技术

这篇文章主要介绍了Java语言之包和继承的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

    一、包

    包名

    在讲包名前,我们先来了解一下,包是用来干什么的?

    Java中允许使用包(package),包将类组织在一个集合中。借助包可以方便管理组织自己的代码,并将自己的代码与别人的提供的代码库分开管理。

    包是组织类的一种方式。使用包的主要目的就是保证类的唯一性。

    在Windows操作系统中,我们都知道,同一个文件夹下,不能同时出现两个一样的文件名的文件。而我们的java类,对应的就是一个.class文件,所以产生了包,而包其实就可以理解为路径中所存放的文件夹,为了出现重命的类名,所以将各个类分布在不同的包(文件夹)中。

    而包名的命名:包名必须全部是小写字母,且一般包的命名方式是所在公司的官网(域名)的逆序写,假如www.xxxx.com,一般包名就是com.xxxx.——等等。

    从编译器的角度来看,嵌套的包之间没有任何关系。例如:java.util包和java.util.jar包毫无关系。每一个包都是独立的类集合。

    Java语言之包和继承的示例分析

    类的导入与静态导入

    一个类可以使用所属包中的所有类,以及其他包下的公共类(public class)。

    访问另一个包的类有两种方式:

    1.使用完全限定名,也就是说在包名后面跟着类名。

    java.util.Scanner scan = new java.util.Scanner(); //类名前面,直接跟包名

    2.使用import关键字

    import语句应该位于源文件的顶部,且位于package语句的后面。

    import java.util.Scanner;
    public class Main {
        public static void main(String[] args) {
            Scanner sc = new scanner();
        }
    }

    对于导包,我们还有一种比较简单的方式,如下

    import java.util.*;

    *,就是通配符。也就是在当前类中,可以直接使用util包的所有类,从而不需要再次导包了。值得注意的是,这里的导入,并不是导入util包下的所有类,这里跟C语言的include,不一样。C语言中的include,是导入头文件下的所有内容;而这里的import导入,只会在需要使用这个包下的类的时候,才会导入进来

    当然,对于import导入包时,还需要特别注意一个问题,如下:

    import java.util.*;
    import java.sql.*;
    public class Main {
        public static void main(String[] args) {
            Date date = new Date(); //error, java.util.Date 还是 java.sql.Date?
        }
    }

    此时进行编译,就会产生一个如上面代码的注释部分的错误。此时的编译器无法确定你想使用的是哪一个包下的Date类。现在就可以添加一个特定的import来解决这个问题。

    import java.util.*;
    import java.sql.*;
    import java.util.Date; //特别指出是使用这个包下的Date类
    public class Main {
        public static void main(String[] args) {
            Date date = new Date();
        }
    }

    如果此时,两个包中的Date都需要使用,那就只能使用完全限定名了。如下:

    import java.util.*;
    import java.sql.*;
    public class Main {
        public static void main(String[] args) {
            java.util.Date date = new java.util.Date();
            java.sql.Date  date2 = new java.util.Date();
        }
    }

    静态导入

    我们还可以使用静态导入包的方式,进行代码的缩写。使用import static 可以导入包中的静态方法和静态字段。这样就可以不必再加类名前缀。

    import static java.lang.System.*;
    public class Main {
        public static void main(String[] args) {
            out.println("hello world");
        }
    }

    只是有这样一种机制,可以进行代码的缩写,但在现实中,这样的代码,可能更不容易读懂。所以大家使用时,酌情考虑。

    在包中添加类

    如果要想将类放入包中,就必须将包的名字放在源文件的开头,即就是放在定义这个包中各个类的代码之前。如下:

    Java语言之包和继承的示例分析

    如果没有在这个源文件的开头,写package语句,则这个源文件中类就属于无名包(unnamed package)。无名包没有包名。

    基本规则:

    • 在源文件的最上方加一个package语句,可以指定该代码在哪个包

    • 包名尽量指定成唯一的名字,通常会使用公司的域名逆序形成

    • 包名要和代码路径相匹配。例如:package com.xxxx.demo,那么所对应的文件路径就是com/xxxx/demo

    • 如果一个源文件没有package语句,则该类会被放到无名包(默认包)中

    IDEA建包过程:

    Java语言之包和继承的示例分析

    包访问权限

    在之前的文章中,我们介绍过publicprivate。而private修饰的方法或成员变量,只能在当前这个类中访问。

    如果有个类,既没有写public,也没有写private访问修饰限定符,则此时这个(类、方法或成员变量)可以在包内部(当前文件夹下)的其他类中使用,但是不能在包外部(其他文件夹下)的类中使用。如下代码:

    import com.xxxx.demo1;
    //demo1 包
    public class Main {
        public static void main(String[] args) {
            Test test = new Test(); //会报错,访问权限不够。
        }
    }
    //=====假设下面是第二个文件夹下的文件=====
    import com.xxxx.demo2;
    class Test { //访问修饰限定符:没写,我们就称为 默认
        public int number;
    }
    public class Demo2 {
        public int val;
    }

    访问修饰限定符权限:

    范围private默认(default)protectedpublic
    同包同类YYYY
    同包不同类
    YYY
    不同包,子类

    YY
    不同包,不同类


    Y

    其中,protected会在继承中讲到,我们继续往下看!!!

    二、继承

    继承的基本思想就是:在已有类的基础之上,创建新的类。继承已存在的类得到就是复用了(继承)这些类的方法,而且可以增加一些新的方法和成员变量。

    类、超类与子类

    我们先来举个例子,比如一只猫和一只狗。它们了分别有自己的名字、性别、还是吃东西等等的一些性质。如下图:

    Java语言之包和继承的示例分析

    他们分别都有自己的这些特征,我们也可以很容易的发现,他们都有自己一些共有的特征:比如姓名,性别。所以如果我们分别在新建猫和狗的类,还得写专属于它们自己的成员变量,这样的话,就显得代码重复累赘,如下图这样:

    Java语言之包和继承的示例分析

    我们可以很清晰的看到,红色框代码部分,就是一模一样的,所以出现了重复的代码。而且这两个类都是动物,所以说引出了一个继承中的一个概念:“is -a”关系。

    也就是说,什么是一个什么这样的概念。就可能会用到继承。

    那该怎么实现继承关系呢?我们来看下图:

    Java语言之包和继承的示例分析

    我们可以使用extends关键字来实现继承关系,这样的话,猫和狗两个类,就能够同时实现name和sex字段。这就是继承。

    此时猫和狗类,我们称为子类或者派生类。而Animal类我们称为父类基类超类

    总结:

    • 使用extends指定父类

    • Java中一个子类只能继承一个父类。(而C++中可以实现多继承)

    • 子类会继承父类所有的public的字段和方法

    • 对于父类的private的字段和方法,子类是无法进行访问的

    • 子类的实例中,也包含这父类的实例。可以使用super关键字得到父类实例的引用。

    重写方法(override)

    Java语言之包和继承的示例分析

    像上图,子类和父类中,方法名和参数列表是一模一样的。我们就称为方法重写(override)。可能有人就会问,我该怎么调用相应的方法呢?

    我们想调用Animal的eat方法,我们只需要new出一个Animal的对象,就能进行调用,当然,Cat类的实例对象也是如此。如果我们想在Cat类的实例对象调用父类的方法,则我们可以使用super关键字进行调用。如下图:

    Java语言之包和继承的示例分析

    切记:

    • super关键字,在使用的时候,只能调用他的直接父类的方法或字段。比如:Animal类还继承了一个类,此时Cat类中,使用super,则只会调用Animal中的方法或字段。

    • 在子类中重写的方法,这个方法的访问修饰限定符的等级,应高于或等于父类的方法的访问修饰限定符。比如:父类中的eat方法是public修饰,而子类中的eat方法也应该是public,或者是更高的。(当然只是举个例子,public就是最高的访问修饰限定符了)

    • 被重写的方法,不能是被static修饰的

    this与super的区别:

    Java语言之包和继承的示例分析

    子类构造器

    在上面说了,super关键字来调用父类的构造方法,那具体是如何进行调用的,我们来看一下具体的代码实现:

    public class Cat extends Animal{
        public Cat(String name, String sex) {
            super(name, sex); //调用父类的构造方法,super语句必须在子类构造器的第一行
            System.out.println("Cat的构造方法"); 
        }
        public void eat() {
            System.out.println("吃鱼");
        }
    }
    public class Animal {
        public String name;
        public String sex;
        public Animal(String name, String sex) { //父类的构造方法
            this.name = name;
            this.sex = sex;
        }
        public void eat() {
            System.out.println("吃肉");
        }
    }

    总结:

    • 使用super构造方法的语句必须放在子类构造方法中的第一行。

    • 如果子类中,没有显示地调用父类的构造方法,将自动地调用超类的无参构造方法。

    • 在进行子类的实例化时,会调用子类的构造方法,而在调用子类构造方法时,将会先调用父类的构造方法。也就是说:new Cat ,实际上将先会新建出父类,在父类新建完成后,才会回到子类的构造方法,进行新建子类。

    下面是一道有趣的题:请问下列代码的输出结果是什么。

    class X {
        Y y=new Y();
        public X() {
            System.out.print("X");
        }
    }
    class Y {
        public Y() { 
            System.out.print("Y");
        }
    }
    public class Z extends X {
        Y y=new Y();
        public Z() {
            System.out.print("Z");
        }
        public static void main(String[] args) {
            new Z();
        }
    }

    上面的代码的输出结果是:YXYZ。

    分析:

    • 如果调用的是子类,那么在进入子类构造方法后,将先执行super语句(若没写,编译器自带),先构造父类。

    • 在父类构造完成后,再次回到子类的构造方法。此时将先初始化当前类的成员变量。

    • 在成员变量初始化之后,才会执行构造方法里面的语句。

    上诉代码执行流程图:

    Java语言之包和继承的示例分析

    protected关键字

    在上文中,我写了一个访问修饰限定符的表,表中第3个protected关键字。

    前面我们学了public和private访问修饰限定符,public的权限有大了,对于public来说,整个工程都可以进行使用;而对于private来说,只能在当前的类中进行使用。二者之前,一个权限过大,一个权限过小。所以在Java的继承中,还引入了这个关键字:protected;

    对于protected来说,protected修饰的内容,在这个包下,可以直接使用。而在不同的包下,只有继承了这个类,才能在不同的包下使用该类被protected修饰内容。

    阻止继承:final关键字

    在前面的文章中,我们介绍过final关键字,final修饰的变量,在初始化之后,将不能被修改。

    final int a = 10;
    a = 20; //编译出错,此时的a被final修饰,存储在方法区,且不能被修改

    final也能修饰类,,表示不能再被继承,称为密封类。

    final还能修饰方法,表示此时的方法不能被重写,称为密封方法。

    切记:如果一个类被final修饰,那么其中的方法将自动地称为final,但是不包括字段。如果一个方法没有被重写并且还很短,编译器将会对此进行优化处理,这个过程称为内联

    组合

    和继承类似的,还有一个叫组合的概念,也是用于表达类之间的关系,也能够达到代码的重复使用。

    例如:一个公司由很多人组合而成,有当经理的、职员的、保洁员的等等……

    class Person {
        public String name;
        public String sex;
    }
    class Manager extends Person { //继承 人
        //经理的薪水
        public double getSalary() {
        }
    }
    class Staff extends Person { //继承 人
        //普通职员的薪水
        public double getSalary() {
        }
    }
    //组合
    public class Company {
        public Manager[] manager; //经理
        public Staff[] staff; //普通职员
    }

    组合并没有涉及到特殊的语法,仅仅只是将一个类的实例作为另一个类的字段,这也是我们设计类的一种常用的方式或思想。

    组合表示has- a 的语义:意为:一个事物 由 什么组合而成,也就是包含的意思。

    继承表示is-a的语义:意为:一个事物 是 一个什么事物的概念。

    感谢你能够认真阅读完这篇文章,希望小编分享的“Java语言之包和继承的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI