• 《java练级之路》类和对象,博主熬夜肝六个小时万字博客


    🎇🎇🎇作者:
    @小鱼不会骑车
    🎆🎆🎆专栏:
    《java练级之旅》
    🎓🎓🎓个人简介:
    一名专科大一在读的小比特,努力学习编程是我唯一的出路😎😎😎
    在这里插入图片描述

    🙈🙈🙈作者心里话

    小鱼一直都是秉承着“开开心心看博客,快快乐乐学知识的观点,虽然浏览量好低…”

    前言
    继上次博客,这次讲到的是类和对象的第三部分

    🍃1. 封装

    🍂1.2 封装的概念

    面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说
    就是套壳屏蔽细节。
    生活案例:
    生活中的封装比如ATM收款机,会使用一个机器来保证钱的正常流动,给你一个特定的方法来存钱取钱,不会说让你随意的取钱存钱,在java中,封装也是这个概念,封装就是把过程和数据包裹起来,对数据的访问只能通过已经定义的接口,面向对象计算始于这个基本概念,即现实世界已经被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象
    java中封装的理解:
    我们在程序设计的时候就追求“高内聚、低耦合

    • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
    • 低耦合:仅对外部暴露少量的方法用于使用。

    隐藏对象内部的复杂性、只对外公开简单的接口。便于外界调用从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来,这就是封装的设计思想。

    🍂1.3 访问限定符

    • 在Java中通过权限修饰符关键字private、protected和public实现封装

    java中的四个访问修饰限定符
    在这里插入图片描述
    简单介绍一下这四个修饰限定符,后期会一一用到

    • public:可以理解为一个人的外貌特征,谁都可以看得到
    • default: 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了
    • private:只有自己知道,其他人都不知道

    default权限其实可以理解为默认权限,就是自己这其他三个权限都不设置的情况下,我们的编译器就会默认为default权限,例如

    class Person {
        private String name;//名字
        public int age;//年龄
        int height;//体重,默认为default
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    其中我们的height就是default修饰的权限
    注意:一般情况下成员变量设置为private,成员方法设置为public

    🍂1.4 封装扩展之包

    🍁1.4.1 包的概念

    在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件
    包。有点类似于目录。比如我们为了更好的管理学习到的知识点,我们就可以用一个一个包,一种好的方式就是将相同属性的知识点放在相同文件下,也可以对某个文件夹下的知识点进行更详细的分装。
    在这里插入图片描述

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

    🍁1.4.2 导入包中的类

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

    public class Test1 {
        public static void main(String[] args) {
            java.util.Date date=new java.util.Date();
            //但是大家看上面代码是不是有一些冗余
            System.out.println(date);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    更简便的方法:可以使用 import语句导入包.

    import java.util.Date;//用import导入这个util.Date这个包
    
    public class Test1 {
        public static void main(String[] args) {
          Date date=new Date();
          //上述代码,代码量减少但是作用没变
            System.out.println(date);
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    当然,如果我们需要util包中更多的类,我们就可以用import java.util.*

    import java.util.*;//用import导入这个util.Date这个包中所有的类
    
    public class Test1 {
        public static void main(String[] args) {
          Date date=new Date();
          //上述代码,代码量减少但是作用没变
            System.out.println(date);
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    虽然我们这个是可以导入这个包中的任意类,就是我们用什么,他就默认导入什么类,但是不要和C语言的#include弄混了,C语言在预处理的时候将头文件中所有的代码都添加到了后缀为.i文件中,
    但是java不一样,它并不会直接将那些包中的代码全部引入,只会是选择自己使用到的类进行引入。
    但是需要注意的是java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配
    在这里插入图片描述
    那么就会报错,因为编译器是无法识别我的这个Date是哪个包里的,如果想解决这个问题,我们就只能使用完整的类名,这样就会解决编译器识别不清楚的问题。

    import java.util.*;
    import java.sql.*;
    
    public class Test1 {
        public static void main(String[] args) {
          java.util.Date date=new java.util.Date();
            System.out.println(date);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    总结:

    • 两个及两个以上的类都可以用.*来引入包中的多个类
    • 如果是因为两个包中都有相同的类,那么就需要使用完整的类名来区分

    import 和 C++ 的 #include 差别很大. C++ 必须 #include 来引入其他文件内容, 但是 Java 不需要,import 只是为了写代码的时候更方便.,import 更类似于 C++ 的 namespace 和 using

    🍁1.4.3 自定义包

    基本规则

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

    如何创建一个包
    第一步.

    1. 在 IDEA 中先新建一个包: 右键 src -> 新建 -> 包
      在这里插入图片描述
      第二步
    2. 在弹出的对话框中输入包名, 例如 com.baidu.www
      在这里插入图片描述
      第三步
      3.生成一个java文件
      在这里插入图片描述
      4.此时可以看到我们的磁盘上的目录结构已经被 IDEA 自动创建出来了在这里插入图片描述
      并且我们也会发现Test.java,在文件的最上面出现了一个 package 语句
      在这里插入图片描述

    🍁1.4.4 包的访问权限控制举例

    Computer在我们的com.baidu.www的包里,Person在我们的com.Google.www的包里,两者不在同一个包
    在这里插入图片描述
    Computer类

    package com.baidu.www;
    
    public class Computer {
        private String cpu; // cpu
        String memory; // 内存
        public String screen; //屏幕
        public void  Boot() {
            System.out.println("开机");
        }
    
        public Computer(String cpu, String memory, String screen) {
            this.cpu = cpu;
            this.memory = memory;
            this.screen = screen;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Person类

    package com.Google.www;
    
    import com.baidu.www.Computer;
    
    public class Person {
    
        private String name;//姓名
        private int age;//年龄
        public void sleep() {
            System.out.println(name+"睡觉");
        }
        public void eat () {
            System.out.println(name+"吃饭");
        }
        public static void main(String[] args) {
            Computer computer=new Computer("HW", "i7", "8G");
            System.out.println(computer.cup);
            System.out.println(computer.memory);
            //报错,cpu是私有的是private修饰的,
            //memory是default修饰的,是只能在自己的包中使用的
        }
    }
    // 注意:如果去掉Computer类之前的public修饰符,代码也会编译失败!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    🍁1.4.5 常见的包

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

    🍃2. static

    这部分是本节的重点

    🍂2.1 再谈成员变量

    我们创建一个学生类

    
    public class Student {
        private String name;//姓名
        private int age;//年龄
        private String sex;//性别
        private String classroom;//教室
        public void sleep () {
            System.out.println(name+"上课");
        }
        public void eat () {
            System.out.println(name+"吃饭");
        }
    public void print() {
        System.out.println(name+" "+age+" "+sex+" "+classroom);
    }
        public Student(String name, int age, String sex, String classroom) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.classroom = classroom;
        }
        public static void main(String[] args) {
            Student s1=new Student("小明",18,"男","高三四班");
            Student s3=new Student("小王",17,"男","高三四班");
            Student s2=new Student("小张",19,"女","高三四班");
            s1.print();
            s2.print();
            s3.print();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    大家看,我们的教室是不是都一样,但是每次我们还需要再去填入是哪个教室,是不是很麻烦,并且大家也可以看到我们的变量都是开辟在堆上的
    在这里插入图片描述
    这三个对象里面都有相同的教室,是不是我们可以把这个教室单独拿出来,让这三个类都可以共享到,这个时候就可以使用static这个关键字了

    🍂2.2 static修饰成员变量

    在这里插入图片描述
    被static修饰的成员变量是静态成员变量,不属于某个对象,是所有对象共享的。
    那我们该如何单独访问这个静态成员变量呢?
    试试用对象的引用访问
    在这里插入图片描述
    我们会发现,在之后并没有我们想要的classroom,这是因为我们的classroom是静态成员变量,不会出现在引用中,但是如果强行去调用也是可以的在这里插入图片描述
    更标准一些的写法就是用类名去调用
    在这里插入图片描述
    其实我们的静态成员数据是不占内存的(随类的加载而加载),我们可以不用实例化就去调用

      public static void main(String[] args) {
           // Student s1=new Student("小明",18,"男");
            System.out.println(Student.classroom);
            //没有实例化依然可以调用
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    同时我们还可以发现,我们的静态变量是不会储存在某个具体的对象中的
    在这里插入图片描述

    最后我们就可以总结静态成员变量的特性

    1. 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
    2. 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问
    3. 类变量存储在方法区当中
    4. 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)

    只要被static修饰的变量就不属于对象

    还有一个重要的知识点就是,我们去修改静态成员变量的值,但是每次实例化新对象后,接受的静态成员变量的值也都是被修改过的

    class P{
        public static int a=0;
    
    }
    public class Test2 {
        public static void main(String[] args) {
            P p1=new P();
            P p2=new P();
            P p3=new P();
            p1.a+=5;
            p2.a+=4;
            p3.a+=2;
            p1.a-=8;
            System.out.println(P.a);
        }
        //最后输出3
        所以我们就把这个成员变量的权限设置为private以防被外界篡改信息
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    🍂2.3 static修饰成员方法

    一般类中的数据成员都设置为private,而成员方法设置为public,那设置之后,Student类中classRoom属性如何
    在类外访问呢?

    public class Student {
        private String name;//姓名
        private int age;//年龄
        private String sex;//性别
        private static String classroom="高三四班";//教室
        public void sleep () {
            System.out.println(name+"上课");
        }
        public void eat () {
            System.out.println(name+"吃饭");
        }
    public void print() {
        System.out.println(name+" "+age+" "+sex+" "+classroom);
    }
        public Student(String name, int age, String sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
    }
    class Main {
        public static void main1(String[] args) {
            System.out.println(Student.classroom);
        }
        这里会报错,因为我的classroom的权限仅限于在类里面
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    那我们该如何访问呢?这时候就需要一个一个接口,注意!!!这个接口最好是被static修饰的,下面给大家解释
    在这里插入图片描述
    我们可以通过这个快速创建两个方法,用来修改值和返回值的

    public class Student {
        private String name;//姓名
        private int age;//年龄
        private String sex;//性别
        private static String classroom;//教室
        public static String getClassroom() {
            return classroom;
        }
        public static void setClassroom(String classroom) {
            Student.classroom = classroom;
        }
    }
    class Main {
    
        public static void main(String[] args) {
                Student.setClassroom("高三四班");
            System.out.println(Student.getClassroom());
        }
      //  最后输出高三四班
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    前面讲了,我们的静态变量是不需要实例化对象的,可以直接使用,虽然我们无法直接修改classroom的值,但是我们可以通过输入接口来进行修改,但是大家有没有注意到,我们的这两个接口的方法都是被static修饰的。如果用的是非静态的方法,那我们还要再去实例化一个对象

    public class Student {
        private String name;//姓名
        private int age;//年龄
        private String sex;//性别
     private static String classroom;//教室
    	//没有用static修饰
        public  String getClassroom() {
            return classroom;
        }
    	//没有用static修饰
        public  void setClassroom(String classroom) {
            Student.classroom = classroom;
        }
    }
    class Main {
    
        public static void main(String[] args) {
              Student student=new Student();//需要实例化对象才可以使用
                student.setClassroom("高三四班");
            System.out.println(student.getClassroom());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    那我们可以在静态方法中用静态成员变量,那我们可不可以用非静态成员变量呢?或者非静态的成员方法呢?

    public class Student {
        private String name;//姓名
        private int age;//年龄
        private String sex;//性别
        private static String classroom;//教室
    
        public static String getClassroom() {
            return classroom;
        }
        public static void setClassroom(String classroom) {
            Student.classroom = classroom;
            System.out.println(name);
            System.out.println(age);
        }
    }
    class Main {
    
        public static void main(String[] args) {
            Student.setClassroom("高三四班");
        }
        //报错,无法从静态方法中引用非静态的成员数据
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述
    静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中无法传递this引用。

    因为非静态成员的是属于对象的,我在调用静态方法时没有实例化任何对象,所以如果想访问非静态数据成员那就要实例化这个对象,用这个对象的引用去调用,就像我们的main函数,是静态方法,想在静态方法里面使用非静态的成员数据就需要实例化对象

       public static void main(String[] args) {
            Student.setClassroom("高三四班");
            Student student=new Student();
            //用这个引用去调用这个非静态对象
            //非静态成员变量。刚才已经修改了age权限所以现在可以用
            student.age=10;
            //非静态成员方法
            student.print();
        }
        这样就会避免报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    但是普通成员方法中可以调用静态方法!!!
    总结静态方法

    1. 不属于某个具体的对象,是类方法
    2. 可以通过对象调用,也可以通过类名.静态方法名(…)方式调用,更推荐使用后者
    3. 不能在静态方法中访问任何非静态成员变量

    🍂2.4 static成员变量初始化

    注意:静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性
    静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。
    就地初始化已经讲过了

      private static String classroom="高三四班";//教室
    
    • 1

    那什么是静态代码块初识化呢?

    🍃3.代码块

    🍂3.1 代码块概念以及分类

    使用 {} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:

    • 普通代码块
    • 构造块
    • 静态块
    • 同步代码块(后续讲解多线程部分再谈)

    🍂3.2 普通代码块

    普通代码块:定义在方法中的代码块

    public class Test4 {
        
        public static void main(String[] args) {
            {
                    System.out.println("我是个普通代码块");
            }
             System.out.println("========我是分割符");
        }
    最后输出
    我是个普通代码块
    我是分隔符
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
       public static void main(String[] args) {
            System.out.println("========");
            {
                System.out.println("我是普通代码块");
            }
        }
    最后输出
    我是分隔符
    我是普通代码块
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们就可以发现我们的普通代码块是根据在方法中的顺序,从上往下执行的。当然,如果我们在普通代码块中创建局部变量,那么出了这个代码块,这个局部变量就会销毁
    用法比较少见

    🍂3.3 构造代码块

    依旧是给大家对比一下我的代码块放在不同的位置输出的结果
    在这里插入图片描述
    由此我们可以总结到,我们的实例/构造代码块是在调用构造方法之后优先执行的, 一般就用于初始化实例化成员

    🍂3.4 静态代码块

    一般用于初始化静态成员变量。
    什么是静态代码块呢?就是用static修饰的代码块,我们接下来进行两组对比
    对比一
    静态代码块放在构造方法的前面和后面
    对比二
    静态代码块和实例代码块进行对比,分别按不同的顺序

    🍁3.4.1 对比一

    在这里插入图片描述

    总结: 静态代码块优先于构造方法执行,并且静态代码块根据先后顺序来绝对谁先执行

    🍁3.4.2 对比二

    在这里插入图片描述

    总结: 不论先后顺序,静态代码块一定是在构造方法中第一个执行的,执行完静态代码块再去执行实例代码块,最后执行构造方法。

    🍁3.4.3 注意事项

    • 静态代码块不管生成多少个对象,其只会执行一次
    • 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
    • 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)
    • 实例代码块只有在创建对象时才会执行
  • 相关阅读:
    6-1 列表推导生成随机数矩阵(高教社,《Python编程基础及应用》习题4-10 Python
    【672. 灯泡开关 Ⅱ】
    vue 兄弟组件通信, provide/inject,
    转转集团宣布品牌焕新背后:黄炜继续模仿爱回收,公司多次被处罚
    Python GDAL+numpy遥感图像处理过程中背景像元处理方法
    vue跨域proxy详解(下)
    企业架构LNMP学习笔记58
    基于Spring Boot的网上租贸系统设计与实现(源码+lw+部署文档+讲解等)
    jdbc的API详解
    阿里云CentOS主机开启ipv6
  • 原文地址:https://blog.csdn.net/xiaoyubuhuiqiche/article/details/127813917