栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java面向对象之包、访问修饰符、封装及继承

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java面向对象之包、访问修饰符、封装及继承

文章目录
      • 1、包
        • 1.1、需求引出
        • 1.2、包的三大作用
        • 1.3、基本语法
        • 1.4、包的本质分析
        • 1.5、包的命名
        • 1.6、常用的包
        • 1.7、如何引入包
        • 1.8、注意事项和使用细节
      • 2、访问修饰符
        • 2.1、定义
        • 2.2、4 种访问修饰符的访问范围
        • 2.3、使用的注意事项
        • 2.4、代码实现
      • 3、面向对象编程三大特征
        • 3.1、封装
          • 3.1.1、定义
          • 3.1.2、封装的优势
          • 3.1.3、封装的实现步骤
          • 3.1.4、将构造器和 setXxx 结合
        • 3.2、继承
          • 3.2.1、定义
          • 3.2.2、定义继承的基本语法
          • 3.2.3、代码实现
          • 3.2.4、继承给编程带来的便利
          • 3.2.5、继承的细节问题
          • 3.2.6、继承的本质分析

1、包 1.1、需求引出

1.2、包的三大作用
  1. 区分相同名字的类
  2. 当类很多时,可以很好的管理类【看Java API文档】
  3. 控制访问范围
1.3、基本语法
package com.helloedu;

说明:
1、package: 关键字, 表示打包
2、com.helloedu: 表示包名
1.4、包的本质分析


1.5、包的命名

只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字或保留字
demo.class.exec1 // 错误 class是关键字
demo.12a // 错误 12a是数字开头
demo.ab12.oa // 对
命名规范:
一般是小写字母+小圆点
例如:com.xxx.oa.model;
com.xxx.oa.controller;
举例:
com.sina.crm.user; // 用户模块
com.sina.crm.order; // 订单模块
com.sina.crm.utils; // 工具类

1.6、常用的包

一个包下,包含很多的类,java 中常用的包有:

  1. java.lang.* // lang 包是基本包,默认引入,不需要再引入
  2. java.util.* // util 包,系统提供的工具包,工具类,使用 Scanner
  3. java.net.* // 网络包,网络开发
  4. java.awt.* // 是做 java 的界面开发,GUI
1.7、如何引入包

// 一个类中最多只有一句 package
package com.use_;

// 建议: 我们需要使用到哪个类, 就导入哪个类即可, 不建议使用 * 导入
// import 指令位置放在 package 的下面, 在类定义前面, 可以有多句且没有顺序要求
import java.util.Arrays;  // 表示只会引入 java.util 包下的 Arrays
import java.util.*;  // 表示将 java.util 包下的所有类都引入(导入)

public class Sort_ {
    public static void main(String[] args) {
        int[] arrList = {1, -2, 99, -105, 82, 30, -3, 0, 5, 29};
        // 系统提供了相关的类, 可以方便完成排序 (Arrays 类)
        Arrays.sort(arrList);
        for (int i = 0; i < arrList.length; i++) {
            System.out.print(arrList[i] + "t");
        }
    }
}
1.8、注意事项和使用细节

2、访问修饰符 2.1、定义

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

  1. 公开级别:用 public 修饰,对外公开
  2. 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
  3. 默认级别:没有修饰符号,向同一个包的类公开
  4. 私有级别:用 private 修饰,只有类本身可以访问,不对外公开
2.2、4 种访问修饰符的访问范围

2.3、使用的注意事项
  1. 修饰符可以用来修饰类中的属性,成员方法及类
  2. 只有默认的和public才能修饰类,并且遵循上述访问权限的特点
  3. 成员方法的访问规则和属性完全一样
2.4、代码实现


TestClass.java

package access;

import access1.TestClass3;
import access1.TestClass4;

public class TestClass {
    public int n1 = 10;
    protected int n2 = 20;
    int n3 = 30;
    private int n4 = 40;

    public void m1() {
        System.out.println("TestClass中 public m1 方法");
    }

    protected void m2() {
        System.out.println("TestClass中 protected m2 方法");
    }

    void m3() {
        System.out.println("TestClass中 默认 m3 方法");
    }

    private void m4() {
        System.out.println("TestClass中 private m4 方法");
    }

    public static void main(String[] args) {
        // 在同类中测试
        // 结论: 所有属性和方法都能正常访问
        TestClass testClass = new TestClass();
        System.out.println(testClass.n1);
        System.out.println(testClass.n2);
        System.out.println(testClass.n3);
        System.out.println(testClass.n4);
        testClass.m1();
        testClass.m2();
        testClass.m3();
        testClass.m4();
        System.out.println("=====");

        // 在同一个包中, 不同的类中测试 测试 TestClass1 类
        // 结论: private 属性和方法不能正常访问
        TestClass1 testClass1 = new TestClass1();
        System.out.println(testClass1.h1);
        System.out.println(testClass1.h2);
        System.out.println(testClass1.h3);
        // System.out.println(testClass1.h4);  // 报错
        testClass1.q1();
        testClass1.q2();
        testClass1.q3();
        // testClass1.q4();  // 报错
        System.out.println("=====");

        // 在同一个包中, 子类继承父类 测试 测试 TestClass2 类
        // 结论: private 属性和方法不能正常访问
        TestClass2 testClass2 = new TestClass2();
        System.out.println(testClass2.h1);
        System.out.println(testClass2.h2);
        System.out.println(testClass2.h3);
        // System.out.println(testClass2.h4);  // 报错
        testClass2.q1();
        testClass2.q2();
        testClass2.q3();
        // testClass2.q4();  // 报错
        System.out.println("=====");

        // 在不同的包中, 子类继承父类 测试 测试 TestClass3 类
        // 结论: 默认和private 属性和方法不能正常访问
        TestClass3 testClass3 = new TestClass3();
        System.out.println(testClass3.n1);
        System.out.println(testClass3.n2);
        // System.out.println(testClass3.n3);  // 错误
        // System.out.println(testClass3.n4);  // 错误
        testClass3.m1();
        testClass3.m2();
        // testClass3.m3();  // 错误
        // testClass3.m4();  // 错误
        System.out.println("=====");

        // 在不同的包中, 测试 TestClass4 类
        // 结论: protected、默认private 属性和方法不能正常访问, 只有公开类的属性和方法可以正常访问
        TestClass4 testClass4 = new TestClass4();
        System.out.println(testClass4.v1);
        // System.out.println(testClass4.v2);  // 报错
        // System.out.println(testClass4.v3);  // 报错
        // System.out.println(testClass4.v4);  // 报错
        testClass4.c1();
        // testClass4.c2();  // 报错
        // testClass4.c3();  // 报错
        // testClass4.c4();  // 报错
    }
}

TestClass1.java

package access;

// 在同一个包中, 不同的类中测试
public class TestClass1 {
    public int h1 = 100;
    protected int h2 = 200;
    int h3 = 300;
    private int h4 = 400;

    public void q1() {
        System.out.println("TestClass1中 public q1 方法");
    }

    protected void q2() {
        System.out.println("TestClass1中 protected q2 方法");
    }

    void q3() {
        System.out.println("TestClass1中 默认 q3 方法");
    }

    private void q4() {
        System.out.println("TestClass1中 private q4 方法");
    }
}

TestClass2.java

package access;

public class TestClass2 extends TestClass1{
}

TestClass3.java

package access1;

import access.TestClass;

public class TestClass3 extends TestClass {
}

TestClass4.java

package access1;

public class TestClass4 {
    public int v1 = 1000;
    protected int v2 = 2000;
    int v3 = 3000;
    private int v4 = 4000;

    public void c1() {
        System.out.println("TestClass4中 public c1 方法");
    }

    protected void c2() {
        System.out.println("TestClass4中 protected c2 方法");
    }

    void c3() {
        System.out.println("TestClass4中 默认 c3 方法");
    }

    private void c4() {
        System.out.println("TestClass4中 private c4 方法");
    }
}
3、面向对象编程三大特征

封装、继承和多态

3.1、封装 3.1.1、定义

3.1.2、封装的优势

3.1.3、封装的实现步骤

public class Encapsulation {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("张三");
        person.setAge(150);  // 年龄150不在范围内, 用默认值 18
        person.setSalary(1000.98);
        System.out.println(person.info());
    }
}

// 不能随便查看人的年龄, 工资等隐私, 并对设置的年龄进行合理的验证
// 年龄合理就设置, 否则给默认年龄 18, 年龄必须在 1-120, 工资不能直接查看, name 的长度在 2-6 字符之间
class Person {
    public String name;
    private int age;
    private double salary;

    public Person() {

    }

    public Person(String name, int age, double salary) {
        // 我们可以将 set 方法写在构造器中, 这样仍然可以验证
        setName(name);
        setAge(age);
        setSalary(salary);
    }

    //自己写 setXxx 和 getXxx 太慢, 我们使用快捷键
    // 然后根据要求来完善我们的代码
    // 加入对数据的校验, 相当于增加了业务逻辑
    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (name.length() >= 2 && name.length() <= 6) {
            this.name = name;
        } else {
            System.out.println("名字的长度不对, 需要(2-6)个字符, 默认名字");
            this.name = "无名";
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {  // 如果是合理范围
        if (age >= 1 && age <= 120) {
            this.age = age;
        } else {
            System.out.println("你设置年龄不对, 需要在 (1-120), 给默认年龄 18");
            this.age = 18;  // 给一个默认年龄
        }
    }

    public double getSalary() {
        // 可以这里增加对当前对象的权限判断
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    // 写一个方法, 返回属性信息
    public String info() {
        return "信息为 name=" + name + " age=" + age + " 薪水=" + salary;
    }
}
3.1.4、将构造器和 setXxx 结合
public Person(String name, int age, double salary) {
    // 我们可以将 set 方法写在构造器中, 这样仍然可以验证
    setName(name);
    setAge(age);
    setSalary(salary);
}
3.2、继承 3.2.1、定义

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

3.2.2、定义继承的基本语法

3.2.3、代码实现

Extends.java

package com.jm;

public class Extends {
    public static void main(String[] args) {
        Pupil pupil = new Pupil();
        pupil.name = "张三";
        pupil.age = 18;
        pupil.setScore(95);
        pupil.testing();
        pupil.showInfo();
        System.out.println("=====");
        Graduate graduate = new Graduate();
        graduate.name = "李四";
        graduate.age = 20;
        graduate.setScore(100);
        graduate.testing();
        graduate.showInfo();

    }
}

// 父类, 是 Pupil 和 Graduate 的父类
class Student {
    // 共有属性
    public String name;
    public int age;
    private double score;//成绩

    // 共有的方法
    public void setScore(double score) {
        this.score = score;
    }

    public void showInfo() {
        System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
    }
}

Pupil.java

package com.jm;

public class Pupil extends Student {  // 子类Pupil 继承父类Student 
    public void testing() {
        System.out.println("小学生 " + name + " 正在考小学数学..");
    }
}

Graduate.java

package com.jm;

public class Graduate extends Student {  // 子类Graduate 继承父类Student 
    public void testing() {
        System.out.println("大学生 " + name + " 正在考大学数学..");
    }
}
3.2.4、继承给编程带来的便利
  1. 代码的复用性提高了
  2. 代码的扩展性和维护性提高了
3.2.5、继承的细节问题
  1. 子类继承了所有的属性和方法, 非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问, 要通过父类提供公共的方法去访问
  2. 子类必须调用父类的构造器, 完成父类的初始化
  3. 当创建子类对象时, 不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器, 如果父类没有提供无参构造器, 则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作, 否则, 编译不会通过
  4. 如果希望指定去调用父类的某个构造器, 则显式的调用一下:super(参数列表)
  5. super 在使用时, 必须放在构造器第一行(super 只能在构造器中使用)
  6. super() 和 this() 都只能放在构造器第一行, 因此这两个方法不能共存在一个构造器
  7. java 所有类都是 Object 类的子类, Object 是所有类的基类.
  8. 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
  9. 子类最多只能继承一个父类(指直接继承), 即 java 中是单继承机制
  10. 不能滥用继承, 子类和父类之间必须满足 is-a 的逻辑关系

ExtendsDetail.java

package com.jm;

public class ExtendsDetail {
    public static void main(String[] args) {
        System.out.println("===第 1 个对象====");
        Sub sub = new Sub();  // 创建了子类对象 sub
        

        System.out.println("===第 2 个对象====");
        Sub sub2 = new Sub("jack");  // 创建了子类对象 sub2
        


        System.out.println("===第 3 对象====");
        Sub sub3 = new Sub("king", 10);  // 创建了子类对象 sub2
        sub.sayOk();
        
    }
}

Topbase.java

package com.jm;

public class Topbase {
    public Topbase() {
        super();  // Object 的无参构造器
        System.out.println("构造器 Topbase() 被调用...");
    }
}

base.java

package com.jm;

public class base extends Topbase {  //父类
    // 4 个属性
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public base() {
        // 无参构造器
        System.out.println("父类 base()构造器被调用....");
    }

    public base(String name, int age) {  // 有参构造器
        // 默认 super()
        System.out.println("父类 base(String name, int age)构造器被调用....");
    }

    public base(String name) {  // 有参构造器
        System.out.println("父类 base(String name)构造器被调用....");
    }

    //父类提供一个 public 的方法, 返回了 n4
    public int getN4() {
        return n4;
    }

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

    protected void test200() {
        System.out.println("test200");
    }

    void test300() {
        System.out.println("test300");
    }

    private void test400() {
        System.out.println("test400");
    }

    // call
    public void callTest400() {
        test400();
    }
}

Sub.java

package com.jm;

// 输入 ctrl + H 可以看到类的继承关系
public class Sub extends base {  // 子类
    public Sub(String name, int age) {
        // 1. 调用父类的无参构造器, 如下或者什么都不写, 默认就是调用super()
        // super();  // 父类的无参构造器
        // 2. 调用父类的 base(String name) 构造器
        // super("tom");
        // 3. 调用父类的 base(String name, int age) 构造器
        super("king", 20);
        // 细节: super 在使用时, 必须放在构造器第一行
        // 细节: super() 和 this() 都只能放在构造器第一行, 因此这两个方法不能共存在一个构造器
        // this() 不能再使用了
        System.out.println("子类 Sub(String name, int age)构造器被调用....");
    }

    public Sub() {  // 无参构造器
        // super();  // 默认调用父类的无参构造器
        super("smith", 10);
        System.out.println("子类 Sub()构造器被调用....");
    }

    // 当创建子类对象时, 不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器
    public Sub(String name) {
        super("tom", 30);
        // do nothing...
        System.out.println("子类 Sub(String name)构造器被调用....");
    }

    public void sayOk() {
        // 子类方法
        // 非私有的属性和方法可以在子类直接访问
        // 但是私有属性和方法不能在子类直接访问
        System.out.println(n1 + " " + n2 + " " + n3);
        test100();
        test200();
        test300();
        // test400();  错误
        // 要通过父类提供公共的方法去访问
        System.out.println("n4=" + getN4());
        callTest400();
    }
}
3.2.6、继承的本质分析

当子类对象创建好后,建立查找的关系

ExtendsTheory.java

package com.jm;

public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();  // 内存的布局
        // 要按照查找关系来返回信息
        // (1) 首先看子类是否有该属性
        // (2) 如果子类有这个属性, 并且可以访问, 则返回信息
        // (3) 如果子类没有这个属性, 就看父类有没有这个属性(如果父类有该属性, 并且可以访问, 就返回信息..)
        // (4) 如果父类没有就按照(3)的规则, 继续找上级父类, 直到 Object...
        System.out.println(son.name);  // 返回就是大头儿子
        // System.out.println(son.age);  // 报错
        System.out.println(son.getAge());  // 返回的就是 39
        System.out.println(son.hobby);  // 返回的就是旅游
    }
}

class GrandPa {  // 爷类
    String name = "大头爷爷";
    String hobby = "旅游";
}

class Father extends GrandPa {  //父类
    String name = "大头爸爸";
    private int age = 39;

    public int getAge() {
        return age;
    }
}

class Son extends Father {  //子类
    String name = "大头儿子";
}

子类创建的内存布局

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/591298.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号