类与对象(中级)

简介: 类与对象(中级)

面向对象的编程共有的三大特征即封装,继承,多态。

在了解封装之前先来了解一下包的概念。


1. 包


1.1 包的概念


在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件,也可以对某个文件夹下的音乐进行更详细的分类



087c833389b6436693783aa06468e303.png


在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。


1.2 导入包中的类


Java 中已经提供了很多现成的类供我们使用. 例如Date类:可以使用 java.util.Date 导入 java.util 这个包中的 Date类:

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


但是这种写法比较麻烦一些, 可以使用 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.*

但是一般不推荐这种写法,一整个 util 包中包涵了非常多的类太大。建议需要哪个类就是用哪个类。

对于某些类而言,可能会有几个包中都有该类,但是该类在不同的包中的作用不同,我们需要正确的引用。

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());
    }
}


注意事项: import 和 C++ 的 #include 差别很大. C++ 必须 #include 来引入其他文件内容, 但是 Java 不需要.

import 只是为了写代码的时候更方便. import 更类似于 C++ 的 namespace 和 using

1.3 自定义包


基本语法: 例如: package com.csdn。

package 是关键字,表示打包;后面的com.csdn 表示项目名称


基本规则:

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

2. 包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 ).            3. 包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存储代码.

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


1.4 常见的包


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. Java三大特性 --  封装


面向对象程序三大特性:封装、继承、多态。这里主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节。


介绍:封装(encapsulation)就是把抽象出来的数据(属性)和对数据的操作(方法)封装到一起,数据被保护在内部,程序的其他部分只有被授权的操作(方法),才可以对数据进行操作。


理解与目的:

1. 隐藏实现细节,也就是我们上一章说的,把大象装进冰箱有几步的问题;我们在装的不是不用注意细节,用的就是这个封装。

2. 可以对数据进行验证,保证安全合理。及比如我们登入qq需要账号密码一般。

实现细节:

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


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


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


例如:设计一个程序,不能随便查看人的年龄、工资,并且对年龄的进行合理的验证;年龄在1-100之前,有名字,name 在2 - 6 个字符之前。

class Person {
    public String name;//名字公开
    private int age;//年龄和薪水私有化
    private double salary;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }
}
public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("jack");
        person.setAge(6);
        person.setSalary(6000.0);
        System.out.println(person.toString());
    }

我们只有通过暴露出的公开方法才可以进行访问,不然直接的.age就会出错。

008919efca79466dad1818a24a4710ff.png


如果想要对年龄进行验证只需要加个判断条件。

574a0a04505a4779aa073cc8db0deea0.png


3. Java三大特性 --  继承


3.1 继承的概念:


继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。


例如:狗和猫都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用。

图示:


814cad0346d64883aa9c2d261ca34460.png


上述图示中,Dog和Cat都继承了Animal类,其中:Animal类称为父类/基类或超类,Dog和Cat可以称为Animal的子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。

从继承概念中可以看出继承最大的作用就是:实现代码复用,还有就是来实现多态(后序讲)。


3.2 继承的语法


在Java中如果要表示类之间的继承关系,需要借助extends关键字,具体如下:

修饰符 class 子类 extends 父类 {

// ...

}

原理图:


09b7b98529cb45c5ab2cc2907ffc9cbe.png


3.3 父类成员访问


在继承体系中,子类将父类中的方法和字段继承下来了,那在子类中能否直接访问父类中继承下来的成员呢?


3.3.1 子类中访问父类的成员变量


1. 当子类和父类不存在同名成员变量

    public class Base {
        int a;
        int b;
    }
    public class Derived extends Base{
        int c;
        public void method(){
            a = 10; // 访问从父类中继承下来的a
            b = 20; // 访问从父类中继承下来的b
            c = 30; // 访问子类自己的c
        }
    }


2. 子类和父类成员变量同名

public class Base {
    int a;
    int b;
    int c;
} 
public class Derived extends Base{
    int a; // 与父类中成员a同名,且类型相同
    char b; // 与父类中成员b同名,但类型不同
    public void method(){
        a = 100; // 访问父类继承的a,还是子类自己新增的a?
        b = 101; // 访问父类继承的b,还是子类自己新增的b?
        c = 102; // 子类没有c,访问的肯定是从父类继承下来的c
// d = 103; // 编译失败,因为父类和子类都没有定义成员变量b
    }
}


在子类方法中 或者 通过子类对象访问成员时:

如果访问的成员变量子类中有,优先访问自己的成员变量。

如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。

如果访问的成员变量与父类中成员变量同名,则优先访问自己的。

成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找


3.3.2 子类中访问父类的成员方法

1 成员方法名字不同

class Base {
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
}
public class Derived extends Base{
    public void methodB(){
        System.out.println("Derived中的methodB()方法");
    }
    public void methodC(){
        methodB(); // 访问子类自己的methodB()
        methodA(); // 访问父类继承的methodA()
// methodD(); // 编译失败,在整个继承体系中没有发现方法methodD()
    }
}


总结:成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错。

2. 成员方法名字相同

class Base {
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
    public void methodB(){
        System.out.println("Base中的methodB()");
    }
}
public class Derived extends Base{
    public void methodA(int a) {
        System.out.println("Derived中的method(int)方法");
    }
    public void methodB(){
        System.out.println("Derived中的methodB()方法");
    }
    public void methodC(){
        methodA(); // 没有传参,访问父类中的methodA()
        methodA(20); // 传递int参数,访问子类中的methodA(int)
        methodB(); // 直接访问,则永远访问到的都是子类中的methodB(),基类的无法访问到
    }
}


【说明】

通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。

通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错;


4. super关键字


基本介绍:super代表父类的引用,用于访问父类的属性、方法、构造器。

super可以访问父类的属性和方法,但是有权限要求,由private修饰的不可以访问。


4.1 子类构造方法


父子父子,先有父再有子,即:子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

看例题:


class Base {
    public Base(){
        System.out.println("Base()");
    }
}
public class Derived extends Base{
    public Derived(){
// super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
// 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
// 并且只能出现一次
        System.out.println("Derived()");
    }
}
class Test {
    public static void main(String[] args) {
        Derived d = new Derived();
    }
}


在子类构造方法中,并没有写任何关于基类构造的代码,但是在构造子类对象时,先执行基类的构造方法,然后执行子类的构造方法,因为:子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子父子肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整


使用细节总结:


1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构

造方法

2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的

父类构造方法调用,否则编译失败。

3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。

4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现


4.2 super 和 this 的区别


【相同点】

1. 都是Java中的关键字

2. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段

3. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在

【不同点】

1. 访问属性

this访问本类的属性,如果本类没有此属性,再去父类中继续查找;super直接访问父类的属性。


2. 调用方法


this访问本类的方法,如果本类没有此方法,再去父类中继续查找;super直接访问父类的方法。


3. 调用构造器


this调用本类构造器;super调用父类构造器


4. 表示对象


this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用。

fadf8b6a804f4d9c8983c9f960ead975.png

5. 默认调用

构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有


相关文章
|
3月前
|
存储 编译器 数据安全/隐私保护
【软件设计师备考 专题 】面向对象开发方法:理解类、对象和封装
【软件设计师备考 专题 】面向对象开发方法:理解类、对象和封装
65 0
|
3月前
|
前端开发 JavaScript PHP
【软件设计师备考 专题 】类程序设计语言主要特点和适用情况
【软件设计师备考 专题 】类程序设计语言主要特点和适用情况
77 1
|
3月前
|
Java 编译器
关于类和对象超级初级小白知识
关于类和对象超级初级小白知识
41 0
关于类和对象超级初级小白知识
|
3月前
【中级软件设计师】—程序设计语言(九)
【中级软件设计师】—程序设计语言(九)
【中级软件设计师】—程序设计语言(九)
|
3月前
|
设计模式 敏捷开发 测试技术
【中级软件设计师】—软件工程、面向对象、数据流图考点总结篇(六)
【中级软件设计师】—软件工程、面向对象、数据流图考点总结篇(六)
|
存储 人工智能 安全
Java面向对象程序设计综合练习3(选择题)
Java面向对象程序设计综合练习3(选择题)
406 0
|
存储 Java 编译器
类与对象(初级)
类与对象(初级)
103 0
类与对象(初级)
|
算法 安全 Java
Java面向对象编程中级
Java面向对象编程中级
66 0
|
Java
Java面向对象简答题
Java面向对象简答题
116 0