Java面向对象

目录

 

1. 包

1.1  导入包中的类

1.2 静态导入

1.3 将类放到包中

1.4 包的访问权限控制

1.5 常见的系统包 

2. 继承

2.1 语法规则

2.2 protected关键字

3. 组合

4. 多态

4.1 向上转型

4.2 动态绑定

4.3 方法重写

4.3 理解多态

 

 

 

 


1. 包

包 (package) 是组织类的一种方式.

使用包的主要目的是保证类的唯一性.

1.1  导入包中的类

可以使用 java.util.Date 这种方式引入 java.util 这个包中的 Date 类.

但是这种写法比较麻烦一些, 可以使用 import 语句导入包.

1.2 静态导入

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

1.3 将类放到包中

基本规则

在文件的最上方加上一个 package 语句指定该代码在哪个包中.

包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 ).

包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存 储代码.

如果一个类没有 package 语句, 则该类被放到一个默认包中.

1.4 包的访问权限控制

我们已经了解了类中的 public 和 private. private 中的成员只能被类的内部使用.
如果某个成员不包含 public 和 private 关键字, 此时这个成员可以在包内部的其他类使用, 但是不能在包外部的类使用. 

1.5 常见的系统包 

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编程开发包。

2. 继承

代码中创建的类, 主要是为了抽象现实中的一些事物(包含属性和方法).

有的时候客观事物之间就存在一些关联关系, 那么在表示成类和对象的时候也会存在一定的关联.

// 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 + "正在飞 ︿( ̄︶ ̄)︿");
     }
 } 

这个代码我们发现其中存在了大量的冗余代码.
仔细分析, 我们发现 Animal 和 Cat 以及 Bird 这几个类中存在一定的关联关系: 
这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的. 这三个类都具备一个相同的 name 属性, 而且意义是完全一样的. 从逻辑上讲, Cat 和 Bird 都是一种 Animal (is - a 语义). 此时我们就可以让 Cat 和 Bird 分别继承 Animal 类, 来达到代码重用的效果. 

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

2.1 语法规则

基本语法

class 子类 extends 父类 {

     } 
使用 extends 指定父类.

Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).

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

对于父类的 private 的字段和方法, 子类中是无法访问的.

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

2.2 protected关键字

如果把字段设为 private, 子类不能访问. 但是设成 public, 又违背了我们 "封装" 的初衷.

两全其美的办法就是 protected 关键字. 对于类的调用者来说, protected 修饰的字段和方法是不能访问的

对于类的 子类 和 同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的
 

小结: Java 中对于字段和方法共有四种访问权限

private: 类内部能访问, 类外部不能访问

默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.

protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.

public : 类内部和类的调用者都能访问

3. 组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果.
组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段. 这是我们设计类的一种常用方式之一.
组合表示 has - a 语义
在刚才的例子中, 我们可以理解成一个学校中 "包含" 若干学生和教师.

继承表示 is - a 语义
在上面的 "动物和猫" 的例子中, 我们可以理解成一只猫也 "是" 一种动物.

4. 多态

4.1 向上转型

Bird bird = new Bird("圆圆"); 
这个代码也可以写成这个样子
Bird bird = new Bird("圆圆"); Animal bird2 = bird; 
 
// 或者写成下面的方式 Animal bird2 = new Bird("圆圆"); 
此时 bird2 是一个父类 (Animal) 的引用, 指向一个子类 (Bird) 的实例. 这种写法称为 向上转型.
向上转型这样的写法可以结合 is - a 语义来理解.

为啥叫 "向上转型"?

在面向对象程序设计中, 针对一些复杂的场景(很多类, 很复杂的继承关系), 程序猿会画一种 UML 图的方式来表 示类之间的关系. 此时父类通常画在子类的上方. 所以我们就称为 "向上转型" , 表示往父类的方向转.

4.2 动态绑定

当子类和父类中出现同名方法的时候, 再去调用会出现什么情况呢?
对前面的代码稍加修改, 给 Bird 类也加上同名的 eat 方法, 并且在两个 eat 中分别加上不同的日志.
 

// Animal.java
 public class Animal {
     protected String name; 
 
    public Animal(String name) {
         this.name = name;
     } 
 
    public void eat(String food) {
         System.out.println("我是一只小动物");
         System.out.println(this.name + "正在吃" + food);
     }
} 
 
// Bird.java
 public class Bird extends Animal {
     public Bird(String name) {
         super(name);
     } 
 
    public void eat(String food) {
         System.out.println("我是一只小鸟");
         System.out.println(this.name + "正在吃" + food);
     }
 } 
 
// Test.java
 public class Test {
     public static void main(String[] args) {
         Animal animal1 = new Animal("圆圆");
         animal1.eat("谷子");
         Animal animal2 = new Bird("扁扁");
         animal2.eat("谷子");
     }
 } 
 
// 执行结果
 我是一只小动物
 圆圆正在吃谷子
 我是一只小鸟
 扁扁正在吃谷子 

animal1 和 animal2 虽然都是 Animal 类型的引用, 但是 animal1 指向 Animal 类型的实例, animal2 指向 Bird 类型的实例.

针对 animal1 和 animal2 分别调用 eat 方法, 发现 animal1.eat() 实际调用了父类的方法, 而 animal2.eat() 实际调用了子类的方法. 

因此, 在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引 用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定.

4.3 方法重写

针对刚才的 eat 方法来说:

子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override).

关于重写的注意事项:

1. 重写和重载完全不一样. 不要混淆

2. 普通方法可以重写, static 修饰的静态方法不能重写. 

3. 重写中子类的方法的访问权限不能低于父类的方法访问权限. 

4.3 理解多态

有了面的向上转型, 动态绑定, 方法重写之后, 我们就可以使用多态的形式来设计程序了.

当类的调用者在编写一个方法的时候, 参数类型为父类, 此时在该方法内部并不知道, 也不关注当前的引用指向的是哪个类型(哪个子类)的实例. 此时这个引用调用方法可能会有多种不同的表现, 这种行为就称为 多态

1) 类调用者对类的使用成本进一步降低.

封装是让类的调用者不需要知道类的实现细节.

多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法即可. 

2) 能够降低代码的 "圈复杂度", 避免使用大量的 if - else

3) 可扩展能力更强.

如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低. 

 


 


 



 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值