【Java】包与继承

一、包

包是什么?

书包里装的是书,钱包里装的是钱,化妆包里装的是化妆品,而 Java 中的包里装的是各种各样的类

在这里插入图片描述

在 IDEA 中创建一个类通常的做法是在 src 下直接创造一个类,比如这个类叫 TestDemo ,此时,在这个包里名为 TestDemo 的 java 文件有且只能有一个。

在做一个大的工程项目时,如果大家都采取这样的创建类的方式,很难保证同事不和你一样写一个 TestDemo 类,当同一个包里面有两个类重名时,编译代码时就会出现错误。

为能够更好地组织类,保证类的唯一性,Java 提供了机制,用于区别类名的命名空间。

当我们在 IDEA 中创建一个 TestDemo 类后,可以这么做,来看看这厮究竟搁哪地儿了。

在这里插入图片描述

综上所述,简而言之!包!说白了就是一装着类的文件夹!

在这里插入图片描述
在这里插入图片描述

1.1 把类从包里导进来

在此之前,我们其实已经使用过许多 Java 为我们准备的类,当需要使用时直接用 import 关键字将其导入即可。

📑代码示例一:

//方法一
import java.util.Arrays;
import java.util.Scanner;
//方法二
//import java.util.*;
public class TestDemo {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //System.in 表示从键盘进行读入
        int[] array = {1,2,3,4};
        System.out.println(Arrays.toString(array));
    }
}

💬代码解释:

  • 想要使用 ScannerArrays 这两个类,就需要用 import关键字将 util 包下的 ScannerArrays 这两个类导入到程序当中,如果不导入,类就没有办法使用。
  • 方法一属于单类型的导入,即用哪个类就导入哪个类
  • 方法二属于按需类型的导入* 表示的是通配符包括 util 的所有的类,后程序中如果要用到这个包中的别的类都不需要再重新导入包了。实际上,真正导入的时候并不会导入所有的类,而是用到哪个类就导入哪个类,这也是 Java 的一大好处。

在众多的类中有这样的一种特殊的类,两个包中都有该类,例如 Date 类。

在这里插入图片描述

📑代码示例二:

import java.util.*;
import java.sql.*;
public class TestDemo {
    public static void main(String[] args) {
        //方法一
        Date date = new Date();
        //方法二
        java.util.Date date = new java.util.Date();
        
        System.out.println(date.getTime());
    }
}

💬代码解释:

  • 由于 utilsql 中都存在一个 Date 这样的类,方法一这样的表达形式,就会出现歧义,对 Date 的引用不明确,编译出错。
  • 可以使用方法二这样的形式,使用完整的类名对其进行实例化。
  • 排除这种特殊情况。可以在没有导包的情况下用方法二来导入类也是可行的,缺点在于写法较为麻烦;一般来说在用 import 关键字导入包的情况下,方法一进行实例化会较为普遍。

方法一报错图示:

在这里插入图片描述

1.2 再把类丢包里去

想要将类放入包中,首先需要自己先建一个包。

建包创类操作:

一:建包

  1. 右键 src -> New -> Package

在这里插入图片描述

  1. 输入包名

在这里插入图片描述

  1. 结果图(为了使包更具有层次感,可以通过设置进行操作)

在这里插入图片描述

二:创类

  1. 右键包名(这里选择在 www 这个包下面创建一个类)-> New -> Java Class (如果选择在 jxust 这个包下创建一个类,那么该类将会和 www 这个包同级)

在这里插入图片描述

  1. 输入类名

在这里插入图片描述

  1. 结果图,可以看见这里有两个 TestDemo 类,但是存在于不同的包下面,就不会产生任何的冲突

在这里插入图片描述

文件途径:

在这里插入图片描述

代码区:

package com.jxust.www;
public class TestDemo {
    
}

注意:

  • 完成上述的操作之后,在文件的最上方会出现一个 package 语句,该条语句指定了该代码在哪个包中,不可以将其删除
  • 包名通常为公司的域名的逆置,差不多就像上述我的举例的那样,但并非硬性规定,也可以选择想起什么名儿就起什么名儿。
  • 包名要和代码路径相匹配

1.3 包的访问权限控制

在上一章类与对象中,有介绍过类中的 public 和 private 关键字,public 是最为公开的,可以被所有的类所访问,private 是最为私有的,只能被自己的类访问和修改。

当某一个成员没有任何的关键字进行修饰,该成员就受包的访问权限控制该成员可以在包内部的其他类使用, 但是不能在包外部的类使用。实际上,这种成员默认被 default(friendly) 所修饰。

📑代码示例:

www 包:

package com.jxust.www;
public class TestDemo {
    int a = 18;
}
//定义一个包访问权限的变量a
package com.jxust.www;
public class TestDemo2 {
    public static void main(String[] args) {
        TestDemo testDemo = new TestDemo();
        System.out.println(testDemo.a);
    }
}
//执行通过,可以访问的到a

其他包里面:

public class TestDemo {
    public static void main(String[] args) {
        com.jxust.www.TestDemo testDemo = new com.jxust.www.TestDemo();
        System.out.println(testDemo.a);
    }
}
//编译错误

在这里插入图片描述

1.4 常见的一些系统包

在这里插入图片描述

  • util 工具包使用的范围很广,非常重要
  • lang 包提供了程序设计的基础类,在创造各种基础类型的变量时,都会自动的导入该包

1.5 静态导入(了解)

可以使用 import static 导入包中的静态的方法和字段

📑代码示例:

求对 a 和 b 变量的平方和进行开平方的结果

import static java.lang.Math.*;
public class TestDemo {
    public static void main(String[] args) {
        double a = 2,b = 3;
        //静态导入的方式
        double result = sqrt(pow(a,2) + pow(b,2));
        //一般方式
        //double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        System.out.println(result);
    }
}

💬代码解释:

静态导入的优点就在于可以将代码写起来更加的简单,缺点就在于代码的可读性降低,所以一般来说,静态导入不太会用到,了解即可。

二、继承

2.1 初介绍

在正是学习 Java 语言前,就有了解到 Java 语言是面向对象的,而面向对象的基本特征:封装、继承、多态、抽象

在此之前,封装已经有所了解,知道了通过 private 关键字将成员包裹在当前的类中,外界想要对数据进行访问就需要使用已经提供的 get 和 set 方法,从而保证了模块具有较好的独立性,使得程序维护修改较为容易。

现在,我们讲一讲继承这一个基本特征。

日常生活中什么是继承?隔壁小王继承了他的爸爸老王的一大笔财产,这就意味着,原本属于老王的钱小王也可以花了。

面向对象中的继承有着异曲同工之妙,类与类之间会存在着某种关系,被继承的类称为 父类/基类/超类,而继承别的类的类就叫做子类/派生类,类似小王继承了老王的财产一样,子类继承了父类的字段和方法。

此时此刻,你是否…

在这里插入图片描述

举个例子:

📑代码示例:

class Animal {
    public int age;
    public String name;
    public void eat() {
        System.out.println(this.age +"岁的" + this.name + " 会吃饭");
    }
}
class Bird extends Animal{
    public void fly() {
        System.out.println(this.age +"岁的" + this.name + " 会飞翔");
    }
}
class Dog extends Animal{
    public String color;
    public void bark() {
        System.out.println(this.age +"岁的" + this.name + " 会狗叫");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "旺财";
        dog.age = 3;
        dog.eat();
        dog.bark();
    }
}

🏸 代码结果:

在这里插入图片描述

💬代码解释:

  • 创建了三个类,Animal类,Bird 类以及 Dog 类,这三个类存在着某些关联,鸟是动物,狗也是动物,因此动物所具有的特征(比如有名字,有年龄,会吃饭)这俩都有,如果这些共有的特征在每个类里面都写一遍,就会造成代码冗余。
  • 此时该代码采取让 BirdDog 分别继承 Animal 类,这样这两个类就是所谓子类,Animal 就是所谓父类子类继承了父类的所有公开的字段和方法,达到了代码重用的效果

Dog 类的内存分布:

在这里插入图片描述

2.2 语法规则

✒️基本语法形式:

class A extends B {
    
}

注意事项:

  • A 代表子类,B 代表父类,关键字 extends在 Java 中的作用是继承的意思,使用该关键字指定父类
  • 在 Java 中不允许多继承的存在,一个子类只能继承一个父类
  • 子类会继承父类所有公开的字段和方法,被 private 关键字修饰的字段和方法,子类是没有办法进行访问的
  • 子类可以使用 super 关键字得到父类实例的引用

举例代码改进:

📑代码示例:

class Animal {
    public int age;
    public String name;
    public Animal(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public void eat() {
        System.out.println(this.age +"岁的" + this.name + " 会吃饭");
    }
}
class Bird extends Animal{
    public Bird(int age, String name) {
        super(age, name);
    }
    public void fly() {
        System.out.println(this.age +"岁的" + this.name + " 会飞翔");
    }
}
public class TestDemo {
    public static void main(String[] args) {
       Bird bird = new Bird(2,"麻雀");
       bird.fly();
       bird.eat();
    }
}

🏸 代码结果:

在这里插入图片描述

💬代码解释:

  • 当父类创造了带两个参数的构造方法时,子类既然已经继承了父类,就需要先帮助父类进行构造,否则代码就会报错
  • 子类帮助父类构造方法的快捷步骤:
  1. 将光标放置在报错之处
  2. Alt + 回车键
  3. 选择 Create constructor matching super
  4. 报错消失,帮助父类构造方法完成
  • super() 的作用就是显示的调用父类的构造方法
  • 在代码升级之前并没有报错是因为,编译器默认父类拥有无参的构造方法,默认子类调用父类不带参数的构造方法

2.3 super 关键字

super 关键字表示获取到父类实例的引用,简而言之,在子类内部调用父类方法或成员。

用法一:

super() 调用父类的构造方法(前面有所介绍)

public Bird(int age, String name) {
    super(age, name);
}

注意:一般放在第一行

用法二、三:

super.方法 调用父类的普通方法

super.成员方法 调用父类的普通方法

class Animal {
  public int age;
  public String name;
  public void eat() {
      System.out.println(this.age +"岁的" + this.name + " 会吃饭");
  }
}
class Bird extends Animal{
  public void fly() {
      super.eat();
      System.out.println(super.age +"岁的" + this.name + " 会飞翔");
  }
}
public class TestDemo {
  public static void main(String[] args) {
     Bird bird = new Bird(2,"麻雀");
     bird.fly();
  }
}

🏸 代码结果:

在这里插入图片描述

💬代码解释:

  • 在子类的 fly方法中用关键字 super 调用了父类的 eat 方法,因此 当如我代码这么写的话,只需要在 main 函数中调用了 fly 方法,eat 方法也会被调用
  • fly 方法中的 age 是调用父类的 age,name 是继承父类得来的,使用上并没有什么区别,一般当前的类用 this 较为普遍

注意:

  • super()this() 都需要放在第一行,因此两者不能共存
  • super 关键字不可以在被 static 修饰的方法中进行使用,因为该关键字依赖当前对象
  • super 关键字只会指向最直接的父类
  • 当子类和父类拥有同名的字段或方法时,符合就近原则使用子类的该字段或方法,若依然想要用父类的该字段或方法,就需要使用到 super
  • superthis 最大的区别在于,super 表示对当前对象的父类的引用,this 表示对当前对象的引用;另外,查找的范围也有所区别,super 不会查找本类直接调用父类,this 先查找本类,如果本类没有就调用父类

2.4 protected 关键字

如果将某字段用 private 修饰,其子类没有办法访问。用 public 修饰,就没有封装的存在了。

此时,protected 关键字就起到了重要作用,被该关键字修饰的字段和方法可以被其类的子类(同一个包和不同的包都包含在内)和同一个包的其他的类访问到

需要注意的是,如果是不同包下面的子类,不可以用对象的引用来访问父类的变量,可以通过 super。如果是同一个包下的话,两种方法都可以。

总结表:

在这里插入图片描述

2.5 final 关键字

A类继承了B类,B类继承了C类,C类继承了D类…

像这样层层叠叠更为复杂的继承方式称为多层继承,即子类还可以进一步的再派生出新的子类,但实际上超过三层的继承关系就需要考虑一下对代码进行重构,否则代码的可读性不高。

想要在语法上限制类被继承,final 关键字起到了重要作用。

之前有了解到,被 final 关键字修饰的变量或者字段,表示常量,是没有办法被修改的。

该关键字也可以修饰类,表示被修饰的类是不能被继承的。如果继承了,就会编译错误。

完!

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

富春山居_ZYY(已黑化)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值