Java - 包、继承、组合、多态、抽象类、接口

面向对象编程
本节目标

  • 继承
  • 组合
  • 多态
  • 抽象类
  • 接口

包 (package) 是组织类的一种方式.
使用包的主要目的是保证类的唯一性.

//例如, 你在代码中写了一个 Test 类. 然后你的同事也可能写一个 
//Test 类. 如果出现两个同名的类, 就会冲突, 导致代码不能编译通过.

导入包中的类

Java 中已经提供了很多现成的类供我们使用. 例如

public class Test {
   
    public static void main(String[] args) {
   
        java.util.Date date = new java.util.Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
    }
}

可以使用 java.util.Date 这种方式引入 java.util 这个包中的Date 类.
但是这种写法比较麻烦一些, 可以使用 import 语句导入包.

import java.util.Date;

public class Test {
   
    public static void main(String[] args) {
   
        Date date = new Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
    }
}

如果需要使用 java.util 中的其他类, 可以使用 import java.util.*

import java.util.*;

public class Test {
   
    public static void main(String[] args) {
   
        Date date = new Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
    }
}

但是我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况.

import java.util.*;
import java.sql.*;

public class Test {
   
    public static void main(String[] args) {
   
        // util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
        Date date = new Date();
        System.out.println(date.getTime());
    }
}
// 编译出错
Error:(5, 9) java:Date的引用不明确
java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配

在这种情况下需要使用完整的类名

import java.util.*;
import java.sql.*;

public class Test {
   
    public static void main(String[] args) {
   
        java.util.Date date = new java.util.Date();
        System.out.println(date.getTime());
    }
}

注意事项: import 和 C++ 的 #include 差别很大. C++ 必须 #include 来引入其他文件内容, 但是 Java 不需要.import 只是为了写代码的时候更方便. import 更类似于 C++ 的namespace 和 using。(即Java只在使用导入的类的时候,才会调用。
而c是将整个包都导入。)
注意事项
在一个包中引用另一个包的同名类,两个包里面类名相同,默认会调用当前类。(import com.bit.demo1.*;为灰色,没有导入)
在这里插入图片描述
使用import导入会编译错误
在这里插入图片描述

在这种情况下需要使用完整的类名即可
在这里插入图片描述

静态导入(用的很少)

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

import static java.lang.System.*;

public class Test {
   
    public static void main(String[] args) {
   
    out.println("hello");
    }
}

使用这种方式可以更方便的写一些代码, 例如

import static java.lang.Math.*;

public class Test {
   
    public static void main(String[] args) {
   
        double x = 30;
        double y = 40;
        // 静态导入的方式写起来更方便一些.
        // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        double result = sqrt(pow(x, 2) + pow(y, 2));
        System.out.println(result);
    }
}

将类放到包中

基本规则

  • 在文件的最上方加上一个 package 语句指定该代码在哪个包中.
  • 包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 ),包的名字都是小写字母.
  • 包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存储代码.
  • 如果一个类没有 package 语句, 则该类被放到一个默认包中.

包的访问权限控制

如果某个成员不包含 public 和 private 关键字, 此时这个成员可以在包内部的其他类使用, 但是不能在包外部的类使用.(即当你的成员变量不加任何访问修饰限定词的时候,默认是包访问权限.)
下面的代码给了一个示例. Demo1 和 Demo2 是同一个包中, Test 是其他包中.
Demo1.java

package com.bit.demo;

public class Demo1 {
   
    int value = 0;
}

Demo2.java

package com.bit.demo;

public class Demo2 {
   
    public static void Main(String[] args) {
   
        Demo1 demo = new Demo1();
        System.out.println(demo.value);
    }
}
// 执行结果, 能够访问到 value 变量
10

Test.java

import com.bit.demo.Demo1;

public class Test {
   
    public static void main(String[] args) {
   
        Demo1 demo = new Demo1();
        System.out.println(demo.value);
    }
}
// 编译出错
Error:(6, 32) java: value在com.bit.demo.Demo1中不是公共的; 无法从外部程序包中对其进行访问

常见的系统包

  1. java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
  2. java.lang.reflect:java 反射编程包;
  3. java.net:进行网络编程开发包。
  4. java.sql:进行数据库开发的支持包。
  5. java.util:是java提供的工具程序包。(集合类等) 非常重要
  6. java.io:I/O编程开发包。

继承

背景

代码中创建的类, 主要是为了抽象现实中的一些事物(包含属性和方法).
有的时候客观事物之间就存在一些关联关系, 那么在表示成类和对象的时候也会存在一定的关联.
例如, 设计一个类表示动物
注意, 我们可以给每个类创建一个单独的 java 文件. 类名必须和 .java 文件名匹配(大小写敏感).

// Animal.java
public class Animal {
   
    public String name;
    public Animal(String name) {
   
    this.name = name;
        }
    public void eat(String food) {
   
        System.out.println(this.name + "正在吃" + food);
    }
}
// Cat.java
class Cat {
   
    public String name;
    public Cat(String name) {
   
    this.name = name;
    }
    public void eat(String food) {
   
        System.out.println(this.name + "正在吃" + food);
    }
}
// Bird.java
class Bird {
   
    public String name;
    public Bird(String name) {
   
    this.name = name;
    }
    public void eat(String food) {
   
        System.out.println(this.name + "正在吃" + food);
    }
    public void fly() {
   
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
    }
}

这个代码我们发现其中存在了大量的冗余代码.
仔细分析, 我们发现 AnimalCat 以及 Bird 这几个类中存在一定的关联关系:

  • 这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的.
  • 这三个类都具备一个相同的 name 属性, 而且意义是完全一样的.
  • 从逻辑上讲, Cat 和 Bird 都是一种 Animal (is - a 语义).

此时我们就可以让 Cat 和 Bird 分别继承 Animal 类, 来达到代码重用的效果.
此时, Animal 这样被继承的类, 我们称为 父类 , 基类 或 超类, 对于像 Cat 和 Bird 这样的类, 我们称为 子类, 派生类和现实中的儿子继承父亲的财产类似, 子类也会继承父类的字段和方法, 以达到代码重用的效果.

语法规则

基本语法

class 子类 extends 父类 {
   
}
  • 使用 extends 指定父类.
  • Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
  • 子类会继承父类的所有 public 的字段和方法.
  • 对于父类的 private 的字段和方法, 子类中是无法访问的.(父类的private修饰的成员变量是否被继承了?答案:没有被继承,因为子类无法访问到父类的private的字段和方法 )
  • 子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用.
  • 所有的类,父类都默认是Object

对于上面的代码, 可以使用继承进行改进. 此时我们让 Cat 和Bird 继承自 Animal 类, 那么 Cat 在定义的时候就不必再写name 字段和 eat 方法.

class Animal {
   
    public String name;
    public Animal(String name) {
   
        this.name = name;
    }
    public void eat(String food) {
   
        System.out.println(this.name + "正在吃" + food);
    }
}
class Cat extends Animal {
   
    public Cat(String name) {
   
    // 使用 super 调用父类的构造方法.
        super(name);
    }
}
class Bird extends Animal {
   
    public Bird(String name) {
   	
        super(name);
    }
    public void fly() {
   
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
    }
}
public class Test {
   
    public static void main(String[] args) {
   
        Cat cat = new Cat("小黑");
        cat.eat("猫粮");
        Bird bird = new Bird("圆圆");
        bird.fly();
    }
}

如果我们把 name 改成 private, 那么此时子类就不能访问了.

class Bird extends Animal {
   
    public Bird(String name) {
   
        super(name);
    }
    public void fly() {
   
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
    }
}
// 编译出错
Error:(19, 32) java: name 在 Animal 中是 private 访问控制

注意1子类构造的同时,要 先 帮助父类来构造
子类继承了父类,那么子类在构造的时候,需要先帮助父类进行构造,使用super()的方式来显示调用父类的构造方法。而子类没有用super引用父类构造方法就会编译错误(继承的父类如果是无参构造方法,子类不用super())。正确做法如上代码。
默认无参,和自己写的无参是一样的,但是你写了一个非无参数的构造方法,如果需要无参数构造方法,必须自己写
这样引用父类构造方法也可以:

public class Animal {
   
    protected String name;
    protected int age;
    public Animal(String name,int age) {
   
        this.name = name;
        this.age = age;
    }
    public void eat(String food) {
   
        System.out.println(this.name + "正在吃" + food);
    }
}
// Bird.java
class Bird extends Animal {
   
    public String wing;
    public Bird(String name,int age,String wing) 
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java中的接口是一种抽象的数据类型,它定义了类应该具有的方法和属性,但并不提供实现细节。它可以被看作是一种规范,让开发者知道他们需要实现的方法和属性。 接口可以被类实现,类实现接口时必须实现接口中定义的所有方法和属性。这种实现方式使得类可以具有多个接口的特性,从而实现了Java中的多重继承。 下面是一个简单的接口示例: ```java public interface Animal { void move(); void eat(String food); } ``` 上面的接口定义了两个方法`move()`和`eat(String food)`,类实现这个接口时必须实现这两个方法。 接口还可以继承其他接口,从而扩展接口的功能。下面是一个继承其他接口接口示例: ```java public interface Bird extends Animal { void fly(); } ``` 上面的接口继承了Animal接口,同时添加了一个新的方法`fly()`。 接口还可以用于回调函数的实现,例如定义一个接口作为事件监听器,当某个事件发生时,回调函数会调用接口中定义的方法。 接口Java中非常重要的概念,对于理解Java的多抽象类等概念有很大的帮助。 ### 回答2: Java继承和多是面向对象编程中的重要概念,而接口Java语言中实现多的方式之一。 继承是指一个类可以继承另一个类的属性和方法。通过使用关键字“extends”,子类可以继承父类的属性和方法,并且可以在子类中添加新的方法或属性。继承可以实现代码的重用,同时也体现了面向对象的特点。 多是指同一个类型的对象在不同的情况下表现出不同的行为。在Java中,多可以通过接口来实现。接口是一个抽象类的特殊形式,它定义了一组方法的签名,但没有实现这些方法的具体逻辑。一个类可以实现一个或多个接口,并实现接口中定义的所有方法。通过接口,我们可以将不同的类组织在一起,以实现类之间的松耦合和代码的重用。 接口定义了一组规范,而类则去实现这些规范。接口可以通过关键字“implements”来实现。通过实现接口,类必须实现接口中定义的所有方法。接口可以作为方法的参数类型或返回值类型,从而实现多的效果。 总之,学习Java继承和多接口,我们能够更好地组织和管理代码,实现代码的重用和灵活性。接口的使用使得我们可以面向接口编程,而不是面向具体的类,从而提高了代码的可扩展性和可维护性。掌握这些概念,能够更有效地编写面向对象的Java程序。 ### 回答3: 在Java编程语言中,继承和多是重要的概念,而其中的接口是实现多的关键。接口是一种约定或契约,是一组方法的集合,但没有具体的实现。接口定义了一些必须实现的方法,而这些方法的具体实现则由实现接口的类来完成。 通过继承和实现接口,我们能够实现代码的重用和灵活性。继承允许一个类继承另一个类的属性和方法,而接口则定义了一组方法,使得不同的类能够被视为同一类型,从而实现多接口有两个主要的作用:规范和实现多。通过接口的规范,我们可以对各个类的方法进行统一管理和调用。这样一来,我们能够降低代码的重复性,改进代码的可读性和维护性。通过实现多,我们可以让一个对象以不同的形呈现,从而实现灵活性和扩展性。 在Java中,一个类可以实现一个或多个接口。通过实现接口,类必须实现接口中定义的所有方法。这样一来,我们可以根据接口的类型来引用不同的对象,而不需要关心具体实现的细节。 例如,我们有一个接口叫做Animal,定义了一个方法叫做move()。然后,我们有两个类,一个是Dog,一个是Cat,它们都实现了Animal接口。通过多性,我们可以使用Animal类型的引用来引用Dog和Cat对象,然后调用move()方法,而不用担心具体是哪个类的对象。 总之,学习Java继承和多接口是非常重要和有用的。接口能够帮助我们实现代码的重用、灵活性和扩展性。通过继承和实现接口,我们能够更好地组织和管理代码,提高代码的可读性和维护性,从而更高效地进行程序开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值