08 - 面向对象编程(中级部分)

每一个强者的自由,都应该以弱者的自由为边界。

1.包

1.1 为什么要有包这个概念

现在有两个程序员共同开发一个Java项目,程序员甲要定义一个类Dog,程序员乙也想要定义一个类Dog。两个类只是名字相同,实际的业务处理是不一样的。现在要怎么办呢?打一架,赢了的有定义权吗?

1.2 包的作用

  1. 区分相同名字的类
  2. 当项目非常大,定义的类非常多时,可以有条理,有层次地管理类
  3. 控制各个类的访问范围

1.3 包的基本语法

package com.example.controller;

// 说明
- package:java关键字,表示打包
- com.example.controller:表示定义的包名

1.4 包的本质

实际上就是创建不同的文件夹/目录来保存类文件。(类似Windows的目录结构)

1.5 常用的包

java.lang.*        //lang 包是基本包,默认引入
java.util.*        //util 包,系统提供的工具包, 工具类
java.net.*         //网络包,网络开发
java.awt.*         //是做 java 的界面开发,GUI

1.6 包的引入

// 引入单个类
import java.util.Scanner;

// 引入一个包下面的所有类
import java.util.*;

1.7 使用注意

  • package 的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package。
  • import 位置放在package的下面,在类定义的前面,可以有多句且没有顺序要求。

2.访问修饰符

java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):

访问级别访问控制修饰符同类        同包        子类        不同包
公开public可以可以可以可以
受保护protected可以可以可以不可以
默认没有修饰符可以可以不可以不可以
私有private可以不可以不可以不可以

一般就使用 public(哪里的都都可以访问) 和 private(只有本类的可以访问)。

3.面向对象编程 - 封装

把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据就被保护在内部,程序的其它部分只有通过被授权的操作(方法),才能对数据进行操作。

好处

  1. 隐藏实现的细节
  2. 可以对数据进行验证,保证安全合理

最典型的例子就是,定义私有的属性,通过get、set方法去操作属性值。

封装的实现步骤(三步)

1.将属性进行私有化private(不能直接修改属性)

2.提供一个公共的(public)set 方法,用于对属性判断并赋值

public void SetXxx(类型 参数名) {
    // 加入数据验证的业务逻辑
    属性 = 参数名;
}

3.提供一个公共的(public)get 方法,用于获取属性的值

public 数据类型 getXxx() {
    return xx;
}

4.面向对象编程 - 继承

继承可以解决代码复用,让我们的编程更加靠近人类思维。多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类。在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来 声明继承父类即可。

继承的基本语法

class 子类 extends 父类 {

}

// 说明
1. 子类就会自动拥有父类定义的属性和方法
2. 父类又叫超类、基类
3. 子类又叫派生类

好处

1) 代码的复用性提高了

2) 代码的扩展性和维护性提高了

注意

  • 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。
  • 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制
  • 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系。

方法重写/覆盖(override) 

方法重写就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法。

使用情况:当父类中提供的方法已经不满足子类使用时,子类就通过重写的方法,重新写子类需要这个方法的逻辑。

5.super关键字

super 代表父类的引用(this代表本对象的引用),用于访问父类的属性、方法、构造器。

基本语法

1.访问父类的属性,但不能访问父类的private属性
    super.属性名;

2.访问父类的方法,但不能访问父类的private方法
    super.方法名(参数列表)

3.访问父类的构造器
    super(参数列表); //只能放在构造器的第一句,只能出现一句

6.面向对象编程 - 多态

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

多态的前提是:两个对象(类)存在继承关系。

6.1 方法的多态(方法重载)

代码示例

public class HelloWorld {
    public static void main(String[] args) {
        // 方法重载体现多态 - 传入不同的参数,就会调用不同 sum 方法
        A a = new A();
        System.out.println(a.sum(10, 20));
        System.out.println(a.sum(10, 20, 30));
    }
}

class A {

    /**
     * 计算两个整数的和
     */
    public int sum(int n1, int n2) {
        return n1 + n2;
    }

    /**
     * 计算三个整数的和
     */
    public int sum(int n1, int n2, int n3) {
        return n1 + n2 + n3;
    }
}

6.2 对象的多态(核心)

  • 一个对象的编译类型和运行类型可以不一致
  • 编译类型在定义对象时,就确定了,不能改变
  • 运行类型是可以改变的(改变引用的指向)
  • 编译类型看定义时 = 号的左边,运行类型看 = 号的右边
// 使用多态机制,可以统一的管理主人喂食的问题
// animal 编译类型是 Animal,可以指向(接收) Animal 子类的对象
// food 编译类型是 Food ,可以指向(接收) Food 子类的对象
public void feed(Animal animal, Food food) {
    System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());
}

6.3 多态的向上/向下转型

向上转型

1.本质:父类的引用指向了子类的对象

2.语法:父类类型 引用名 = new 子类类型();

3.特点:编译类型看左边,运行类型看右边。

可以调用父类中的所有成员(需遵守访问权限),子类中的特有成员不能调用,因为编译类型在代码运行时已经固定。

最终运行效果看子类的具体实现

向下转型

1.语法:子类类型 引用名 = (子类类型)父类引用;

2.只能强转父类的引用,不能强转父类的对象

3.要求父类的引用必须指向的是当前目标类型的对象

4.当向下转型后,可以调用子类类型中所有的成员

代码示例

public class HelloWorld {
    public static void main(String[] args) {
        // 向上转型: 父类的引用指向了子类的对象
        Animal animal = new Cat();
        animal.eat();       //猫吃鱼
        animal.show();      //hello,你好
        animal.sleep();     //睡
        //animal.catchMouse();错误

        // 多态的向下转型 - 可以调用子类中特有的方法
        Cat cat = (Cat) animal;
        cat.catchMouse();   //猫抓老鼠
    }
}

class Animal {
    String name = "动物";
    int age = 10;

    public void sleep() {
        System.out.println("睡");
    }

    public void run() {
        System.out.println("跑");
    }

    public void eat() {
        System.out.println("吃");
    }

    public void show() {
        System.out.println("hello,你好");
    }
}

class Cat extends Animal {
    // 重写父类方法
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // Cat 子类中特有的方法
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

7.Object 类详解

7.1 equals方法

== 和 equals 对比

  • ==:既可以判断基本类型(判断的是值是否相等),也可以判断引用类型(判断的是地址是否相等,即是不是同一个对象)。
  • equals:是Object类中的方法,只能判断引用类型,即判断的是地址是否相等,子类中往往会重写该方法,用于判断内容是否相等。
    public static void main(String[] args) {
        // 基本数据类型,判断值是否相等
        int num1 = 10;
        double num2 = 10.0;
        System.out.println(num1 == num2);

        // 引用数据类型,判断地址是否相等
        String str1 = "hello";
        String str2 = "hello";
        System.out.println(str1 == str2);
        System.out.println(str1.equals(str1));

    }

输出结果

true
true
true

查看String重写的equals源码

    /**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

7.2 toString方法

1) 默认返回:全类名+@+哈希值的十六进制 

2) 重写 toString 方法,返回的是对象的属性信息

代码示例

public class HelloWorld {
    public static void main(String[] args) {
        // 不重写toString方法,默认返回:@全类名 + @ + 十六进制的哈希值
        Person person = new Person("路明非", "男", 18);
        System.out.println(person.toString());

        // 重写toString方法,返回的是对象的属性信息
        Cat cat = new Cat("小花", "女", 3);
        System.out.println(cat.toString());
    }
}

class Person {
    private String name;
    private String sex;
    private int age;

    public Person(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
}

class Cat {
    private String name;
    private String sex;
    private int age;

    public Cat(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }
}

输出

Person@4554617c
Cat{name='小花', sex='女', age=3}

JDK的toString方法

    /**
     * Returns a string representation of the object. In general, the
     * {@code toString} method returns a string that
     * "textually represents" this object. The result should
     * be a concise but informative representation that is easy for a
     * person to read.
     * It is recommended that all subclasses override this method.
     * <p>
     * The {@code toString} method for class {@code Object}
     * returns a string consisting of the name of the class of which the
     * object is an instance, the at-sign character `{@code @}', and
     * the unsigned hexadecimal representation of the hash code of the
     * object. In other words, this method returns a string equal to the
     * value of:
     * <blockquote>
     * <pre>
     * getClass().getName() + '@' + Integer.toHexString(hashCode())
     * </pre></blockquote>
     *
     * @return  a string representation of the object.
     */
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

7.3 finalize方法

1) 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作。

2) 什么时候被回收:当某个对象没有任何引用时,jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize 方法。

3) 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制。

在实际开发中,几乎不会运用 finalize (都默认交给虚拟机自动处理), 所以更多就是为了应付面试。

代码示例

public class HelloWorld {
    public static void main(String[] args) {
        Car bmw = new Car("宝马");
        bmw = null;
        System.gc();    //主动调用垃圾回收器
        System.out.println("程序退出了....");
    }
}

class Car {
    private String name;

    public Car(String name) {
        this.name = name;
    }
    // 重写finalize
    @Override
    protected void finalize() throws Throwable {
        System.out.println("销毁汽车" + name );
        System.out.println("释放了某些资源...");
    }
}
  • 30
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值